Staging: a shared lattice, and the element size the songs were all sharing
The cast and ink slice lowered the floor as predicted but left `scale` — feature
size — consistently WORSE than the legacy arm, 0.033 against 0.053 and well
outside the noise. Every stage still chose its own element size from its own
param range, so every song landed in the same place: the videos shared a cast
and also, accidentally, shared how big everything was.
Staging is the third artifact. A lattice — grid, radial, spiral, scatter,
strata — with jitter, spread, a size hierarchy and a bias toward the middle or
the edges, transported the same way the cast is: uniforms plus a `stageNode`
function in the preamble, no new engine plumbing. Constellation, Swarm and
Procession place on it; the stage keeps its motion and gives up its composition.
Soloist takes only the scale, since a close-up has no composition to share.
`elementScale` is the part that mattered. It is the song's answer to "how big is
this made of", spanning about a factor of six, and it is the decision that was
missing rather than mis-set. Measured, over twelve songs and three runs:
stages spread +0.0111 ±0.0043 → +0.0143 ±0.0008
scale block 0.033 ±0.004 → 0.041 ±0.007
Against the legacy arm at +0.0108 ±0.0071 the harness still says
indistinguishable, and it is right to: the gap is +0.0035 and the legacy arm's
own run-to-run range is twice that. What can be said is narrower and holds up.
Stages have the lowest floor of the three arms by a clear margin — 0.082 against
0.095 and 0.104 — so sharing content does make a video look like itself, which
was the central prediction. And the targeted fix moved the block it was aimed at
in the direction it was aimed.
Also added: a lint check that the shader preamble contains no backticks. Twice
now one has closed the template literal and produced a check page that hangs on
"starting…" with an empty console, which is an expensive way to find a typo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,9 @@
|
||||
/** Fill treatments, as the shader's `u_inkFill` index. */
|
||||
export const FILLS = ['flat', 'ramp', 'hatch', 'stipple', 'halftone', 'hollow'];
|
||||
|
||||
/** Lattices, as the shader's `u_latKind` index. */
|
||||
export const LATTICES = ['grid', 'radial', 'spiral', 'scatter', 'strata'];
|
||||
|
||||
const clamp01 = (x) => Math.max(0, Math.min(1, x));
|
||||
|
||||
/**
|
||||
@@ -110,7 +113,47 @@ export function generateIdentity(summary, rng, sections = 4) {
|
||||
posterize: rng.bool(0.3) ? rng.int(3, 6) : 0,
|
||||
};
|
||||
|
||||
return { cast: { protagonist, chorus }, ink, character: { angular, intricate, solid } };
|
||||
// STAGING: where things go, and how their sizes are distributed.
|
||||
//
|
||||
// The first four stages separated songs almost entirely on layout while
|
||||
// their feature SCALE collapsed — every stage placed similarly-sized
|
||||
// elements, so size stopped being a variable at all. A shared lattice fixes
|
||||
// both halves: the stages agree with each other about placement, which is
|
||||
// what makes a video look like itself, and the size hierarchy becomes a
|
||||
// decision the song makes rather than one each stage makes for itself.
|
||||
const lattice = {
|
||||
kind: rng.pickWeighted(LATTICES, [
|
||||
1 + angular * 3, // grid
|
||||
1 + (1 - angular) * 2, // radial
|
||||
1 + (1 - angular) * 2, // spiral
|
||||
2, // scatter
|
||||
1 + angular * 2, // strata
|
||||
]),
|
||||
jitter: clamp01(rng.range(0, 0.5) + (1 - angular) * 0.3),
|
||||
spread: rng.range(0.5, 0.85) + dynamic * 0.35,
|
||||
// A few large and many small, or all one size. Busy material earns the
|
||||
// hierarchy; a sparse track wants its elements to be equals.
|
||||
scaleSpread: clamp01(0.15 + intricate * 0.6 + rng.range(-0.2, 0.25)),
|
||||
// Whether the big ones sit in the middle or around the edges.
|
||||
scaleBias: rng.range(-1, 1),
|
||||
// How big the song's elements are AT ALL — a per-song decision rather
|
||||
// than a per-stage one.
|
||||
//
|
||||
// This is the block the measurements kept pointing at. Sharing a cast
|
||||
// lowered the floor as predicted, but `scale` — feature size — came out
|
||||
// consistently WORSE than the legacy arm (0.033 against 0.053, well
|
||||
// outside the noise), because every stage still chose its own element
|
||||
// size from its own param range and every song therefore landed in the
|
||||
// same place. A song made of six huge forms and a song made of four
|
||||
// hundred tiny ones are different videos before anything else is
|
||||
// decided; that decision belongs here.
|
||||
elementScale: 0.35 * 2 ** rng.range(-1.4, 1.4) * (1.25 - intricate * 0.5),
|
||||
};
|
||||
|
||||
return {
|
||||
cast: { protagonist, chorus }, ink, lattice,
|
||||
character: { angular, intricate, solid },
|
||||
};
|
||||
}
|
||||
|
||||
/** Neutral values, so a layer built without an identity renders as it always did. */
|
||||
@@ -121,6 +164,8 @@ export const NEUTRAL_IDENTITY_UNIFORMS = {
|
||||
u_chorusNotchN: 0, u_chorusNotchD: 0, u_chorusHollow: 0,
|
||||
u_inkWeight: 0.3, u_inkEdge: 0.5, u_inkFill: 0, u_inkHatchAngle: 0,
|
||||
u_inkHatchScale: 80, u_inkOutline: 0, u_inkPosterize: 0,
|
||||
u_latKind: 3, u_latJitter: 0.5, u_latSpread: 0.9,
|
||||
u_latScaleSpread: 0.3, u_latScaleBias: 0, u_latScale: 0.35,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -162,6 +207,13 @@ export function identityUniforms(identity, shape = null) {
|
||||
u_inkFill: FILLS.indexOf(ink.fill),
|
||||
u_inkHatchAngle: ink.hatchAngle, u_inkHatchScale: ink.hatchScale,
|
||||
u_inkOutline: ink.outline, u_inkPosterize: ink.posterize,
|
||||
|
||||
u_latKind: LATTICES.indexOf(identity.lattice.kind),
|
||||
u_latJitter: identity.lattice.jitter,
|
||||
u_latSpread: identity.lattice.spread,
|
||||
u_latScaleSpread: identity.lattice.scaleSpread,
|
||||
u_latScaleBias: identity.lattice.scaleBias,
|
||||
u_latScale: identity.lattice.elementScale,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -175,5 +227,7 @@ export function describeIdentity(identity) {
|
||||
const ink = identity.ink;
|
||||
return `cast ${form(a)} + ${form(b)} · ink ${ink.fill}` +
|
||||
`${ink.outline ? '+outline' : ''}${ink.posterize ? `/${ink.posterize}-tone` : ''}` +
|
||||
` w${ink.weight.toFixed(2)}`;
|
||||
` w${ink.weight.toFixed(2)} · on ${identity.lattice.kind}` +
|
||||
` at ${identity.lattice.elementScale < 0.2 ? 'tiny' :
|
||||
identity.lattice.elementScale > 0.6 ? 'huge' : 'mid'} scale`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user