A reproducible migration, and the first eighteen scenes through it
The library is sixty-one scenes, which is too many to convert from memory or from taste, so the migration is a queue with a gate rather than a judgement call per file. Three pieces. A classifier reads each shader and assigns a tier from evidence in the source — drawn, figure, field, treatment — so two passes over the library reach the same answer and the work has an order. MIGRATION.md is the recipe per tier, written to be followed mechanically. And a gate makes the result verifiable: `consumes` is now a schema field, the lint enforces it in both directions, and the per-scene battery renders each scene under two deliberately distant identities and requires the picture to change. That gate is the part that matters. Without it `consumes` is a comment, and the whole inversion becomes unverifiable at exactly the point where it stops being checkable by eye. With it, a scene that declares the cast and ignores it fails. Eighteen scenes migrated. Four by hand at the drawn tier — Firefly Drift, Metaballs, Floating Geometry, Prism Bloom — and ten at the field tier by script, which is one declaration and one wrapped return. All eighteen pass. The field tier is honestly marginal and the gate says so: every one of the ten moves by 37 to 39 of 255, against 173 to 255 for the drawn tier, and the uniformity across ten unrelated scenes is the tell. That is one global posterisation applying, not ten scenes expressing anything. Cheap, real, shallow. The decomposition moved from identity being worth 54% of the container to 158%, but the stage set changed underneath the measurement and part of that is Metaballs expressing a cast better than Constellation did. What survives the caveat is the useful finding: a migrated library scene carries the identity better than a stage written from scratch to carry it. The four bespoke stages were the wrong shape of effort. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,7 @@ import { synthesizeSectioned } from '../audio/synth.js';
|
||||
import { frameLuminance, frameVariance, frameMaxDelta } from '../engine/hash.js';
|
||||
import { peakFlashRate } from '../engine/flash.js';
|
||||
import { generatePersonality } from '../look/Personality.js';
|
||||
import { generateIdentity } from '../look/Identity.js';
|
||||
|
||||
const PALETTE = [
|
||||
[0.06, 0.03, 0.16], [0.85, 0.15, 0.55], [0.15, 0.75, 0.95],
|
||||
@@ -133,6 +134,41 @@ export function runSceneGate(name) {
|
||||
const rate = peakFlashRate(luminance, 60);
|
||||
record(rate <= 3, 'flash rate', `${rate}/s at aggressive settings (ceiling 3)`);
|
||||
|
||||
// --- identity response -----------------------------------------------
|
||||
// The migration gate. A scene that declares it consumes the cast must
|
||||
// produce a DIFFERENT PICTURE when the song's cast changes — otherwise
|
||||
// `consumes` is a comment and the whole inversion is unverifiable at
|
||||
// library scale. Deliberately a much larger threshold than the trait
|
||||
// check: a trait may be honoured subtly, but content is the subject.
|
||||
for (const artifact of module.consumes || []) {
|
||||
const other = generatePersonality(SUMMARY, new Rng(9001));
|
||||
// Two identities as far apart as the generator can make them.
|
||||
const alt = generateIdentity(
|
||||
{ ...SUMMARY, meanFlatness: 0.6, meanCentroid: 0.85, bpm: 168 },
|
||||
new Rng(31337), 6);
|
||||
// Force the always-visible ink decisions on. A field scene's whole
|
||||
// migration may be `inkValue`, and posterisation is off for most
|
||||
// identities — without pinning it the probe would sometimes hand the
|
||||
// scene two identities that ask it for the same picture and then
|
||||
// fail it for complying.
|
||||
alt.ink = { ...alt.ink, posterize: 4, fill: 'hatch', outline: 0.8, weight: 0.8 };
|
||||
other.identity = alt;
|
||||
if (artifact === 'cast') {
|
||||
// The protagonist's geometry is read from the signature form.
|
||||
other.shape = { sides: 8, roundness: 0.02, elongation: 1.4, tilt: 0.9 };
|
||||
}
|
||||
|
||||
engine.setLayerSpecs([{
|
||||
module, params: defaultValues(module), seed: 4242,
|
||||
opacity: 1, blend: 'normal', palette: PALETTE, personality: other,
|
||||
}]);
|
||||
engine.compositor.reset();
|
||||
const changed = frameMaxDelta(base,
|
||||
Uint8Array.from(engine.readPixels(engine.renderFrame(600))));
|
||||
record(changed > 24, `consumes: ${artifact}`,
|
||||
`delta ${changed}/255 (floor 24)`);
|
||||
}
|
||||
|
||||
// --- personality response --------------------------------------------
|
||||
// Every declared trait must move the image; a trait declared and ignored
|
||||
// gets the scene cast in tracks it cannot express.
|
||||
|
||||
@@ -381,7 +381,7 @@ export async function decomposeReportLines({ songs = 6, probes = 3 } = {}) {
|
||||
const lines = [];
|
||||
lines.push('IDENTITY vs CONTAINER — where visual difference actually comes from');
|
||||
lines.push('');
|
||||
lines.push(` ${d.songs} songs · one fixed track · stage held or varied as labelled`);
|
||||
lines.push(` ${d.songs} songs · one fixed track · ${d.stageCount} cast-consuming scenes`);
|
||||
lines.push('');
|
||||
lines.push(` identity only ${bar(Math.min(1, d.identityOnly * 5))} ${d.identityOnly.toFixed(4)}`);
|
||||
lines.push(` one stage (${d.stage}), each song's cast, ink and lattice`);
|
||||
|
||||
@@ -622,8 +622,12 @@ export function measureFingerprint({ songs = 6, probes = 4, refScenes = 5 } = {}
|
||||
export function measureDecomposition({ songs = 6, probes = 3, stageNames = null } = {}) {
|
||||
const bank = songBank({ count: songs });
|
||||
const track = bank[0].track;
|
||||
const names = stageNames || ['Procession', 'Constellation', 'Soloist', 'Swarm'];
|
||||
const stages = names.map((n) => scenes.find((m) => m.name === n)).filter(Boolean);
|
||||
// Every scene that actually draws the cast, not a hardcoded list — so this
|
||||
// number tracks the migration instead of being pinned to the four scenes
|
||||
// that happened to be written first.
|
||||
const stages = stageNames
|
||||
? stageNames.map((n) => scenes.find((m) => m.name === n)).filter(Boolean)
|
||||
: scenes.filter((m) => (m.consumes || []).includes('cast') && m.role !== 'accent');
|
||||
|
||||
// Each song's identity, lifted off its own look so it can be transplanted.
|
||||
const looks = bank.map((e) => generateLook(e.track, { seed: hashString(e.name) }));
|
||||
@@ -673,5 +677,8 @@ export function measureDecomposition({ songs = 6, probes = 3, stageNames = null
|
||||
render(oneStage, looks[0], 4242),
|
||||
]);
|
||||
|
||||
return { identityOnly, containerOnly, both, sameBoth, stage: oneStage.name, songs: bank.length };
|
||||
return {
|
||||
identityOnly, containerOnly, both, sameBoth,
|
||||
stage: oneStage.name, songs: bank.length, stageCount: stages.length,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -53,6 +53,15 @@ export const REACTIVE_FEATURES = [
|
||||
|
||||
export const REACTIVE_RESPONSES = ['linear', 'spike', 'smooth', 'inverse'];
|
||||
|
||||
/**
|
||||
* Identity artifacts a scene can consume. See look/Identity.js and EPIC-3.md.
|
||||
*
|
||||
* A trait is a modifier a scene may honour; an artifact is CONTENT the scene
|
||||
* draws. Declaring one is a commitment the gate enforces: swap the song's
|
||||
* identity and a scene that claims `cast` must produce a different picture.
|
||||
*/
|
||||
export const ARTIFACT_NAMES = ['cast', 'ink', 'staging'];
|
||||
|
||||
/**
|
||||
* Personality traits a scene can honour. See look/Personality.js.
|
||||
*
|
||||
@@ -231,6 +240,15 @@ export function validateModule(module) {
|
||||
if (!TRAIT_NAMES.includes(t)) errors.push(`${id}: unknown trait '${t}'`);
|
||||
}
|
||||
}
|
||||
if (module.consumes !== undefined) {
|
||||
if (!Array.isArray(module.consumes)) {
|
||||
errors.push(`${id}: \`consumes\` must be an array of ${ARTIFACT_NAMES.join('/')}`);
|
||||
} else {
|
||||
for (const a of module.consumes) {
|
||||
if (!ARTIFACT_NAMES.includes(a)) errors.push(`${id}: unknown artifact '${a}'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (module.texture !== undefined
|
||||
&& (typeof module.texture !== 'number' || module.texture < 0 || module.texture > 2)) {
|
||||
errors.push(`${id}: \`texture\` must be a number 0..2 — how much of the track's ` +
|
||||
|
||||
@@ -14,6 +14,7 @@ export const contourMap = {
|
||||
kind: 'fragment',
|
||||
// Drafting, not photography.
|
||||
texture: 0.3,
|
||||
consumes: ['ink'],
|
||||
traits: ['camera', 'space', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -88,7 +89,7 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
|
||||
col = sigAir(col, p, sat(1.0 - below * 0.9));
|
||||
col += sigGrain(uv);
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ export const fireflyDrift = {
|
||||
family: 'flow',
|
||||
kind: 'fragment',
|
||||
// Personality: see look/Personality.js.
|
||||
consumes: ['cast', 'ink', 'staging'],
|
||||
traits: ['camera', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -38,25 +39,29 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
if (float(i) >= u_count) break;
|
||||
float fi = float(i);
|
||||
|
||||
// Seed the mote to a stable place in the frame (deterministic per i).
|
||||
vec2 grid = vec2(hash12(vec2(fi, 1.7)), hash12(vec2(fi, 9.1)));
|
||||
vec2 base = (grid - 0.5) * 2.0 * u_spread * vec2(1.0, 0.7);
|
||||
// The mote's home is the song's lattice; the drift is this scene's own.
|
||||
vec3 node = stageNode(fi, u_count);
|
||||
vec2 base = node.xy * u_spread * vec2(1.0, 0.7);
|
||||
|
||||
// Advect along the curl field plus a bounded wander term on top.
|
||||
vec2 flow = curl(grid * 3.0 + vec2(0.0, t * 0.15), t * 0.5);
|
||||
vec2 flow = curl(node.xy * 3.0 + vec2(0.0, t * 0.15), t * 0.5);
|
||||
vec2 pos = base + flow * 1.3
|
||||
+ vec2(sin(t * (0.4 + fract(fi * 0.13))),
|
||||
cos(t * (0.5 + fract(fi * 0.29)))) * u_jitter;
|
||||
|
||||
// A mote is one of the chorus, drawn small — the glow is the scene's
|
||||
// contribution, the form is the song's.
|
||||
float size = 0.045 * node.z;
|
||||
float sd = castChorus((p - pos) / max(size, 1e-3)) * size;
|
||||
float d = length(p - pos);
|
||||
|
||||
vec3 hc = pal(int(mod(fi, 4.0)));
|
||||
col = mix(col, hc, inkMask(sd, uv));
|
||||
col += hc * (exp(-d * d / (0.015 + u_glow * 0.04)) * (1.0 + u_glow * 0.6));
|
||||
col += hc * exp(-d * d * 60.0);
|
||||
}
|
||||
|
||||
col += sigGrain(uv);
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
@@ -10,6 +10,7 @@ export const floatingGeometry = {
|
||||
// of shapes, so `shape` is the trait it exists to express.
|
||||
// Takes the track's surface grain, but lightly — this is drawn, not filmed.
|
||||
texture: 0.4,
|
||||
consumes: ['cast', 'ink', 'staging'],
|
||||
traits: ['shape', 'camera', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -41,30 +42,29 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
float fi = float(i);
|
||||
float s = u_seed + fi * 123.456;
|
||||
|
||||
vec2 pos = vec2(
|
||||
sin(t * 0.5 + s) * u_spread,
|
||||
cos(t * 0.3 + s * 1.1) * u_spread * 0.55
|
||||
);
|
||||
// The song's lattice sets where they hang; this scene keeps the float.
|
||||
vec3 node = stageNode(fi, float(u_count));
|
||||
vec2 pos = node.xy * u_spread * vec2(1.0, 0.55)
|
||||
+ vec2(sin(t * 0.5 + s), cos(t * 0.3 + s * 1.1)) * 0.18;
|
||||
|
||||
vec2 sp = rot(t * (0.2 + fract(s) * u_spin)) * (p - pos);
|
||||
|
||||
float size = u_size * (0.6 + fract(s * 0.7) * 0.8);
|
||||
float size = u_size * node.z * (0.6 + fract(s * 0.7) * 0.8);
|
||||
|
||||
// Every element is the track's signature form. This scene used to pick
|
||||
// Every element is the song's protagonist. This scene used to pick
|
||||
// between a box and a circle per element, which is precisely the choice
|
||||
// the production design should be making — one video, one cast.
|
||||
// The variety param only scales them apart; it never changes what they are.
|
||||
float scale = size * (1.0 + (fract(s * 0.37) - 0.5) * u_variety);
|
||||
float d = sigShape(sp / max(scale, 1e-3)) * scale;
|
||||
float d = castMain(sp / max(scale, 1e-3)) * scale;
|
||||
|
||||
vec3 shapeColor = pal(i + int(floor(t * 0.3)));
|
||||
float intensity = smoothstep(0.012, 0.0, d) + sigEdge(d) * 0.35;
|
||||
col = mix(col, shapeColor, intensity * 0.85);
|
||||
col = mix(col, shapeColor, inkMask(d, uv) * 0.85);
|
||||
col += shapeColor * (1.0 - smoothstep(0.0, size * 2.2, abs(d))) * u_aura;
|
||||
}
|
||||
|
||||
col += sigGrain(uv);
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@ export const halftoneMisprint = {
|
||||
kind: 'fragment',
|
||||
// The paper's tooth is the point; take the track's grain in full.
|
||||
texture: 1.2,
|
||||
consumes: ['ink'],
|
||||
traits: ['camera', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -94,7 +95,7 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
|
||||
col = max(col, vec3(0.0));
|
||||
col += sigGrain(uv);
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ export const metaballs = {
|
||||
family: 'organic',
|
||||
kind: 'fragment',
|
||||
// Personality: see look/Personality.js.
|
||||
consumes: ['cast', 'ink', 'staging'],
|
||||
traits: ['shape', 'camera', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -39,16 +40,18 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
float fi = float(i);
|
||||
float s = u_seed + fi * 71.3;
|
||||
|
||||
vec2 centre = vec2(
|
||||
sin(t * (0.7 + fract(s * 0.13)) + s) * u_spread,
|
||||
cos(t * (0.5 + fract(s * 0.29)) + s * 1.7) * u_spread * 0.62
|
||||
);
|
||||
// Homes on the song's lattice, orbited by this scene's own motion.
|
||||
vec3 node = stageNode(fi, float(u_count));
|
||||
vec2 centre = node.xy * u_spread * vec2(1.0, 0.62)
|
||||
+ vec2(sin(t * (0.7 + fract(s * 0.13)) + s),
|
||||
cos(t * (0.5 + fract(s * 0.29)) + s * 1.7)) * 0.25;
|
||||
|
||||
// Distance measured in the track's form rather than as a circle: for a
|
||||
// round personality this is exactly length(p - centre), and for a
|
||||
// hexagonal one the blobs merge as hexagons.
|
||||
float d = sigShape((p - centre) / max(u_radius, 1e-3)) * u_radius + u_radius;
|
||||
float contribution = (u_radius * u_radius) / max(d * d, 1e-4);
|
||||
// Distance measured in the song's FORM rather than as a circle: for a
|
||||
// round cast this is exactly length(p - centre), and for a hexagonal
|
||||
// one the blobs merge as hexagons.
|
||||
float radius = u_radius * node.z;
|
||||
float d = castMain((p - centre) / max(radius, 1e-3)) * radius + radius;
|
||||
float contribution = (radius * radius) / max(d * d, 1e-4);
|
||||
field += contribution;
|
||||
tint += pal(i) * contribution;
|
||||
}
|
||||
@@ -64,7 +67,7 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
col += tint * rim * u_rim;
|
||||
col += sigGrain(uv);
|
||||
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ export const moireGrid = {
|
||||
// Personality: see look/Personality.js.
|
||||
// Crisp line work: the track's surface grain would only fur the edges.
|
||||
texture: 0,
|
||||
consumes: ['ink'],
|
||||
traits: ['camera', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -67,7 +68,7 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
|
||||
col *= 0.6 + 0.4 * exp(-dot(p, p) * 0.3);
|
||||
col += sigGrain(uv);
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ export const myceliumWeb = {
|
||||
name: 'Mycelium Web',
|
||||
family: 'organic',
|
||||
kind: 'fragment',
|
||||
consumes: ['ink'],
|
||||
traits: ['camera', 'space', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -91,7 +92,7 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
|
||||
col = sigAir(col, p, sat(1.0 - below * 1.1));
|
||||
col += sigGrain(uv);
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ export const nebula = {
|
||||
family: 'organic',
|
||||
kind: 'fragment',
|
||||
// Personality: see look/Personality.js.
|
||||
consumes: ['ink'],
|
||||
traits: ['camera', 'space', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -59,7 +60,7 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
col = sigAir(col, p, smoothstep(0.0, 1.6, r));
|
||||
col += sigGrain(uv);
|
||||
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ export const plasmaBloom = {
|
||||
family: 'organic',
|
||||
kind: 'fragment',
|
||||
// Personality: see look/Personality.js.
|
||||
consumes: ['ink'],
|
||||
traits: ['camera', 'space', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -48,7 +49,7 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
|
||||
col = sigAir(col, p, smoothstep(0.0, 1.8, length(p)));
|
||||
col += sigGrain(uv);
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ export const prismBloom = {
|
||||
// Personality: see look/Personality.js.
|
||||
// Crisp line work: the track's surface grain would only fur the edges.
|
||||
texture: 0,
|
||||
consumes: ['cast', 'ink', 'staging'],
|
||||
traits: ['shape', 'camera', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -45,8 +46,8 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
float t = u_time * u_speed + u_seed;
|
||||
p = sigFolded(sigCamera(p));
|
||||
|
||||
// Facet count yields to the track's signature form when it names one.
|
||||
float sites = u_sigSides > 2.5 ? u_sigSides : float(u_sites);
|
||||
// Facet count yields to the song's cast when it names a form.
|
||||
float sites = u_castSides > 2.5 ? u_castSides : float(u_sites);
|
||||
|
||||
vec3 col = pal(0) * 0.04;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
@@ -54,7 +55,7 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
float fi = float(i);
|
||||
|
||||
// Layers counter-rotate and breathe independently; all closed-form.
|
||||
float layerRadius = u_radius * (0.5 + fi * 0.24);
|
||||
float layerRadius = u_radius * stageScale() * (0.5 + fi * 0.24);
|
||||
float breathe = 0.78 + 0.22 * sin(u_time * 0.9 + fi * 1.7);
|
||||
vec2 lp = rot(fi * 0.7 + t * (fi * 0.5 + 0.3) * u_spin) * p;
|
||||
|
||||
@@ -65,13 +66,14 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
col += pal(0) * halo;
|
||||
}
|
||||
|
||||
// The heart of the bloom is the track's own form.
|
||||
float core = sigForm(p, vec2(0.0), 0.09 + u_beat * 0.06);
|
||||
col = mix(col, pal(3), core);
|
||||
// The heart of the bloom is the song's protagonist, drawn in its ink.
|
||||
float coreSize = (0.09 + u_beat * 0.06) * stageScale();
|
||||
float core = castMain(p / max(coreSize, 1e-3)) * coreSize;
|
||||
col = mix(col, pal(3), inkMask(core, uv));
|
||||
col += pal(3) * exp(-dot(p, p) * 8.0) * (0.5 + u_glow);
|
||||
|
||||
col += sigGrain(uv);
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
@@ -12,6 +12,7 @@ export const rainColumn = {
|
||||
name: 'Rain Column',
|
||||
family: 'flow',
|
||||
kind: 'fragment',
|
||||
consumes: ['ink'],
|
||||
traits: ['camera', 'space', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -101,7 +102,7 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
|
||||
col = sigAir(col, p, smoothstep(0.2, 1.5, abs(p.x) * 0.6 + sat(above)));
|
||||
col += sigGrain(uv);
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ export const ridgeTerrain = {
|
||||
family: 'structural',
|
||||
kind: 'fragment',
|
||||
// Personality: see look/Personality.js.
|
||||
consumes: ['ink'],
|
||||
traits: ['space', 'camera', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -71,7 +72,7 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
}
|
||||
|
||||
col += sigGrain(uv);
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ export const smokeColumn = {
|
||||
name: 'Smoke Column',
|
||||
family: 'flow',
|
||||
kind: 'fragment',
|
||||
consumes: ['ink'],
|
||||
traits: ['camera', 'space', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -81,7 +82,7 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
|
||||
col = sigAir(col, p, smoothstep(0.0, 1.8, length(p)));
|
||||
col += sigGrain(uv);
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@ export const synthwaveRun = {
|
||||
family: 'structural',
|
||||
kind: 'fragment',
|
||||
// Personality: see look/Personality.js.
|
||||
consumes: ['ink'],
|
||||
traits: ['space', 'camera', 'style'],
|
||||
|
||||
params: {
|
||||
@@ -103,7 +104,7 @@ vec4 scene(vec2 uv, vec2 p) {
|
||||
col += colorMain * exp(-abs(p.y - horizon) * 8.0) * u_glow * 0.35;
|
||||
col += sigGrain(uv);
|
||||
|
||||
return vec4(col, 1.0);
|
||||
return vec4(inkValue(col), 1.0);
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user