<!-- SAGA2 · part 75 -->
s (variation)
      for(var per3=0;per3<4;per3++){ var pdd=(0.8-per3*0.15)*vv[0], pep3=[];
        for(var pea4=-1;pea4<=1;pea4+=0.2){ pep3.push([4.6+Math.cos(pea4)*pdd*0.4, 0.5+Math.sin(pea4)*pdd, 1.2]); }
        pL2(pep3, iG);
      }
      // Nose (variation width)
      var pnw2=vv[2];
      pL2([[0,2,5.2*pnw2],[0,0,6.0*pnw2],[0,-1,6.3*pnw2]], iG);
      // Eyes (variation size)
      var pes2=vv[3];
      for(var per4=0;per4<3;per4++){ var ped2=(1.0-per4*0.2)*pes2, pep4=[];
        for(var pea5=0;pea5<=12;pea5++){ var pa3=(pea5/12)*Math.PI*2;
          pep4.push([-1.9+Math.cos(pa3)*ped2, 2+Math.sin(pa3)*ped2*0.5, 4.9]);
        }
        pL2(pep4, iC);
      }
      pg2.add(makeNumber2(pv2+1, 0, -10, 0));
      pg2.position.set(-90+pv2*20, 14, 60);
      practiceHeads.add(pg2);
    }
    scene.add(practiceHeads);



    // PROFILE LIGHT/SHADOW — from King's reference sketch
    // SHADOW zones: dense hatching
    // Under nose (shadow) — 5 dense lines
    for(var sh1=0;sh1<5;sh1++){ var shy=-1.2-sh1*0.15;
      L([[-0.3,shy,6.4],[0,shy,6.6],[0.3,shy,6.4]], iD);
    }
    // Mouth line (shadow) — 4 dense lines
    for(var sh2=0;sh2<4;sh2++){ var shy2=-2.8-sh2*0.12;
      L([[-0.5,shy2,6.3],[0,shy2,6.5],[0.5,shy2,6.3]], iD);
    }
    // Under lower lip (shadow) — 4 dense lines
    for(var sh3=0;sh3<4;sh3++){ var shy3=-3.6-sh3*0.15;
      L([[-0.4,shy3,6.1],[0,shy3,6.3],[0.4,shy3,6.1]], iD);
    }
    // Under chin (shadow) — 5 dense lines
    for(var sh4=0;sh4<5;sh4++){ var shy4=-4.5-sh4*0.15;
      L([[-0.6,shy4,5.9],[0,shy4,6.1],[0.6,shy4,5.9]], iD);
    }
    // LIGHT zones: sparse (single lines, already have the profile)
    // Nose bridge (light) — keep single
    // Philtrum (light) — single line
    L([[0,-1.5,6.8],[0,-2.0,6.6]], iC); // philtrum (light, sparse)
    // Chin front (light) — single
    L([[0,-4.2,6.3],[0,-4.5,6.2]], iC); // chin (light, sparse)


    // DIRECTIONAL LIGHT — face shading (King's 3-head reference, light from right)
    // LEFT = shadow (dense hatching), RIGHT = light (sparse)
    // Left cheek shadow — 8 dense lines
    for(var dl=0;dl<8;dl++){ var dly=1-dl*0.5;
      L([[-3.5,dly,4.6],[-2.8,dly-0.2,4.9],[-2.0,dly-0.4,5.0]], iD);
    }
    // Left jaw shadow — 6 dense lines
    for(var dj=0;dj<6;dj++){ var djy=-2-dj*0.5;
      L([[-3.2,djy,4.4],[-2.5,djy-0.2,4.7],[-1.8,djy-0.4,4.9]], iD);
    }
    // Left forehead shadow — 5 dense lines
    for(var df=0;df<5;df++){ var dfy=5+df*0.4;
      L([[-3.0,dfy,4.2],[-2.2,dfy,4.5],[-1.5,dfy,4.7]], iD);
    }
    // Right side = light (sparse, just 2 lines each for form)
    L([[3.5,1,4.6],[2.8,0.8,4.9]], iC); // right cheek (light)
    L([[3.2,-2,4.4],[2.5,-2.2,4.7]], iC); // right jaw (light)
    // Nose shadow (casts left, light from right)
    for(var dn=0;dn<4;dn++){ var dny=1-dn*0.4;
      L([[-0.8,dny,5.5],[-0.5,dny,5.8]], iD); // left of nose (shadow)
    }


    // RIBBON helper — flat strip along a path (width in world units)
    function ribbon(pts, width, mat){
      var verts=[], idx=[];
      for(var i=0;i<pts.length;i++){
        var p=pts[i];
        // perpendicular in XY plane (for front-facing ribbons)
        var dir=[0,0,0];
        if(i<pts.length-1){ dir=[pts[i+1][0]-p[0], pts[i+1][1]-p[1], 0]; }
        else { dir=[p[0]-pts[i-1][0], p[1]-pts[i-1][1], 0]; }
        var len=Math.sqrt(dir[0]*dir[0]+dir[1]*dir[1])||1;
        var nx=-dir[1]/len*width/2, ny=dir[0]/len*width/2;
        verts.push(p[0]+nx, p[1]+ny, p[2], p[0]-nx, p[1]-ny, p[2]);
        if(i>0){ var b=i*2; idx.push(b-2,b-1,b, b,b-1,b+1); }
      }
      var g=new THREE.BufferGeometry();
      g.setAttribute('position', new THREE.Float32BufferAttribute(verts,3));
      g.setIndex(idx); g.computeVertexNormals();
      var m=new THREE.Mesh(g, mat);
      // Use basic material (linework style, not shaded)
      return m;
    }
    // Test ribbons on the central profile (nose/lips/chin) — width 0.15
    var ribMat = new THREE.MeshBasicMaterial({color:0x00cccc, transparent:true, opacity:0.55, side:THREE.DoubleSide});
    ig.add(ribbon([[0,7,4.2],[0,5,5.0],[0,3.5,5.8]], 0.08, ribMat)); // forehead
    ig.add(ribbon([[0,3.5,5.8],[0,2,6.3],[0,0.5,6.9]], 0.10, ribMat)); // nose bridge
    ig.add(ribbon([[0,0.5,6.9],[0,-0.8,7.2],[0,-1.5,6.8]], 0.12, ribMat)); // nose tip


    // INTRICATE FACE — King: be intricate where it matters
    // Eyelids (upper and lower, both eyes)
    for(var el=0;el<3;el++){
      L([[-3.0-el*0.2,2.8-el*0.1,4.85],[-1.9,3.0-el*0.1,4.9],[-0.8-el*0.2,2.8-el*0.1,4.85]], iG); // left upper
      L([[-3.0-el*0.2,1.4+el*0.1,4.85],[-1.9,1.2+el*0.1,4.9],[-0.8-el*0.2,1.4+el*0.1,4.85]], iG); // left lower
      L([[0.8+el*0.2,2.75-el*0.1,4.85],[1.9,2.95-el*0.1,4.9],[3.0+el*0.2,2.75-el*0.1,4.85]], iG); // right upper
      L([[0.8+el*0.2,1.35+el*0.1,4.85],[1.9,1.15+el*0.1,4.9],[3.0+el*0.2,1.35+el*0.1,4.85]], iG); // right lower
    }
    // Nose wings (ala) — intricate
    for(var nw=0;nw<4;nw++){
      L([[-1