<!-- SAGA2 · part 51 -->
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.0-nw*0.15,-0.5-nw*0.2,5.9],[-0.7-nw*0.1,-0.8-nw*0.15,6.1]], iG); // left ala
      L([[1.0+nw*0.15,-0.5-nw*0.2,5.9],[0.7+nw*0.1,-0.8-nw*0.15,6.1]], iG); // right ala
    }
    // Lips defined (upper and lower, with cupid's bow)
    L([[-1.2,-2.6,6.0],[-0.4,-2.5,6.2],[0,-2.45,6.25],[0.4,-2.5,6.2],[1.2,-2.6,6.0]], iG); // upper lip
    L([[-1.0,-3.0,5.9],[0,-3.15,6.0],[1.0,-3.0,5.9]], iG); // lower lip
    L([[0,-2.45,6.25],[0,-2.7,6.15]], iC); // philtrum to mouth


    // NOSE FRONT — bridge width, nostrils defined
    for(var nb=0;nb<5;nb++){ var nby=3-nb*0.8;
      L([[-0.4-nb*0.08,nby,5.6+nb*0.15],[0.4+nb*0.08,nby,5.6+nb*0.15]], iG); // bridge width
    }
    // Nostrils — anatomical comma shape (not ovals)
    for(var no=0;no<3;no++){ var ns=1-no*0.25;
      // Left: comma (wide outer, narrow inner)
      L([[-1.1*ns,-1.0,6.0],[-0.85*ns,-1.25,6.05],[-0.6*ns,-1.3,6.05],[-0.45*ns,-1.15,6.0]], iD);
      // Right: mirrored comma
      L([[1.1*ns,-1.0,6.0],[0.85*ns,-1.25,6.05],[0.6*ns,-1.3,6.05],[0.45*ns,-1.15,6.0]], iD);
    }
    // Nose tip — rounded definition
    for(var nt=0;nt<3;nt++){ var nty=-0.6-nt*0.2, ntp=[];
      for(var ntx=-0.5;ntx<=0.5;ntx+=0.1){
        ntp.push([ntx, nty - Math.pow(ntx/0.5,2)*0.25, 6.2-nt*0.05]);
      }
      L(ntp, nt==1?iG:iD);
    }
    // MOUTH — larger, more present
    L([[-1.8,-2.7,5.8],[-0.9,-2.55,6.0],[0,-2.5,6.05],[0.9,-2.55,6.0],[1.8,-2.7,5.8]], iG); // upper lip (wider)
    L([[-1.5,-3.1,5.7],[-0.7,-3.25,5.85],[0,-3.3,5.9],[0.7,-3.25,5.85],[1.5,-3.1,5.7]], iG); // lower lip (fuller)
    L([[-1.8,-2.7,5.8],[1.8,-2.7,5.8]], iD); // mouth line


    // STIPPLING — skin texture (dots where light hits, R5)
    function stipple(cx, cy, cz, r, n, mat){
      for(var sd=0;sd<n;sd++){
        var sa=(sd/n)*Math.PI*2 + 0.3, sr=r*(0.3+0.7*((sd*7)%5)/5);
        var sx=cx+Math.cos(sa)*sr, sy=cy+Math.sin(sa)*sr*0.7;
        // tiny dot as 3-point ribbon
        L([[sx-0.03,sy,cz],[sx,sy+0.03,cz],[sx+0.03,sy,cz]], mat);
      }
    }
    stipple(2.5, 0.5, 5.2, 1.2, 12, iC); // right cheek
    stipple(-2.5, 0.5, 5.2, 1.2, 12, iC); // left cheek
    stipple(0, 4.5, 5.5, 0.8, 8, iC); // forehead
    stipple(0, 1.5, 5.8, 0.5, 6, iC); // nose bridge

    // PHILTRUM — two lines nose to lip
    L([[-0.25,-1.5,6.1],[-0.25,-2.2,6.05]], iD);
    L([[0.25,-1.5,6.1],[0.25,-2.2,6.05]], iD);
    // LIPS — more defined (Cupid's bow, full lower)
    L([[-1.8,-2.7,5.8],[-0.9,-2.6,6.0],[-0.3,-2.45,6.1],[0,-2.5,6.12],[0.3,-2.45,6.1],[0.9,-2.6,6.0],[1.8,-2.7,5.8]], iG);
    // CHIN — mental crease + form
    L([[-0.8,-3.8,5.7],[0,-3.9,5.75],[0.8,-3.8,5.7]], iD); // crease under lip
    L([[-1.2,-4.5,5.5],[-0.5,-4.8,5.6],[0,-4.9,5.65],[0.5,-4.8,5.6],[1.2,-4.5,5.5]], iG); // chin curve
    ig.position.set(0, 14, 120);
    ig.rotation.y = Math.PI; // face toward camera
    for(var wb=0;wb<3;wb++){L([[-3.5,4.5+wb*0.3,4.6],[-1.5,4.3+wb*0.3,4.9],[1.5,4.3+wb*0.3,4.9],[3.5,4.5+wb*0.3,4.6]],iG);}
    window.__builtHead = ig;
  })();

===== FILE: public/saga2/head-youth.js =====
// test
  (function(){
    var ig = new 