Track A: Opus 5.5 alone

agent (cont.)

+0:41
  • Bashsource ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && grep -n -i "brow\|mouth\|role" tools/export_glb.py | head -60; echo ----; grep -n "def \|brow\|mouth" tools/vroid_portrait.py | head -120

    command

    source ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && grep -n -i "brow\|mouth\|role" tools/export_glb.py | head -60; echo ----; grep -n "def \|brow\|mouth" tools/vroid_portrait.py | head -120

    result, 156 lines

    2:browser 3D viewer.
    5:the viewer can toggle and x-ray them. Face, eye, line, brow, mouth and hair keep VRoid's textures
    18:TEXTURED = ("face", "iris", "white", "highlight", "line", "brow", "mouth", "hair")
    19:ROLE_TONE = {"face": "5", "body": "4", "shadow": "3", "hair": "D", "brow": "B", "coat": "M", "cape": "W", "metal": "8",
    22:             "grass": "c", "dirt": "f", "stone": "l", "mouth": "2", "line": "o", "iris": "s", "white": "w",
    26:def group_of(p, role):
    31:    if role in ("face", "body", "shadow", "iris", "white", "highlight", "line", "brow", "mouth"):
    33:    if role == "hair":
    111:    for k, (p, role) in enumerate(zip(portrait.prims, portrait.roles)):
    112:        if role == "skip" or not len(p["tri"]) or (only_world and not p.get("world")):
    120:        mat = dict(name=f"{group_of(p, role)}:{role}", doubleSided=True,
    122:        tone = ROLE_TONE.get(role)
    125:        if role == "face":
    127:        if role in TEXTURED and tex is not None:
    130:            src = portrait._hair_v if role == "hair" and getattr(portrait, "_hair_v", None) is not None \
    133:            mat["pbrMetallicRoughness"]["baseColorTexture"] = dict(index=add_texture((id(src), p["mi"], role), raw))
    134:            if role == "hair":                        # strands are grey in the texture: tint them
    136:            if role in ("hair", "line", "brow", "iris", "highlight"):
    141:        if role in ("metal", "steel", "gold"):
    144:        meshes.append(dict(name=group_of(p, role), primitives=[dict(
    146:        nodes.append(dict(name=f"{group_of(p, role)}/{p['material']}", mesh=len(meshes) - 1,
    147:                          extras=dict(group=group_of(p, role), role=role, world=bool(p.get("world")), material=p["material"])))
    170:# simulated cloth: piece -> (its static trims, hidden while the cloth simulates; the role whose colour
    184:    """Everything the browser's pixel renderer and cloth solver need besides the meshes: palette
    185:    bands per role, the lights, body colliders, cloth grids and the mouth curve (model space,
    191:    roles = {"face": dict(mode="bands", bands=bands(vp.SKIN_BANDS)),
    196:             "line": dict(mode="flat", color=hexp("o")), "brow": dict(mode="flat", color=hexp("A")),
    197:             "mouth": dict(mode="flat", color=hexp("1")), "white": dict(mode="flat", color=hexp("w")),
    201:        roles[r] = dict(mode="bands", bands=bands(tbl), world=r in vp.WORLD_ROLES)
    204:    body = [p for p, r in zip(portrait.prims, portrait.roles) if r == "body"][0]
    227:    if getattr(portrait, "mouth_curve", None) is not None:
    228:        face = [p for p, r in zip(portrait.prims, portrait.roles) if r == "face"]
    232:        _, i = cKDTree(allp).query(portrait.mouth_curve)
    233:        curve = ((portrait.mouth_curve + alln[i] * 0.0015) * FLIP).tolist()
    237:        img = Image.fromarray(np.where(m == 1, 128, 0).astype(np.uint8), "L")     # nose mark only; the mouth is a line
    242:    # painted renderer: a material kind and one base colour per role; the shader builds the ramp
    259:    for role, val in pc.items():                             # extra roles a cast entry names (cloth unless it says)
    260:        if role not in paint and isinstance(val, str) and val.startswith("#"):
    261:            paint[role] = dict(kind="cloth", base=val)
    262:        elif role not in paint and isinstance(val, dict) and "base" in val:
    263:            paint[role] = dict(kind=val.get("kind", "cloth"), base=val["base"])
    264:    for role, g in (pc.get("grain") or {}).items():          # optional per-role brush grain (big flat cloth mottles)
    265:        if role in paint:
    266:            paint[role]["grain"] = g
    267:    return dict(roles=roles, light=vp.LIGHT.tolist(), sun=vp.SUN.tolist(), capsules=caps, cloth=cloth, face_marks=marks,
    269:                mouth_curve=curve, mouth_bone="J_Bip_C_Head", ink=dict(o=hexp("o"), skin=hexp("1"), hair=hexp("A")),
    388:    for k, (p, role) in enumerate(zip(portrait.prims, portrait.roles)):
    389:        if role == "skip" or not len(p["tri"]) or p.get("world") or "J" not in p:
    403:        mat = dict(name=f"{group_of(p, role)}:{role}", doubleSided=True,
    405:        tone = ROLE_TONE.get(role)
    408:            hex_rgb(extra[role]) if isinstance(extra.get(role), str) else [0.8, 0.8, 0.8]
    409:        if role in TEXTURED:
    410:            src = portrait._hair_v if role == "hair" and getattr(portrait, "_hair_v", None) is not None \
    416:                if role == "hair":
    418:                if role in ("hair", "line", "brow", "iris", "highlight"):
    424:        if role in ("metal", "steel", "gold"):
    437:        meshes.append(dict(name=group_of(p, role), primitives=[dict(attributes=attrs,
    440:        gnodes.append(dict(name=f"{group_of(p, role)}/{p['material']}", mesh=len(meshes) - 1, skin=0,
    441:                           extras=dict(group=group_of(p, role), role=role, material=p["material"])))
    ----
    4:palette tones (skin/hair/cloth bands from normals; eyes, brows, lashes from alpha-tested masks)
    39:         ("FaceEyeline", "line"), ("FaceEyelash", "line"), ("FaceMouthLine", "line"), ("FaceBrow", "brow"), ("FaceMouth", "mouth"),
    46:# VRoid face textures share one layout: marks only count inside the nose-and-mouth window
    78:def role_of(material):
    85:def bands(v, table):
    95:def repose(v, prims, ref, target):
    103:    def delta(nm):
    119:def reduce_blocks(char, depth, pid, role, h, w):
    143:def camera_rotation(yaw, pitch):
    152:def smooth(t):
    161:#  3. resting expression: VRoid's own shapes (hooded eyes, stern brows) held at a low weight
    164:               face_len=0.0, jaw=0.0, chin_w=0.0, chin_len=0.0, cheek=0.0, brow_ridge=0.0,
    166:               eye=1.0, eye_tilt=0.0, iris=1.0, mouth=1.0, arm_out=0.0, age_lines=0.0, blush=1.0, curl=0.0,
    170:SCULPT_ROLES = ("face", "body", "mouth", "brow", "line", "white", "iris", "highlight", "hair")
    173:def bone_pose(v, sh, base_pose):
    197:    def own_of(i):
    211:    def as4(r):
    274:def landmarks(prims, roles):
    275:    def verts(*rs):
    285:    mouth = verts("mouth").mean(0)
    286:    band = mid[(mid[:, 1] > mouth[1] + 0.005) & (mid[:, 1] < eyeL[1] - 0.01)]
    291:    def window(pts, cond_y, cond_x=None):
    300:    def edge(y, side, pts=face):
    305:    def front(x, y, pts=skin):
    309:    lm = dict(eyeL=eyeL, eyeR=eyeR, eye_y=eye_y, chin=chin, mouth=mouth, nose=nose, span=span)
    329:def sculpt(prims, roles, lm, sh, sigma=0.022):
    333:    def move(name, d):
    341:        move("ridge" + sd, np.array([0, -0.0015, -0.004]) * sh["brow_ridge"])
    346:    for name in ("crown", "occiput", "forehead", "neck_front", "neck_back", "mouth"):
    363:def face_texture(prims, roles, v):
    373:def strip_blush(prims, roles, v, keep):
    393:def face_normals(prims, roles, lm, amount, hair=0.0, forward=0.0, pull=0.5, neck=None):
    397:    instead of patches that jump as the head turns. The face, its brows, lines and mouth and the skull take it in
    417:        if r in ("face", "brow", "line", "mouth"):
    457:def neck_frame(prims, roles, neck):
    469:def axis_at(A, u, y):
    474:def _shadow_card(name, src, P):
    493:def shadow_cards(prims, roles, lm, amount, neck=None):
    563:def face_lines(prims, roles, v, amount):
    565:    (from the nose's wing round the mouth, under the eyes, crow's feet, a frown between the brows,
    566:    down from the mouth's corners), darker and more of them as `amount` (0..1) rises. Each stroke is
    583:    def verts(*rs):
    586:    mouth = verts("mouth")
    591:    mo = lm["mouth"]
    592:    mhw = 0.55 * np.ptp(mouth[:, 0])                             # half the mouth's width (the inner mouth spans it)
    594:    def eye_box(c):
    600:    def drop(x, y):
    605:    def to_uv(P):
    617:    def curve(ctrl, n=24):
    640:        # from the nose's wing round the mouth
    651:        # down from the mouth's corner
    655:    # a frown between the brows
    695:def reshape(prims, roles, lm, sh):
    696:    """Face length, sculpting, eye size/tilt and mouth width (skeleton and expression are applied
    713:        if sh["mouth"] != 1.0 and r == "mouth":
    714:            P[:, 0] = lm["mouth"][0] + (P[:, 0] - lm["mouth"][0]) * sh["mouth"]
    731:    def __init__(self, path, morphs=None, pose=BUST_POSE, shape=None, hair_from=None, costume=None,
    732:                 mouth="curve", world=None, ref_pose=BUST_POSE, hair_trim=None):
    733:        """mouth: how the closed mouth is drawn. 'texture' = VRoid's painted lip line, thickened;
    734:        'texture+lip' = that plus a lower-lip shade; 'drawn' = an FE8-style mouth between the
    735:        projected mouth corners; 'none' = geometry only (the line disappears when closed)."""
    736:        self.mouth = mouth
    825:            if self.roles[k] in ("line", "brow", "iris", "highlight", "white", "hair", "mouth"):
    837:        self.mouth_pts = None
    838:        self.mouth_curve = None
    852:            # 2 = mouth (dark line), 1 = nose mark (one tone softer)
    854:            if self.mouth_pts is None and raw.any():
    867:                        self.mouth_pts = pts
    877:                    self.mouth_curve = np.array(curve) if len(curve) >= 4 else None
    879:    def frame(self, view="bust", pitch=None, w=None, h=None):
    883:    def _frame(self, view, pitch, w, h):
    900:    def render(self, yaw=35, pitch=None, view="bust", smooth=None, w=None, h=None):
    908:        def projector(Rm):
    909:            def project(P):
    922:               if k in self.tex and self.roles[k] in ("line", "brow", "iris", "highlight", "white", "hair", "mouth")}
    963:                if mark is not None and self.mouth in ("texture", "texture+lip", "curve", "curve+lip"):
    970:                    if self.mouth == "texture+lip":
    974:                    if self.mouth in ("texture", "texture+lip"):
    993:            elif r == "brow":
    995:            elif r == "mouth":
    1026:        if self.mouth == "drawn" and self.mouth_pts and all(q is not None for q in self.mouth_pts):
    1027:            pts = project(np.array(self.mouth_pts)) / [SS, SS, 1]
    1028:            draw_mouth(ink, rol, pts)
    1029:        if self.mouth in ("curve", "curve+lip") and self.mouth_curve is not None:
    1030:            draw_curve_mouth(ink, rol, dep, project(self.mouth_curve) / [SS, SS, 1], lip=self.mouth == "curve+lip")
    1033:    def ink(self, c, dep, prim, rol):
    1043:            def nb(a, fill):
    1077:def uv_to_3d(prims, uv):
    1104:def draw_mouth(c, rol, pts):
    1105:    """FE8-style closed mouth: a dark line between the corners with lighter ends, and a lower-lip
    1123:def draw_curve_mouth(c, rol, dep, pts, lip=False, keep=(0.12, 0.88), dark=(0.28, 0.72)):
    1124:    """Closed mouth as a 1-px line along the projected lip curve: dark in the middle, one tone
    1148:def smooth_view(portrait, yaw=35, pitch=None, palette=None, view="bust", w=None, h=None):
    1154:            "line": hexrgb("o"), "brow": hexrgb("B"), "mouth": hexrgb("2"), "white": hexrgb("w"),
    1163:def image(char, scale=1, bg=None, palette=None):
    1177:def main():
  • Bashsource ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && grep -n "mouth_curve\|face_marks\|mouthCurve\|curve" review/vroid-02/index.html | head -30; sed -n 780,900p review/vroid-02/index.html

    command

    source ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && grep -n "mouth_curve\|face_marks\|mouthCurve\|curve" review/vroid-02/index.html | head -30; sed -n 780,900p review/vroid-02/index.html

    result, 122 lines

    389:  // the surface curves (normal change per metre on screen), and broad plates get a soft tone that
            const k = idx(i, j), r = this.r0[k] + this.push[k], h0 = this.h0[k], tt = this.t0[k];
            // keep the rest length of this segment: what the push adds outward comes off the drop
            const L = Math.hypot(this.r0[k] - this.r0[k - 1], h0 - this.h0[k - 1], tt - this.t0[k - 1]);
            const dr = r - pr, dtan = tt - pt, dh = -Math.sqrt(Math.max(L * L - dr * dr - dtan * dtan, 1e-6));
            const h = ph + (j === 1 ? Math.min(dh, h0) : dh);
            const q = W[i].clone().addScaledVector(d, r).addScaledVector(t, tt); q.y += h;
            X[3 * k] = q.x; X[3 * k + 1] = q.y; X[3 * k + 2] = q.z;
            pr = r; ph = h; pt = tt;
          }
        }
        this.prev.set(X);
      }
      reset() { this.push.fill(0); this.pose(0, true); }
      step(dt) { this.pose(dt, false); }
    }
    
    // ---- materials per mesh ----------------------------------------------------------------------------------------------
    const KEY = new THREE.Vector3(-0.45, 0.55, 0.70).normalize();
    // stage grades: ambient multiply, key colour, back rim (characters and stage share them)
    const GRADE = { battle: { ambient: [0.84, 0.87, 0.98], key: [1.05, 1.0, 0.92], rim: [0.38, 0.34, 0.26] },
                    bust: { ambient: [0.90, 0.90, 0.98], key: [1.03, 1.0, 0.96], rim: [0.24, 0.24, 0.34] } };
    const KIND = { cloth: 0, skin: 1, hair: 2, steel: 3, gold: 4, leather: 5, world: 6 };
    function paintMaterial(V, role, map, index, infoRole = role, decal = false) {
      const Rl = V.roles[role] || { mode: "flat", color: "#ff00ff" }, P = (V.paint || {})[role];
      const u = { uKind: { value: 9 }, uBase: { value: new THREE.Color(0.8, 0.8, 0.8) }, uKey: { value: KEY.clone() },
        uMap: { value: map || white }, uAlpha: { value: 0 }, uPass: { value: 0 },
        uInfo: { value: new THREE.Vector4(roleId(infoRole) / 255, (index % 256) / 255, Math.floor(index / 256) / 255, 1) },
        uEye: { value: V.roles.iris.colors.map(hex) }, uFlat: { value: new THREE.Color() }, uSkinRef: { value: new THREE.Vector3(0.965, 0.878, 0.80) },
        uGold: { value: hex((V.paint && V.paint.gold && V.paint.gold.base) || "#b08b3f") },
        uAmbient: { value: new THREE.Vector3(1, 1, 1) }, uKeyCol: { value: new THREE.Vector3(1, 1, 1) }, uRimCol: { value: new THREE.Vector3() },
        uGrain: { value: 0.05 }, uFaceTex: { value: 0 }, uDecal: { value: decal ? 1 : 0 }, uBand: { value: null },
        uSkinTone: { value: new THREE.Vector3(1, 1, 1) }, uShadeOnly: { value: 0 },
        uSkinRamp: { value: 0 }, uSkinL: { value: new THREE.Color() }, uSkinS: { value: new THREE.Color() }, uSkinC: { value: new THREE.Color() },
        tCastInfo: { value: null }, tCastDepth: { value: null }, uCastRes: { value: new THREE.Vector2(1, 1) }, uCastOn: { value: 0 },
        uCastNear: { value: 0.1 }, uCastFar: { value: 40 }, uCastPpm: { value: 1 },
        uMotif: { value: hex((V.paint && V.paint.motif && V.paint.motif.base) || "#3a44a0") } };
      if (P) { u.uKind.value = KIND[P.kind] ?? 0; if (P.base) u.uBase.value = hex(P.base); if (P.grain != null) u.uGrain.value = P.grain; }
      else if (Rl.bands) { u.uKind.value = Rl.world ? 6 : 0; u.uBase.value = hex(Rl.bands[Math.min(1, Rl.bands.length - 1)][1]); }
      if (P && P.kind === "world") { u.uKey.value = new THREE.Vector3(...V.sun); u.uGrain.value = 0.12; }
      if (P && P.shade) u.uShadeOnly.value = 1;         // shadow cards: skin, always in its shade tone
      if (P && P.kind === "skin" && P.ramp) {           // a designed ramp: lit, shade, deep shade
        u.uSkinRamp.value = 1; u.uSkinL.value = hex(P.ramp[0]); u.uSkinS.value = hex(P.ramp[1]); u.uSkinC.value = hex(P.ramp[2]);
      }
      if (P && P.kind === "skin" && P.base) {           // skin tone: the base colour against the default light skin
        const c = hex(P.base); u.uSkinTone.value.set(c.r / 0.973, c.g / 0.882, c.b / 0.835);
      }
      if (role === "face" && map) u.uFaceTex.value = 1;
      if (role === "hair" && map) u.uAlpha.value = 1;
      if (role === "iris") { u.uKind.value = 7; u.uAlpha.value = 1; }
      else if (role === "white" || role === "highlight") { u.uKind.value = map ? 8 : 9; if (map) u.uAlpha.value = 1; u.uFlat.value = hex(Rl.color || "#ffffff"); }
      else if (!P && Rl.mode === "flat") { u.uKind.value = 9; u.uFlat.value = hex(Rl.color); if (map) u.uAlpha.value = role === "line" ? 2 : 1; }
      u.uBand.value = u.uGold.value.clone();
      const m = new THREE.ShaderMaterial({ uniforms: u, vertexShader: PAINT_VS, fragmentShader: PAINT_FS, side: THREE.DoubleSide,
                                           extensions: { derivatives: true } });
      // meshes without plate data or a cloth edge read zeros, not whatever another program left in that slot
      m.defaultAttributeValues = { ...m.defaultAttributeValues, _plate: [0, 0, 0, 0], edge: [0] };
      return m;
    }
    
    // ---- models ------------------------------------------------------------------------------------------------------
    const loader = new GLTFLoader();
    const chars = new Map();          // name -> loaded character
    let ground = null;
    const stage = new THREE.Group();  // the duel: both fighters stand on it; the turn slider rotates it
    scene.add(stage);
    // the lineup: every enemy model standing in a row (camera.json's lineup), each turning in place
    const LINEUP = CAM.lineup || { order: [], spacing: 0.9 };
    const ROW_VIEW = () => state.view === "lineup" || state.view === "compare";     // several models in a row, each turning in place
    const CAM_VIEW = () => state.view === "duel" || ROW_VIEW() ? CAM.duel.cam : charDef(state.who).cams[state.view];
    const activeNames = () => state.view === "duel" ? [CAM.duel.order.player, CAM.duel.order.opponent]
                            : state.view === "lineup" ? LINEUP.order : state.view === "compare" ? state.compare : [state.who];
    const active = () => activeNames().map(n => chars.get(n)).filter(Boolean);
    
    async function parseGlb(file) {
      const j = await (await fetch(file)).json();
      const bin = Uint8Array.from(atob(j.glb), c => c.charCodeAt(0));
      return await new Promise((ok, bad) => loader.parse(bin.buffer, "", ok, bad));
    }
    let meshIndex = 1;
    function prepMesh(o, V, opts = {}) {
      const m0 = o.material, role = o.userData.role || "body", raw = rawTex(m0.map);
      const infoRole = role === "hair" && opts.hairB ? "hair_b" : role === "shadow" ? "body" : role;
      const decal = !!(m0.userData && m0.userData.decal);              // the map is a design mask, not a colour
      const base = { map: decal ? null : (m0.map || null), color: m0.color.clone(), side: THREE.DoubleSide, alphaTest: m0.alphaTest || 0 };
      const clay = new THREE.MeshStandardMaterial({ ...base, roughness: 0.85, metalness: m0.metalness || 0 });
      const toon = new THREE.MeshToonMaterial({ ...base, gradientMap: gradient });
      if (role === "hair" && m0.map && V.paint && V.paint.hair) {
        // the VRoid sample's hair texture carries its own colour (dark on some samples): in 3D use the
        // character's hair colour, with the texture's light and dark only for strand detail
        for (const m of [clay, toon]) {
          m.color = hex(V.paint.hair.base);
          m.onBeforeCompile = sh => { sh.fragmentShader = sh.fragmentShader.replace("#include <map_fragment>",
            `#ifdef USE_MAP
              vec4 texel_ = texture2D(map, vMapUv);
              diffuseColor.rgb *= mix(1.0, clamp(dot(texel_.rgb, vec3(0.3333)) / 0.5, 0.45, 1.35), 0.6);
              diffuseColor.a *= texel_.a;
            #endif`); };
          m.customProgramCacheKey = () => "hairlum";
        }
      }
      o.userData.mats = { clay, toon, painted: paintMaterial(V, role, raw, meshIndex, infoRole, decal) };
      meshIndex++;
      o.userData.group = o.userData.group || "body";
      o.userData.role = role;
      o.frustumCulled = false;
    }
    
    async function loadCharacter(name) {
      if (chars.has(name)) return chars.get(name);
      const def = charDef(name), V = def.info, ci = CAM.characters.indexOf(def);
      const gltf = await parseGlb(`${name}.glb.json`);
      const turn = new THREE.Group(), holder = new THREE.Group();
      turn.add(holder); holder.add(gltf.scene);
      const meshes = [];
      gltf.scene.traverse(o => { if (o.isMesh) { prepMesh(o, V, { hairB: ci > 0 }); meshes.push(o); } });
      gltf.scene.updateMatrixWorld(true);
      const bone = n => gltf.scene.getObjectByName(n);
      const cloths = [], world = new THREE.Group();
      for (const [cname, info] of Object.entries(V.cloth || {})) {
        const skinned = meshes.find(m => m.userData.material === cname);
        if (!skinned) continue;
  • Bashsource ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && sed -n 180,245p tools/export_glb.py; grep -n "def hexp\|PALETTE\s*=\|^ \"[0-9A-Za-z]\":" tools/*.py | head -20; cat $KIT/variant_build.py | head -80

    command

    source ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && sed -n 180,245p tools/export_glb.py; grep -n "def hexp\|PALETTE\s*=\|^    \"[0-9A-Za-z]\":" tools/*.py | head -20; cat $KIT/variant_build.py | head -80

    result, 121 lines

    CLOTH_HEM_ONLY = {"OUTFIT_skirt"}            # border band on the hem row only (its waist has a gold trim)
    
    
    def scene_info(portrait, palette):
        """Everything the browser's pixel renderer and cloth solver need besides the meshes: palette
        bands per role, the lights, body colliders, cloth grids and the mouth curve (model space,
        turned to face +z like the GLB)."""
        import vroid_portrait as vp
        from vrm import bone_weight
        hexp = lambda c: palette[c]
        bands = lambda tbl: [[thr if thr > -5 else -9, hexp(c)] for thr, c in tbl]
        roles = {"face": dict(mode="bands", bands=bands(vp.SKIN_BANDS)),
                 "body": dict(mode="bands", bands=bands(vp.SKIN_BANDS), cap=hexp("4")),
                 "shadow": dict(mode="flat", color=hexp("3")),
                 "hair": dict(mode="bands", bands=bands(vp.HAIR_BANDS)),
                 "cloth": dict(mode="bands", bands=bands(vp.CLOTH_BANDS)),
                 "line": dict(mode="flat", color=hexp("o")), "brow": dict(mode="flat", color=hexp("A")),
                 "mouth": dict(mode="flat", color=hexp("1")), "white": dict(mode="flat", color=hexp("w")),
                 "highlight": dict(mode="flat", color=hexp("w")),
                 "iris": dict(mode="iris", colors=[hexp("r"), hexp("s"), hexp("t")], cuts=[0.25, 0.5])}
        for r, tbl in vp.MATERIALS.items():
            roles[r] = dict(mode="bands", bands=bands(tbl), world=r in vp.WORLD_ROLES)
        names = portrait.v.nodes_by_name()
        W = portrait.v.node_world(portrait.pose_now)
        body = [p for p, r in zip(portrait.prims, portrait.roles) if r == "body"][0]
        caps = []
        for a, b in CAPSULES:
            if a not in names or b not in names:
                continue
            A, B = W[names[a]][:3, 3], W[names[b]][:3, 3]
            wv = bone_weight(body, (a,))
            pts = body["pos"][wv > 0.5]
            if len(pts) < 8:
                continue
            ab = B - A
            t = np.clip(((pts - A) @ ab) / (ab @ ab), 0, 1)
            d = np.linalg.norm(pts - (A + t[:, None] * ab), axis=1)
            caps.append(dict(a=(A * FLIP).tolist(), b=(B * FLIP).tolist(), r=float(np.percentile(d, 70) + 0.012),
                             bones=[a, b]))
        cloth = {}
        for p in portrait.prims:
            if p["material"] in CLOTH and "grid" in p:
                trims, band, collide = CLOTH[p["material"]]
                cloth[p["material"]] = dict(u=int(p["grid"][0]), v=int(p["grid"][1]), trims=list(trims), band=band,
                                            collide=list(collide) if collide else None, closed=bool(p.get("closed")),
                                            edges="hem" if p["material"] in CLOTH_HEM_ONLY else "all")
        curve = None
        if getattr(portrait, "mouth_curve", None) is not None:
            face = [p for p, r in zip(portrait.prims, portrait.roles) if r == "face"]
            allp = np.concatenate([p["pos"] for p in face])
            alln = np.concatenate([p["nrm"] for p in face])
            from scipy.spatial import cKDTree
            _, i = cKDTree(allp).query(portrait.mouth_curve)
            curve = ((portrait.mouth_curve + alln[i] * 0.0015) * FLIP).tolist()
        marks = None
        if getattr(portrait, "marks", None):
            m = next(iter(portrait.marks.values()))
            img = Image.fromarray(np.where(m == 1, 128, 0).astype(np.uint8), "L")     # nose mark only; the mouth is a line
            b = io.BytesIO()
            img.save(b, "PNG", optimize=True)
            import base64
            marks = base64.b64encode(b.getvalue()).decode()
        # painted renderer: a material kind and one base colour per role; the shader builds the ramp
        pc = dict(signature="#7d1e2c", doublet="#2a2d3d", heraldry="#dfe2e8", leather="#5f3e2b", boot="#4a3326", glove="#5f3e2b",
                  steel="#a6adbb", gold="#b08b3f", hair=hexp("C"), trim="#b08b3f")
        pc.update(getattr(portrait, "paint", None) or {})
    tools/proportions.py:61:    "H": "height, crown to sole (metres)",
    tools/vroid_portrait.py:34:PALETTE = {**SKIN, **HAIR_TONES, **COAT, **EYES, **CAPE, **METAL, **GOLD, **LEATHER, **DOUBLET, **HERALDRY, **GRASS,
    """Build armory characters from the worktree in $LOWMARCH_REPO into a site dir, with an expression baked in.
    
      python3 variant_build.py SITE_COPY forward=0.13 pull=0.5 hair=0.0 NAME [NAME...]
    
    SITE_COPY is a copy of the built armory site (with the patched sheet rows); each NAME's .glb.json is replaced.
    """
    import functools
    import os
    import sys
    
    os.environ["LOWMARCH_SITE"] = "armory"
    REPO = os.environ["LOWMARCH_REPO"]          # the track's worktree
    sys.path[:0] = [os.path.join(REPO, "review", "vroid-02"), os.path.join(REPO, "tools"), os.path.join(REPO, "art", "cast")]
    import build  # noqa: E402
    import vroid_portrait as vp  # noqa: E402
    
    site = sys.argv[1]
    kw = dict(a.split("=") for a in sys.argv[2:] if "=" in a)
    names = [a for a in sys.argv[2:] if "=" not in a]
    hair = float(kw.pop("hair", 0.0))
    rest = kw.pop("rest", None)                           # rest=Fcl_ALL_Joy:1,Fcl_MTH_A:0.5 (VRoid expression shapes)
    if rest is not None:
        for n in names:
            build.CAST[n]["shape"] = dict(build.CAST[n]["shape"], rest={} if rest == "none" else
                                          {k: float(v) for k, v in (kv.split(":") for kv in rest.split(";"))})
    skin = kw.pop("skin", None)                           # skin=<tone in cast.SKINS>
    if skin is not None:
        import cast
        for n in names:
            build.CAST[n]["paint"] = dict(build.CAST[n].get("paint") or {})
            if cast.SKINS[skin]:
                build.CAST[n]["paint"]["skin"] = cast.SKINS[skin]
            else:
                build.CAST[n]["paint"].pop("skin", None)
    if "marks" in kw:                                     # marks=nose_dy,ry,rx/lip_dy,ry,rx/neck
        nose, lip, neck = kw.pop("marks").split("/")
        vp.SHADE_MARKS = dict(nose=tuple(map(float, nose.split(","))), lip=tuple(map(float, lip.split(","))),
                              neck=float(neck))
    vp.face_normals = functools.partial(vp.face_normals, **{k: float(v) for k, v in kw.items()})
    vp.NEUTRAL["hair_normals"] = hair
    build.OUT = site
    build.GEOM = os.path.join(site, "_geom")
    os.makedirs(build.GEOM, exist_ok=True)
    import json
    cam_path = os.path.join(site, "camera.json")
    cam = json.load(open(cam_path))
    for n in names:
        res = build.character((n, None))
        for c in cam["characters"]:                       # the page reads paint, roles and cameras from camera.json
            if c["name"] == n:
                c.update(info=res["info"], cams=res["cams"])
        print(n, res["size"])
    json.dump(cam, open(cam_path, "w"))
  • Bashsource ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && ls review/vroid-02 art/cast; grep -n "rest" review/vroid-02/build.py art/cast/*.py | head -30; grep -n "arm_f_slender\|arm_m_youth" -A12 art/cast/*.py | grep -i "rest\|shape\|name" | head

    command

    source ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && ls review/vroid-02 art/cast; grep -n "rest" review/vroid-02/build.py art/cast/*.py | head -30; grep -n "arm_f_slender\|arm_m_youth" -A12 art/cast/*.py | grep -i "rest\|shape\|name" | head

    result, 46 lines

    art/cast:
    cast.py
    __pycache__
    
    review/vroid-02:
    armory_notes.html
    base_spike_notes.html
    battle_test.py
    build.py
    closeup_test.py
    costume_test.py
    duel_check.py
    fit_test.py
    index.html
    mh_workshop_notes.html
    mouths.py
    pose_test.py
    __pycache__
    sheets.py
    snapshot.py
    art/cast/cast.py:232:# archetype. What a face does at rest (a frown, half-closed eyes) and age lines are drawn when the figure is built
    art/cast/cast.py:273:PORTRAIT = {    # at rest and age lines: name -> shape extras (tools/vroid_portrait.py)
    art/cast/cast.py:274:    "arm_m_strong": dict(rest={"Fcl_BRW_Angry": 0.4}),
    art/cast/cast.py:275:    "arm_m_heroic": dict(rest={"Fcl_BRW_Angry": 0.25}),
    art/cast/cast.py:276:    "arm_m_brute": dict(rest={"Fcl_EYE_Close": 0.28, "Fcl_BRW_Angry": 0.75}),
    art/cast/cast.py:277:    "arm_m_old": dict(age_lines=0.8, blush=0.0, rest={"Fcl_EYE_Angry": 0.4, "Fcl_EYE_Close": 0.25, "Fcl_BRW_Angry": 0.5,
    art/cast/cast.py:279:    "arm_f_old": dict(age_lines=0.6, blush=0.3, rest={"Fcl_EYE_Close": 0.22, "Fcl_MTH_Down": 0.2}),
    art/cast/cast.py:280:    "arm_f_strong": dict(rest={"Fcl_BRW_Angry": 0.2}),
    art/cast/cast.py:321:        shape=dict(head=0.95, leg_len=1.04, shoulder_w=0.008, rest={"Fcl_BRW_Angry": 0.35}),
    art/cast/cast.py:332:        shape=dict(head=0.95, leg_len=1.04, shoulder_w=0.008, rest={"Fcl_BRW_Angry": 0.35}),
    art/cast/cast.py:348:                        rest={"Fcl_EYE_Angry": 0.35}),
    art/cast/cast.py:353:                            rest={"Fcl_EYE_Angry": 0.45, "Fcl_EYE_Close": 0.1, "Fcl_EYE_Joy": 0.18, "Fcl_BRW_Angry": 0.45,
    art/cast/cast.py:386:                        rest={"Fcl_EYE_Angry": 0.35}, group="Round 2 · VRoid"),
    art/cast/cast.py:417:                   eye=0.92, neck=1.2, chest=1.06, rest={"Fcl_EYE_Close": 0.2, "Fcl_BRW_Angry": 0.35}),
    art/cast/cast.py:424:                   rest={"Fcl_EYE_Close": 0.18, "Fcl_BRW_Angry": 0.6}),
    art/cast/cast.py:440:                   rest={"Fcl_EYE_Close": 0.15}),
    273-PORTRAIT = {    # at rest and age lines: name -> shape extras (tools/vroid_portrait.py)
    274-    "arm_m_strong": dict(rest={"Fcl_BRW_Angry": 0.4}),
    275-    "arm_m_heroic": dict(rest={"Fcl_BRW_Angry": 0.25}),
    276-    "arm_m_brute": dict(rest={"Fcl_EYE_Close": 0.28, "Fcl_BRW_Angry": 0.75}),
    277-    "arm_m_old": dict(age_lines=0.8, blush=0.0, rest={"Fcl_EYE_Angry": 0.4, "Fcl_EYE_Close": 0.25, "Fcl_BRW_Angry": 0.5,
    279-    "arm_f_old": dict(age_lines=0.6, blush=0.3, rest={"Fcl_EYE_Close": 0.22, "Fcl_MTH_Down": 0.2}),
    280-    "arm_f_strong": dict(rest={"Fcl_BRW_Angry": 0.2}),
    282-ARMORY = {      # name: (label, sex, its reference, cage spec beyond base and ref)
    291:    "arm_f_slender": ("Woman, slender", "f", "ref_f_slender", dict(relax=4, bust_shape=dict(spread=0.008, drop=0.005, flat=0.25))),
    292-    "arm_f_average": ("Woman, average", "f", "ref_f_average", dict(relax=4, bust_shape=dict(spread=0.005, drop=0.008, flat=0.3))),
  • Bashsource ~/Projects/lowmarch-bench/kit/env-a.sh && mkdir -p $WORK/tex && cat > $WORK/tex/x.py <<'EOF'

    command

    source ~/Projects/lowmarch-bench/kit/env-a.sh && mkdir -p $WORK/tex && cat > $WORK/tex/x.py <<'EOF'
    import json,base64,struct,sys,io
    from PIL import Image
    j=json.load(open(sys.argv[1])); b=base64.b64decode(j["glb"])
    L=struct.unpack("<I",b[12:16])[0]; g=json.loads(b[20:20+L]); bin_=b[20+L+8:]
    for m in g["materials"]:
        print(m["name"], m.get("pbrMetallicRoughness",{}).get("baseColorTexture"), m.get("pbrMetallicRoughness",{}).get("baseColorFactor"))
    for i,t in enumerate(g["textures"]):
        im=g["images"][t["source"]]; bv=g["bufferViews"][im["bufferView"]]
        data=bin_[bv.get("byteOffset",0):bv.get("byteOffset",0)+bv["byteLength"]]
        Image.open(io.BytesIO(data)).save(f"{sys.argv[2]}/t{i}.png")
    EOF
    python3 -I $WORK/tex/x.py $WORK/site/arm_f_slender.glb.json $WORK/tex 2>&1 | grep -i "face\|mouth\|brow\|line" ; ls $WORK/tex

    result, 16 lines

    body:mouth {'index': 0} None
    body:face {'index': 3} None
    body:brow {'index': 5} None
    body:line {'index': 6} None
    body:line {'index': 7} None
    t0.png
    t1.png
    t2.png
    t3.png
    t4.png
    t5.png
    t6.png
    t7.png
    t8.png
    t9.png
    x.py
  • Read~/Projects/lowmarch-bench/work/a/tex/t0.png

    input

    {
      "file_path": "~/Projects/lowmarch-bench/work/a/tex/t0.png"
    }

    result

    no output

    tex_t0.png
    tex_t0.png
  • Read~/Projects/lowmarch-bench/work/a/tex/t5.png

    input

    {
      "file_path": "~/Projects/lowmarch-bench/work/a/tex/t5.png"
    }

    result

    no output

    tex_t5.png
    tex_t5.png
  • Bashsource ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && sed -n 1310,1372p review/vroid-02/index.html; grep -n "uCastOn\|tCastInfo.value\|renderOrder" review/vroid-02/index.html

    command

    source ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && sed -n 1310,1372p review/vroid-02/index.html; grep -n "uCastOn\|tCastInfo.value\|renderOrder" review/vroid-02/index.html

    result, 68 lines

        if (view === "duel") setClip("clash", SHEET ? null : "idle"); else if (view === "battle") setClip(want);
        else if (view === "lineup") setClip(clip && CLIP_VIEW[clip] === "battle" ? clip : "idle"); else setClip("idle");
        animate(0);
        scene.updateMatrixWorld(true); cs.forEach(c => c.cloths.forEach(cl => { cl.reset(false); cl.write(); }));
      } catch (e) { console.error(e); statusEl.textContent = "The model didn't load."; }
    }
    
    // ---- rendering -------------------------------------------------------------------------------------------------------
    function applySkin(meshes) {
      // the picked tone on every skin material (face, body, shadow cards); the built tone is kept to go back to
      const tone = state.skin && PAGE && PAGE.skins ? PAGE.skins.find(s => s.name === state.skin) : null;
      for (const o of meshes) {
        const m = o.userData.mats && o.userData.mats.painted, u = m && m.uniforms;
        if (!u || !u.uSkinRamp || u.uKind.value !== 1) continue;
        if (!o.userData.builtSkin) o.userData.builtSkin = [u.uSkinRamp.value, u.uSkinL.value.clone(), u.uSkinS.value.clone(), u.uSkinC.value.clone()];
        if (tone) { u.uSkinRamp.value = 1; u.uSkinL.value.copy(hex(tone.ramp[0])); u.uSkinS.value.copy(hex(tone.ramp[1])); u.uSkinC.value.copy(hex(tone.ramp[2])); }
        else { const b = o.userData.builtSkin; u.uSkinRamp.value = b[0]; u.uSkinL.value.copy(b[1]); u.uSkinS.value.copy(b[2]); u.uSkinC.value.copy(b[3]); }
      }
    }
    function render() {
      const meshes = allMeshes(), cs = active();
      applySkin(meshes);
      const cloths = cs.flatMap(c => c.cloths);
      if (state.mode === "3d") {
        meshes.forEach(o => o.material = o.userData.mat3d);
        cloths.forEach(c => c.lines3d.visible = trimsShown(c));
        sun.position.copy(camera.position).add(new THREE.Vector3(-3, 4, 0)); sun.target.position.copy(ctl.target); sun.target.updateMatrixWorld();
        R.setRenderTarget(null); R.setClearColor(0x191626, 1); R.clear(); R.render(scene, camera); R.setClearColor(0x000000, 0);
        return;
      }
      const buf = R.getDrawingBufferSize(new THREE.Vector2());
      targetsFor(buf.x, buf.y);
      cloths.forEach(c => c.lines3d.visible = false);
      meshes.forEach(o => { o.material = o.userData.mats.painted; o.material.uniforms.uPass.value = 0; });
      const G = GRADE[state.view === "bust" ? "bust" : "battle"];      // stage grade, shared by the characters and the stage
      for (const o of meshes) { const mu = o.material.uniforms; mu.uAmbient.value.set(...G.ambient); mu.uKeyCol.value.set(...G.key); mu.uRimCol.value.set(...G.rim); }
      // the info pass (roles, ids, depth) first: the colour pass reads it for cast shadows
      meshes.forEach(o => {                              // unbound while it is drawn: reading it now would be a feedback loop
        const mu = o.material.uniforms; mu.uPass.value = 1; mu.uCastOn.value = 0; mu.tCastInfo.value = null; mu.tCastDepth.value = null;
      });
      R.setRenderTarget(targets.rtInfo); R.clear(); R.render(scene, camera);
      const ppmBuf = buf.y / (camera.top - camera.bottom) * camera.zoom;
      for (const o of meshes) {
        const mu = o.material.uniforms;
        mu.uPass.value = 0; mu.uCastOn.value = 1; mu.tCastInfo.value = targets.rtInfo.texture; mu.tCastDepth.value = targets.rtInfo.depthTexture;
        mu.uCastRes.value.set(buf.x, buf.y); mu.uCastNear.value = camera.near; mu.uCastFar.value = camera.far; mu.uCastPpm.value = ppmBuf;
      }
      R.setRenderTarget(targets.rt); R.clear(); R.render(scene, camera);
      const u = paint.mat.uniforms;
      u.tColor.value = targets.rt.texture; u.tInfo.value = targets.rtInfo.texture; u.tDepth.value = targets.rtInfo.depthTexture;
      u.uRes.value.set(buf.x, buf.y); u.uNear.value = camera.near; u.uFar.value = camera.far;
      // line weight follows the figure's size on screen (study: ~0.4% of its height)
      const ppm = buf.y / (camera.top - camera.bottom) * camera.zoom, dpr = R.getPixelRatio();
      u.uSil.value = THREE.MathUtils.clamp(1.75 * ppm * 0.0042, dpr, 2.6 * dpr);
      u.uInner.value = Math.max(dpr * 0.75, u.uSil.value * 0.55);
      R.setRenderTarget(null); R.clear(); R.render(paint.scene, compCam);
    }
    
    // ---- check sheets ----------------------------------------------------------------------------------------------------
    // ?sheet=<name> poses one character through every check view; ?sheet=duel shows the bind. Each tile
    // is posed, its cloth settled at that angle, rendered by the same painted renderer as the page, and
    // drawn into one image, which lands in #sheetOut as a PNG data URL (a headless browser reads it).
    const ARMS_YAWS = [0, 45, 90, 135, 180, 270];
    347:  uniform sampler2D tCastInfo; uniform sampler2D tCastDepth; uniform vec2 uCastRes; uniform int uCastOn;
    426:    else if (uCastOn == 1 && uKind == 1 && int(uInfo.x * 255.0 + 0.5) == 2 && castShadow() > 0.5)
    813:    tCastInfo: { value: null }, tCastDepth: { value: null }, uCastRes: { value: new THREE.Vector2(1, 1) }, uCastOn: { value: 0 },
    1348:    const mu = o.material.uniforms; mu.uPass.value = 1; mu.uCastOn.value = 0; mu.tCastInfo.value = null; mu.tCastDepth.value = null;
    1354:    mu.uPass.value = 0; mu.uCastOn.value = 1; mu.tCastInfo.value = targets.rtInfo.texture; mu.tCastDepth.value = targets.rtInfo.depthTexture;
  • Bashsource ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && grep -n "SKIN_HEAD\b\|const SKIN_HEAD\|const SKIN_BODY" review/vroid-02/index.html | head -3; grep -n "\"A\"\|'A':\|\"o\":\|\"1\":\|\"2\":" tools/vroid_portrait.py | head; grep -n "^HAIR_TONES\|^SKIN =" -A6 tools/vroid_portrait.py | head -20

    command

    source ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && grep -n "SKIN_HEAD\b\|const SKIN_HEAD\|const SKIN_BODY" review/vroid-02/index.html | head -3; grep -n "\"A\"\|'A':\|\"o\":\|\"1\":\|\"2\":" tools/vroid_portrait.py | head; grep -n "^HAIR_TONES\|^SKIN =" -A6 tools/vroid_portrait.py | head -20

    result, 7 lines

    309:const SKIN_HEAD = `#include <common>
    311:const SKIN_BODY = `#include <beginnormal_vertex>
    316:const PAINT_VS = `${SKIN_HEAD}
    42:PRIORITY = {"o": 8, "r": 5, "s": 5, "t": 4, "w": 3, "A": 3, "1": 8}   # features win the 4x4 vote
    994:                char[mk] = "A"
    1019:            down = {"E": "D", "D": "C", "C": "B", "B": "A"}
    1062:            rule[hair0 & hair1 & (p1 != prim)] = "A"

agent

+2:19

Now the page edits: brow depth bias, darker brow colour, thicker alpha, mouth texture remap and mouth outline.

  • Bashsource ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && python3 - <<'EOF'

    command

    source ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && python3 - <<'EOF'
    p="review/vroid-02/index.html"; s=open(p).read()
    def rep(a,b,n=1):
        global s
        assert s.count(a)==n, (a, s.count(a)); s=s.replace(a,b)
    # 1. vertex shader: a depth pull toward the camera (brows over the bangs)
    rep("""  attribute float edge; attribute vec4 _plate;
      varying vec3 vN;""", """  attribute float edge; attribute vec4 _plate; uniform float uFront;
      varying vec3 vN;""")
    rep("""    vec4 mv = modelViewMatrix * vec4(transformed, 1.0); vView = -mv.xyz;
        gl_Position = projectionMatrix * mv;
      }`;""", """    vec4 mv = modelViewMatrix * vec4(transformed, 1.0); vView = -mv.xyz;
        gl_Position = projectionMatrix * vec4(mv.xy, mv.z + uFront, mv.w);   // uFront: drawn over what is this close in front
      }`;""")
    # 2. fragment: brow alpha threshold, mouth kind
    rep("""    if (uAlpha == 1 && tex.a < 0.5) discard;""", """    if (uAlpha == 1 && tex.a < 0.5) discard;
        if (uAlpha == 3 && tex.a < 0.28) discard;                       // brows: a fuller stroke than the texture's half alpha""")
    rep("""    } else if (uKind == 8) { col = tex.rgb; }""", """    } else if (uKind == 8) { col = tex.rgb; }
        else if (uKind == 10) {                                            // the open mouth: VRoid's map read as three parts,
          float lum = dot(tex.rgb, vec3(1.0 / 3.0));                       // teeth (white), tongue (its light pink) and the
          col = mix(vec3(0.40, 0.13, 0.16), vec3(0.86, 0.47, 0.50), smoothstep(0.53, 0.58, tex.g));   // dark inside
          col = mix(col, vec3(0.98, 0.96, 0.95), smoothstep(0.80, 0.86, lum));
        }""")
    # 3. material setup
    rep("""  u.uBand.value = u.uGold.value.clone();
      const m = new THREE.ShaderMaterial(""", """  if (role === "brow") {                            // brows: a deep shade of the hair, drawn over the bangs (3 cm)
        u.uAlpha.value = map ? 3 : 0; u.uFront.value = 0.03;
        if (V.paint && V.paint.hair) { const h = {}; hex(V.paint.hair.base).getHSL(h); u.uFlat.value.setHSL(h.h * 0.92, Math.min(1, h.s * 0.75), 0.17); }
      }
      if (role === "mouth" && map) u.uKind.value = 10;
      u.uBand.value = u.uGold.value.clone();
      const m = new THREE.ShaderMaterial(""")
    rep("""    uSkinTone: { value: new THREE.Vector3(1, 1, 1) }, uShadeOnly: { value: 0 },""", """    uSkinTone: { value: new THREE.Vector3(1, 1, 1) }, uShadeOnly: { value: 0 }, uFront: { value: 0 },""")
    # 4. composite: a dark line round the open mouth
    rep("""    bool feature = r0 >= 4 && r0 <= 9;""", """    bool feature = r0 >= 4 && r0 <= 9;
        if (r0 == 9) {                                              // the open mouth's rim: a lip line where it meets the face
          for (int k = 0; k < 8; k++) {
            float a = float(k) * 0.785398;
            vec2 q = uv + vec2(cos(a), sin(a)) * uSil * 0.9 * px;
            vec4 ni = texture2D(tInfo, q);
            if (ni.a > 0.5 && rid(ni) == 1) { col = mix(ink(texture2D(tColor, q).rgb), vec3(0.30, 0.10, 0.12), 0.4); break; }
          }
        }""")
    open(p,"w").write(s)
    EOF
    grep -n "hex = \|function hex" review/vroid-02/index.html | head -3

    result, 1 line

    290:const hex = h => {                                     // raw palette value, no colour-space conversion
  • Bashsource ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && sed -n 288,296p review/vroid-02/index.html

    command

    source ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && sed -n 288,296p review/vroid-02/index.html

    result, 9 lines

    }
    
    const hex = h => {                                     // raw palette value, no colour-space conversion
      const n = parseInt(h.slice(1), 16);
      return new THREE.Color().setRGB((n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255, THREE.LinearSRGBColorSpace);
    };
    const rawTex = t => { if (!t) return null; const c = t.clone(); c.colorSpace = THREE.NoColorSpace; c.needsUpdate = true; return c; };
    const gradient = (() => {
      const d = new Uint8Array([70, 70, 70, 255, 140, 140, 140, 255, 205, 205, 205, 255, 255, 255, 255, 255]);
  • Bashsource ~/Projects/lowmarch-bench/kit/env-a.sh && cp $WORK/expr_list.txt $WORK/expr_list.orig.txt && cat > $WORK/expr_list.txt <<'EOF'

    command

    source ~/Projects/lowmarch-bench/kit/env-a.sh && cp $WORK/expr_list.txt $WORK/expr_list.orig.txt && cat > $WORK/expr_list.txt <<'EOF'
    # expression recipes: name|VRoid shapes baked at build (Fcl_* names, weight; ';' between; 'none' = neutral)
    # the 14 the sheets show; keep these names (front_sheet.py reads them). Edit the recipes freely.
    neutral|none
    joy|Fcl_EYE_Joy:1;Fcl_BRW_Joy:1;Fcl_MTH_Joy:0.6
    smile|Fcl_BRW_Fun:0.6;Fcl_EYE_Fun:0.4;Fcl_MTH_Fun:1
    angry|Fcl_BRW_Angry:1;Fcl_EYE_Angry:0.7;Fcl_MTH_Angry:1
    sad|Fcl_BRW_Sorrow:1;Fcl_EYE_Sorrow:0.7;Fcl_MTH_Sorrow:1
    surprised|Fcl_BRW_Surprised:1;Fcl_EYE_Surprised:1;Fcl_MTH_Surprised:0.55
    shout|Fcl_BRW_Angry:1;Fcl_EYE_Angry:0.6;Fcl_MTH_A:1
    wink|Fcl_EYE_Close_R:1;Fcl_BRW_Fun:0.6;Fcl_MTH_Fun:1
    smug|Fcl_EYE_Close:0.35;Fcl_BRW_Fun:0.4;Fcl_MTH_Fun:0.7
    lip_A|Fcl_MTH_A:0.75
    lip_I|Fcl_MTH_I:1
    lip_U|Fcl_MTH_U:1
    lip_E|Fcl_MTH_E:0.85
    lip_O|Fcl_MTH_O:0.8
    EOF
    cd $LOWMARCH_REPO && date && time $KIT/build_expr.sh $WORK/expr_list.txt neutral joy smile angry sad

    result, 10 lines

    Fri Oct 30 12:45:59 PM PST 2026
    built neutral
    built joy
    built smile
    built angry
    built sad
    
    real	1m26.062s
    user	1m8.025s
    sys	0m52.766s
  • Bashsource ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && time $KIT/build_expr.sh $WORK/expr_list.txt surprised shout wink smug lip_A lip_I lip_U lip_E lip_O && time $KIT/shoot_expr.sh $LOWMARCH_REPO/review/vroid-02/index.html r1 && $KIT/sheets.sh r1 "Round 1: brows over bangs, mouth colours+rim, split recipes"

    command

    source ~/Projects/lowmarch-bench/kit/env-a.sh && cd $LOWMARCH_REPO && time $KIT/build_expr.sh $WORK/expr_list.txt surprised shout wink smug lip_A lip_I lip_U lip_E lip_O && time $KIT/shoot_expr.sh $LOWMARCH_REPO/review/vroid-02/index.html r1 && $KIT/sheets.sh r1 "Round 1: brows over bangs, mouth colours+rim, split recipes"

    result, 20 lines

    built surprised
    built shout
    built wink
    built smug
    built lip_A
    built lip_I
    built lip_U
    built lip_E
    built lip_O
    
    real	2m26.598s
    user	2m2.291s
    sys	1m43.091s
    shot r1
    
    real	7m31.980s
    user	0m32.006s
    sys	0m26.725s
    Command did not complete within its 600s timeout and was moved to the background (ID: bjx5t4ezo). Output is being written to: /tmp/claude-1000/-home-severian-Projects/d2fdcea1-0c48-4814-81a2-89cf837a9b4f/tasks/bjx5t4ezo.output. You will be notified when it completes. It is running now: do not start a second copy while it runs. If it is no longer needed, stop it with TaskStop. To check interim output, use Read on that file path.
    Session cwd remains ~/Projects/lowmarch-bench/c; directory changes made by the backgrounded command do not apply to subsequent commands.
  • Read~/Projects/lowmarch-bench/work/a/shot_r1/angry/painted_arm_f_slender.png

    input

    {
      "file_path": "~/Projects/lowmarch-bench/work/a/shot_r1/angry/painted_arm_f_slender.png"
    }

    result

    no output

    shot_r1_angry_woman.jpg
    shot_r1_angry_woman.jpg