@dopaminefx/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine/color.d.ts +71 -0
- package/dist/engine/color.d.ts.map +1 -0
- package/dist/engine/color.js +107 -0
- package/dist/engine/color.js.map +1 -0
- package/dist/engine/context.d.ts +54 -0
- package/dist/engine/context.d.ts.map +1 -0
- package/dist/engine/context.js +0 -0
- package/dist/engine/context.js.map +1 -0
- package/dist/engine/gl.d.ts +9 -0
- package/dist/engine/gl.d.ts.map +1 -0
- package/dist/engine/gl.js +39 -0
- package/dist/engine/gl.js.map +1 -0
- package/dist/engine/look/glsl.d.ts +95 -0
- package/dist/engine/look/glsl.d.ts.map +1 -0
- package/dist/engine/look/glsl.js +171 -0
- package/dist/engine/look/glsl.js.map +1 -0
- package/dist/engine/look/particles.glsl.d.ts +21 -0
- package/dist/engine/look/particles.glsl.d.ts.map +1 -0
- package/dist/engine/look/particles.glsl.js +44 -0
- package/dist/engine/look/particles.glsl.js.map +1 -0
- package/dist/engine/sdf.d.ts +77 -0
- package/dist/engine/sdf.d.ts.map +1 -0
- package/dist/engine/sdf.js +255 -0
- package/dist/engine/sdf.js.map +1 -0
- package/dist/engine/seed.d.ts +10 -0
- package/dist/engine/seed.d.ts.map +1 -0
- package/dist/engine/seed.js +20 -0
- package/dist/engine/seed.js.map +1 -0
- package/dist/engine/shadow.d.ts +41 -0
- package/dist/engine/shadow.d.ts.map +1 -0
- package/dist/engine/shadow.js +39 -0
- package/dist/engine/shadow.js.map +1 -0
- package/dist/engine/tempo.d.ts +33 -0
- package/dist/engine/tempo.d.ts.map +1 -0
- package/dist/engine/tempo.js +51 -0
- package/dist/engine/tempo.js.map +1 -0
- package/dist/framework/conductor.d.ts +100 -0
- package/dist/framework/conductor.d.ts.map +1 -0
- package/dist/framework/conductor.js +493 -0
- package/dist/framework/conductor.js.map +1 -0
- package/dist/framework/content.d.ts +67 -0
- package/dist/framework/content.d.ts.map +1 -0
- package/dist/framework/content.js +72 -0
- package/dist/framework/content.js.map +1 -0
- package/dist/framework/dope-pass.d.ts +131 -0
- package/dist/framework/dope-pass.d.ts.map +1 -0
- package/dist/framework/dope-pass.js +346 -0
- package/dist/framework/dope-pass.js.map +1 -0
- package/dist/framework/dope-zip.d.ts +22 -0
- package/dist/framework/dope-zip.d.ts.map +1 -0
- package/dist/framework/dope-zip.js +116 -0
- package/dist/framework/dope-zip.js.map +1 -0
- package/dist/framework/effect.d.ts +128 -0
- package/dist/framework/effect.d.ts.map +1 -0
- package/dist/framework/effect.js +19 -0
- package/dist/framework/effect.js.map +1 -0
- package/dist/framework/frame-expr.d.ts +124 -0
- package/dist/framework/frame-expr.d.ts.map +1 -0
- package/dist/framework/frame-expr.js +135 -0
- package/dist/framework/frame-expr.js.map +1 -0
- package/dist/framework/load-effect.d.ts +77 -0
- package/dist/framework/load-effect.d.ts.map +1 -0
- package/dist/framework/load-effect.js +135 -0
- package/dist/framework/load-effect.js.map +1 -0
- package/dist/framework/loader.d.ts +309 -0
- package/dist/framework/loader.d.ts.map +1 -0
- package/dist/framework/loader.js +266 -0
- package/dist/framework/loader.js.map +1 -0
- package/dist/framework/mood-registry.d.ts +58 -0
- package/dist/framework/mood-registry.d.ts.map +1 -0
- package/dist/framework/mood-registry.js +58 -0
- package/dist/framework/mood-registry.js.map +1 -0
- package/dist/framework/panel-runner.d.ts +96 -0
- package/dist/framework/panel-runner.d.ts.map +1 -0
- package/dist/framework/panel-runner.js +137 -0
- package/dist/framework/panel-runner.js.map +1 -0
- package/dist/framework/pass-common.d.ts +97 -0
- package/dist/framework/pass-common.d.ts.map +1 -0
- package/dist/framework/pass-common.js +178 -0
- package/dist/framework/pass-common.js.map +1 -0
- package/dist/framework/pass-runner.d.ts +183 -0
- package/dist/framework/pass-runner.d.ts.map +1 -0
- package/dist/framework/pass-runner.js +212 -0
- package/dist/framework/pass-runner.js.map +1 -0
- package/dist/framework/programs.d.ts +54 -0
- package/dist/framework/programs.d.ts.map +1 -0
- package/dist/framework/programs.js +33 -0
- package/dist/framework/programs.js.map +1 -0
- package/dist/framework/registry.d.ts +29 -0
- package/dist/framework/registry.d.ts.map +1 -0
- package/dist/framework/registry.js +38 -0
- package/dist/framework/registry.js.map +1 -0
- package/dist/framework/runtime.d.ts +19 -0
- package/dist/framework/runtime.d.ts.map +1 -0
- package/dist/framework/runtime.js +37 -0
- package/dist/framework/runtime.js.map +1 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -0
- package/dist/overlay.d.ts +46 -0
- package/dist/overlay.d.ts.map +1 -0
- package/dist/overlay.js +79 -0
- package/dist/overlay.js.map +1 -0
- package/dist/types.d.ts +68 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/package.json +37 -0
- package/src/engine/color.ts +154 -0
- package/src/engine/context.ts +0 -0
- package/src/engine/gl.ts +46 -0
- package/src/engine/look/glsl.ts +183 -0
- package/src/engine/look/particles.glsl.ts +44 -0
- package/src/engine/sdf.ts +298 -0
- package/src/engine/seed.ts +23 -0
- package/src/engine/shadow.ts +66 -0
- package/src/engine/tempo.ts +54 -0
- package/src/framework/conductor.ts +604 -0
- package/src/framework/content.ts +113 -0
- package/src/framework/dope-pass.ts +432 -0
- package/src/framework/dope-zip.ts +125 -0
- package/src/framework/effect.ts +127 -0
- package/src/framework/frame-expr.ts +217 -0
- package/src/framework/load-effect.ts +204 -0
- package/src/framework/loader.ts +502 -0
- package/src/framework/mood-registry.ts +87 -0
- package/src/framework/panel-runner.ts +233 -0
- package/src/framework/pass-common.ts +222 -0
- package/src/framework/pass-runner.ts +391 -0
- package/src/framework/programs.ts +62 -0
- package/src/framework/registry.ts +44 -0
- package/src/framework/runtime.ts +38 -0
- package/src/index.ts +227 -0
- package/src/overlay.ts +109 -0
- package/src/types.ts +63 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `loadEffect()` — the public, no-code entry point for arbitrary `.dope` effects.
|
|
3
|
+
*
|
|
4
|
+
* A host drops in a `.dope` (a parsed object, a JSON string, or a `.dope` zip),
|
|
5
|
+
* optionally patches it (clamp control ranges, pin a brand palette, swap an
|
|
6
|
+
* outline path), and gets back a registered `EffectFactory` playable via
|
|
7
|
+
* `play()` / `prepare()`. The effect binds to a BUNDLED render program
|
|
8
|
+
* (framework/programs.ts) referenced by the doc's
|
|
9
|
+
* `render.backends.webgl2.shader.program` key — the format carries data + a
|
|
10
|
+
* program key; the runtime owns the GLSL. No new shader/renderer code is needed
|
|
11
|
+
* to ship a recolored / re-iconed / retimed variant of a bundled effect.
|
|
12
|
+
*
|
|
13
|
+
* Overrides are a shallow JSON-pointer-style patch applied to the parsed doc,
|
|
14
|
+
* then the merged doc is RE-VALIDATED (parseDope: magic/version + the
|
|
15
|
+
* standalone guard) so a host can't push the effect into an invalid or
|
|
16
|
+
* non-self-contained state. Swapped outline paths are re-baked to an SDF here so
|
|
17
|
+
* the runtime still only samples.
|
|
18
|
+
*/
|
|
19
|
+
import { type DopeDoc } from "./loader.js";
|
|
20
|
+
import type { OKLCH } from "../engine/color.js";
|
|
21
|
+
import type { EffectFactory } from "./effect.js";
|
|
22
|
+
/** Host customization patch — all no-code from the host's POV (docs §9.1). */
|
|
23
|
+
export interface LoadOverrides {
|
|
24
|
+
/**
|
|
25
|
+
* Clamp/retune a control's range or default, by control name. The loader
|
|
26
|
+
* re-validates that default ∈ [min, max] after merging.
|
|
27
|
+
* e.g. `{ intensity: { max: 0.8, default: 0.6 } }`.
|
|
28
|
+
*/
|
|
29
|
+
controls?: Record<string, {
|
|
30
|
+
min?: number;
|
|
31
|
+
max?: number;
|
|
32
|
+
default?: number | null;
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* THEME: replace the generated palette with three explicit OKLCH brand stops
|
|
36
|
+
* (the base-hue rng is still consumed, so per-fire scatter is unchanged), OR
|
|
37
|
+
* pin `seed` to lock the generated palette. `palette` wins over `seed`.
|
|
38
|
+
*/
|
|
39
|
+
palette?: [OKLCH, OKLCH, OKLCH];
|
|
40
|
+
/** THEME: pin the seed so the generated palette reproduces every fire. */
|
|
41
|
+
seed?: number;
|
|
42
|
+
/**
|
|
43
|
+
* RESKIN: swap an outline's SVG path by outline name; re-baked to an SDF here.
|
|
44
|
+
* e.g. `{ checkmark: "M5 55 L40 88 L95 8" }`.
|
|
45
|
+
*/
|
|
46
|
+
outlines?: Record<string, string>;
|
|
47
|
+
}
|
|
48
|
+
export interface LoadEffectOptions {
|
|
49
|
+
/** Register the effect under this name (default: the doc's `id`). */
|
|
50
|
+
name?: string;
|
|
51
|
+
/** Host customization patch (§9.1). */
|
|
52
|
+
overrides?: LoadOverrides;
|
|
53
|
+
/** SDF bake resolution for swapped outlines (default 64). */
|
|
54
|
+
sdfSize?: number;
|
|
55
|
+
/** SDF bake distance range in author units for swapped outlines (default 18). */
|
|
56
|
+
sdfRange?: number;
|
|
57
|
+
}
|
|
58
|
+
/** A loaded, registered effect ready to fire. */
|
|
59
|
+
export interface LoadedEffect {
|
|
60
|
+
/** The registered name (use with `play(name, …)`). */
|
|
61
|
+
readonly name: string;
|
|
62
|
+
/** The registered factory. */
|
|
63
|
+
readonly factory: EffectFactory;
|
|
64
|
+
/** The merged, validated `.dope` document. */
|
|
65
|
+
readonly doc: DopeDoc;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Parse + (optionally) patch a `.dope`, bind it to its bundled render program,
|
|
69
|
+
* register it, and return a playable factory. The merged doc is re-validated.
|
|
70
|
+
*/
|
|
71
|
+
export declare function loadEffectSync(src: string | object, opts?: LoadEffectOptions): LoadedEffect;
|
|
72
|
+
/**
|
|
73
|
+
* Public async `loadEffect`. Accepts a parsed doc, a JSON string, or a `.dope`
|
|
74
|
+
* zip (Uint8Array/ArrayBuffer/Blob). Resolves to the registered, playable effect.
|
|
75
|
+
*/
|
|
76
|
+
export declare function loadEffect(src: string | object | Uint8Array | ArrayBuffer | Blob, opts?: LoadEffectOptions): Promise<LoadedEffect>;
|
|
77
|
+
//# sourceMappingURL=load-effect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-effect.d.ts","sourceRoot":"","sources":["../../src/framework/load-effect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAa,KAAK,OAAO,EAAoB,MAAM,aAAa,CAAC;AACxE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAKhD,OAAO,KAAK,EAAiB,aAAa,EAAgB,MAAM,aAAa,CAAC;AAW9E,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IACnF;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAChC,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC3B,sDAAsD;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8BAA8B;IAC9B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,8CAA8C;IAC9C,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;CACvB;AA+CD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,GAAG,MAAM,EACpB,IAAI,GAAE,iBAAsB,GAC3B,YAAY,CAqDd;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,IAAI,EACtD,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,YAAY,CAAC,CASvB"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `loadEffect()` — the public, no-code entry point for arbitrary `.dope` effects.
|
|
3
|
+
*
|
|
4
|
+
* A host drops in a `.dope` (a parsed object, a JSON string, or a `.dope` zip),
|
|
5
|
+
* optionally patches it (clamp control ranges, pin a brand palette, swap an
|
|
6
|
+
* outline path), and gets back a registered `EffectFactory` playable via
|
|
7
|
+
* `play()` / `prepare()`. The effect binds to a BUNDLED render program
|
|
8
|
+
* (framework/programs.ts) referenced by the doc's
|
|
9
|
+
* `render.backends.webgl2.shader.program` key — the format carries data + a
|
|
10
|
+
* program key; the runtime owns the GLSL. No new shader/renderer code is needed
|
|
11
|
+
* to ship a recolored / re-iconed / retimed variant of a bundled effect.
|
|
12
|
+
*
|
|
13
|
+
* Overrides are a shallow JSON-pointer-style patch applied to the parsed doc,
|
|
14
|
+
* then the merged doc is RE-VALIDATED (parseDope: magic/version + the
|
|
15
|
+
* standalone guard) so a host can't push the effect into an invalid or
|
|
16
|
+
* non-self-contained state. Swapped outline paths are re-baked to an SDF here so
|
|
17
|
+
* the runtime still only samples.
|
|
18
|
+
*/
|
|
19
|
+
import { parseDope } from "./loader.js";
|
|
20
|
+
import { bakeSdf } from "../engine/sdf.js";
|
|
21
|
+
import { getProgram, programNames } from "./programs.js";
|
|
22
|
+
import { registerEffect } from "./registry.js";
|
|
23
|
+
import { resolveDopeParams } from "./loader.js";
|
|
24
|
+
const REMOTE_RE = /^(?:[a-z][a-z0-9+.-]*:)?\/\//i;
|
|
25
|
+
/** Apply control range/default overrides, validating default ∈ [min, max]. */
|
|
26
|
+
function applyControlOverrides(doc, overrides) {
|
|
27
|
+
const controls = doc.controls;
|
|
28
|
+
if (!controls)
|
|
29
|
+
throw new Error("dope: cannot override controls — doc has no `controls` block");
|
|
30
|
+
for (const [name, patch] of Object.entries(overrides)) {
|
|
31
|
+
const c = controls[name];
|
|
32
|
+
if (!c)
|
|
33
|
+
throw new Error(`dope: cannot override unknown control "${name}"`);
|
|
34
|
+
if (patch.min !== undefined)
|
|
35
|
+
c.min = patch.min;
|
|
36
|
+
if (patch.max !== undefined)
|
|
37
|
+
c.max = patch.max;
|
|
38
|
+
if (patch.default !== undefined)
|
|
39
|
+
c.default = patch.default;
|
|
40
|
+
const lo = typeof c.min === "number" ? c.min : -Infinity;
|
|
41
|
+
const hi = typeof c.max === "number" ? c.max : Infinity;
|
|
42
|
+
if (typeof c.min === "number" && typeof c.max === "number" && c.min > c.max) {
|
|
43
|
+
throw new Error(`dope: control "${name}" override has min > max`);
|
|
44
|
+
}
|
|
45
|
+
if (typeof c.default === "number" && (c.default < lo || c.default > hi)) {
|
|
46
|
+
throw new Error(`dope: control "${name}" default ${c.default} out of range [${lo}, ${hi}]`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Swap outline svgPaths and re-bake their SDFs (the runtime still only samples). */
|
|
51
|
+
function applyOutlineOverrides(doc, outlines, size, range) {
|
|
52
|
+
const geo = doc.geometry;
|
|
53
|
+
if (!geo?.outlines)
|
|
54
|
+
throw new Error("dope: cannot swap outline — doc has no `geometry.outlines`");
|
|
55
|
+
const viewBox = geo.viewBox ?? [0, 0, 100, 100];
|
|
56
|
+
for (const [name, svgPath] of Object.entries(outlines)) {
|
|
57
|
+
const o = geo.outlines[name];
|
|
58
|
+
if (!o)
|
|
59
|
+
throw new Error(`dope: cannot swap unknown outline "${name}"`);
|
|
60
|
+
if (REMOTE_RE.test(svgPath) || svgPath.trim().startsWith("/")) {
|
|
61
|
+
throw new Error(`dope: swapped outline path must be a self-contained svgPath, not a ref`);
|
|
62
|
+
}
|
|
63
|
+
o.svgPath = svgPath;
|
|
64
|
+
o.sdf = bakeSdf(svgPath, viewBox, size, range);
|
|
65
|
+
o.source = "baked-sdf";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Parse + (optionally) patch a `.dope`, bind it to its bundled render program,
|
|
70
|
+
* register it, and return a playable factory. The merged doc is re-validated.
|
|
71
|
+
*/
|
|
72
|
+
export function loadEffectSync(src, opts = {}) {
|
|
73
|
+
// Parse + validate the base doc first (rejects remote/absolute refs).
|
|
74
|
+
let doc = parseDope(src);
|
|
75
|
+
// Deep-clone so overrides never mutate a caller's object (and so re-bakes land
|
|
76
|
+
// on a private copy).
|
|
77
|
+
doc = JSON.parse(JSON.stringify(doc));
|
|
78
|
+
const ov = opts.overrides ?? {};
|
|
79
|
+
if (ov.controls)
|
|
80
|
+
applyControlOverrides(doc, ov.controls);
|
|
81
|
+
if (ov.outlines) {
|
|
82
|
+
applyOutlineOverrides(doc, ov.outlines, opts.sdfSize ?? 64, opts.sdfRange ?? 18);
|
|
83
|
+
}
|
|
84
|
+
// Re-validate the merged doc (magic/version + standalone guard). A swapped
|
|
85
|
+
// outline that smuggled a remote/absolute ref is rejected here.
|
|
86
|
+
doc = parseDope(doc);
|
|
87
|
+
// Resolve the bundled render program the doc references.
|
|
88
|
+
const backends = (doc.render.backends ?? {});
|
|
89
|
+
const programKey = backends.webgl2?.shader?.program;
|
|
90
|
+
if (!programKey) {
|
|
91
|
+
throw new Error("dope: render.backends.webgl2.shader.program is required for loadEffect");
|
|
92
|
+
}
|
|
93
|
+
const program = getProgram(programKey);
|
|
94
|
+
if (!program) {
|
|
95
|
+
throw new Error(`dope: unknown render program "${programKey}". Known: ${programNames().join(", ") || "import the effect that registers it"}`);
|
|
96
|
+
}
|
|
97
|
+
const name = opts.name ?? doc.id;
|
|
98
|
+
const seed = ov.seed;
|
|
99
|
+
const paletteOverride = ov.palette;
|
|
100
|
+
const factory = {
|
|
101
|
+
name,
|
|
102
|
+
castsShadow: program.castsShadow,
|
|
103
|
+
reducedMotion: program.reducedMotion,
|
|
104
|
+
resolve(feeling) {
|
|
105
|
+
// A pinned override seed wins over the per-fire seed (locks the palette).
|
|
106
|
+
const f = { ...feeling, seed: seed ?? feeling.seed };
|
|
107
|
+
const numeric = resolveDopeParams(doc, f, program.consts, program.scatterKey, paletteOverride);
|
|
108
|
+
return program.composeParams
|
|
109
|
+
? program.composeParams(numeric, f)
|
|
110
|
+
: numeric;
|
|
111
|
+
},
|
|
112
|
+
create(params, ctx) {
|
|
113
|
+
return program.create(params, ctx);
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
registerEffect(factory);
|
|
117
|
+
return { name, factory, doc };
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Public async `loadEffect`. Accepts a parsed doc, a JSON string, or a `.dope`
|
|
121
|
+
* zip (Uint8Array/ArrayBuffer/Blob). Resolves to the registered, playable effect.
|
|
122
|
+
*/
|
|
123
|
+
export async function loadEffect(src, opts = {}) {
|
|
124
|
+
if (src instanceof Blob)
|
|
125
|
+
src = new Uint8Array(await src.arrayBuffer());
|
|
126
|
+
if (src instanceof ArrayBuffer)
|
|
127
|
+
src = new Uint8Array(src);
|
|
128
|
+
if (src instanceof Uint8Array) {
|
|
129
|
+
const { readDopeZip } = await import("./dope-zip.js");
|
|
130
|
+
const json = await readDopeZip(src);
|
|
131
|
+
return loadEffectSync(json, opts);
|
|
132
|
+
}
|
|
133
|
+
return loadEffectSync(src, opts);
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=load-effect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-effect.js","sourceRoot":"","sources":["../../src/framework/load-effect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.dope` effect loader.
|
|
3
|
+
*
|
|
4
|
+
* Parses a `.dope` JSON document (per docs/effect-format.md) and evaluates its
|
|
5
|
+
* `controls → render.params` mapping grammar, the OKLCH golden-angle palette,
|
|
6
|
+
* and the per-mood baseline table into the SAME flat render-param bag the engine
|
|
7
|
+
* consumes. Shader bodies stay referenced GLSL (the format references them); the
|
|
8
|
+
* loader is NOT a GLSL transpiler.
|
|
9
|
+
*
|
|
10
|
+
* The single load-bearing invariant (the correctness anchor): the PRNG is
|
|
11
|
+
* consumed in the SAME order as the legacy `resolve*Params` — `buildPalette`
|
|
12
|
+
* draws the base hue first (one `rng()` inside it), then the per-fire scatter
|
|
13
|
+
* (`rng() * 1000`). So a pinned seed reproduces the legacy output byte-for-byte;
|
|
14
|
+
* a vitest asserts this across a mood × intensity × whimsy × seed grid.
|
|
15
|
+
*
|
|
16
|
+
* The grammar is intentionally tiny + non-Turing-complete (no loops, no user
|
|
17
|
+
* functions) so it is safe to evaluate from an untrusted file and trivial to
|
|
18
|
+
* port to Swift for the Metal backend.
|
|
19
|
+
*/
|
|
20
|
+
import { type OKLCH, type RGB } from "../engine/color.js";
|
|
21
|
+
import type { BakedSdf } from "../engine/sdf.js";
|
|
22
|
+
import type { FrameExprNode } from "./frame-expr.js";
|
|
23
|
+
/**
|
|
24
|
+
* The per-frame logic spec (`tempo.frame`): the datafied form of an effect's
|
|
25
|
+
* hand-written `frame()` hook. `amp` feeds shadowGeometry; `extras` are keyed by
|
|
26
|
+
* the CANONICAL extra name (matching `binding.extras[].name`) and map to each
|
|
27
|
+
* platform's uniform via the binding contract.
|
|
28
|
+
*/
|
|
29
|
+
export interface DopeFrameSpec {
|
|
30
|
+
amp: FrameExprNode;
|
|
31
|
+
extras?: Record<string, FrameExprNode>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The continuous-loop contract (`tempo.loop`): the effect repeats seamlessly
|
|
35
|
+
* with period `periodMs`. `parseDope` validates the two seam invariants that
|
|
36
|
+
* used to be per-effect convention: the period tiles the "animate on twos"
|
|
37
|
+
* grid (unless `snapAligned` is false) and every baseline `durationMs` is a
|
|
38
|
+
* whole number of periods — so the frame at `t == durationMs` matches `t == 0`
|
|
39
|
+
* at every whimsy. Runners surface the standard periodic clock uniforms
|
|
40
|
+
* `uLoopS` / `uPhase` (and the `loopS` / `phase` frame-expr inputs) from it,
|
|
41
|
+
* and conductors re-arm at `durationMs` instead of tearing down.
|
|
42
|
+
*/
|
|
43
|
+
export interface DopeLoopSpec {
|
|
44
|
+
/** The seamless loop period, ms. */
|
|
45
|
+
periodMs: number;
|
|
46
|
+
/**
|
|
47
|
+
* Whether `periodMs` must be a whole number of `NPR_TIME_STEP_MS` steps so
|
|
48
|
+
* the "animate on twos" snapped clock is also periodic. Default true.
|
|
49
|
+
*/
|
|
50
|
+
snapAligned?: boolean;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The cross-platform uniform-binding contract. SHIPS in the portable doc: the
|
|
54
|
+
* runtime derives which resolved params bind to which shader uniforms from it
|
|
55
|
+
* (and the toolchain consumes it for the Metal struct codegen).
|
|
56
|
+
*/
|
|
57
|
+
export interface DopeBinding {
|
|
58
|
+
note?: string;
|
|
59
|
+
/** `render.params` (or resolved-bag) names that are NOT shader uniforms. */
|
|
60
|
+
excludeParams?: string[];
|
|
61
|
+
/** The per-fire seed-keyed scatter field (auroraSeed / inkSeed / …). */
|
|
62
|
+
scatterKey?: string | null;
|
|
63
|
+
/** The web uniform the scatter binds to (absent = not a shader uniform). */
|
|
64
|
+
scatterWeb?: string;
|
|
65
|
+
/** Per-frame/host extras (filled by `tempo.frame.extras` or host hooks). */
|
|
66
|
+
extras?: Array<{
|
|
67
|
+
name: string;
|
|
68
|
+
type?: string;
|
|
69
|
+
web?: string;
|
|
70
|
+
note?: string;
|
|
71
|
+
}>;
|
|
72
|
+
/** Texture samplers the shader reads (see {@link DopeSampler}). */
|
|
73
|
+
samplers?: Array<string | DopeSampler>;
|
|
74
|
+
/** CPU-precomputed per-frame ARRAYS the shader reads (see {@link DopeFrameArray}). */
|
|
75
|
+
arrays?: DopeFrameArray[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* One per-frame ARRAY in the binding contract — the cross-platform transport
|
|
79
|
+
* for CPU-precomputed frame geometry (lightning's bolt polyline). The web and
|
|
80
|
+
* GL runtimes bind it by NAME as a `uniform vecN <web>[…]` array filled by the
|
|
81
|
+
* `frameArrays` seam; Metal binds it as a `constant floatN *` FRAGMENT BUFFER
|
|
82
|
+
* at index `buffer` (the toolchain's GLSL→MSL transpiler + the generated
|
|
83
|
+
* factory shells consume this entry).
|
|
84
|
+
*/
|
|
85
|
+
export interface DopeFrameArray {
|
|
86
|
+
/** The canonical name — the field of the logic module's returned bundle. */
|
|
87
|
+
name: string;
|
|
88
|
+
/** The web/GL uniform array name (e.g. `uVerts`). */
|
|
89
|
+
web: string;
|
|
90
|
+
/** Vector component count (2 | 3 | 4). */
|
|
91
|
+
size: number;
|
|
92
|
+
/** The Metal fragment buffer index (>= 1; 0 is the uniform struct). */
|
|
93
|
+
buffer?: number;
|
|
94
|
+
note?: string;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* One texture sampler in the binding contract. Beyond the binding names, a
|
|
98
|
+
* sampler may declare a DECLARATIVE SDF source: `outline` names a
|
|
99
|
+
* `geometry.outlines` entry whose baked SDF the runtime decodes + binds at
|
|
100
|
+
* texture unit `texture` (web; the native runtimes keep their analytic
|
|
101
|
+
* fallback), and `on` names the `binding.extras` flag the runner flips to 1
|
|
102
|
+
* when the texture is bound (left at 0 — the analytic path — when the SDF is
|
|
103
|
+
* absent or undecodable).
|
|
104
|
+
*/
|
|
105
|
+
export interface DopeSampler {
|
|
106
|
+
/** The web sampler uniform name (e.g. `uSdfTex`). */
|
|
107
|
+
web: string;
|
|
108
|
+
/** The canonical/MSL argument name (e.g. `sdfTex`). */
|
|
109
|
+
name?: string;
|
|
110
|
+
/** The texture unit it binds at (texture(0) is the panel slot). */
|
|
111
|
+
texture?: number;
|
|
112
|
+
/** A `geometry.outlines` key whose baked SDF backs this sampler. */
|
|
113
|
+
outline?: string;
|
|
114
|
+
/** The canonical `binding.extras` name of the sampler's "on" flag. */
|
|
115
|
+
on?: string;
|
|
116
|
+
note?: string;
|
|
117
|
+
}
|
|
118
|
+
/** A `.dope` document (the parts the loader consumes — others are ignored). */
|
|
119
|
+
export interface DopeDoc {
|
|
120
|
+
fmt: string;
|
|
121
|
+
v: string;
|
|
122
|
+
id: string;
|
|
123
|
+
meta?: {
|
|
124
|
+
name?: string;
|
|
125
|
+
description?: string;
|
|
126
|
+
tags?: string[];
|
|
127
|
+
};
|
|
128
|
+
palette: DopePalette;
|
|
129
|
+
tempo: {
|
|
130
|
+
durationMs?: DopeParamSpec;
|
|
131
|
+
/** Continuous-loop contract (seamless period); see {@link DopeLoopSpec}. */
|
|
132
|
+
loop?: DopeLoopSpec;
|
|
133
|
+
/** Per-frame logic (amp + extras) as frame-expression trees. */
|
|
134
|
+
frame?: DopeFrameSpec;
|
|
135
|
+
/** Reduced-motion peak/hold the factories used to hardcode. */
|
|
136
|
+
reducedMotion?: {
|
|
137
|
+
peakMs?: number;
|
|
138
|
+
holdMs?: number;
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
render: {
|
|
142
|
+
params: Record<string, DopeParamSpec>;
|
|
143
|
+
/** Shadow occluder height: a params-only frame expression (or a bare number). */
|
|
144
|
+
shadowHeightFrac?: FrameExprNode;
|
|
145
|
+
/**
|
|
146
|
+
* PER-PASS scalar uniforms, keyed by the CANONICAL extra name (matching
|
|
147
|
+
* `binding.extras[].name`): expressions over the resolved params + the
|
|
148
|
+
* pass-geometry inputs (`targetMinDimPx` / `sdfRange` / `sdfViewBoxW`),
|
|
149
|
+
* evaluated once per pass by `evalPassExpr` (frame clocks throw).
|
|
150
|
+
*/
|
|
151
|
+
pass?: Record<string, FrameExprNode>;
|
|
152
|
+
/** Loop-cap consts the param mapping's clampMax/clampMin reference. */
|
|
153
|
+
consts?: Record<string, number>;
|
|
154
|
+
/**
|
|
155
|
+
* The dynamic PANEL the host draws each frame and the shader samples
|
|
156
|
+
* (`sampler` must appear in `binding.samplers`; `texture` defaults to 0 —
|
|
157
|
+
* the cross-platform panel slot). The draw itself stays code (the
|
|
158
|
+
* per-platform panel-draw seam); only the wiring is data.
|
|
159
|
+
*/
|
|
160
|
+
panel?: {
|
|
161
|
+
sampler: string;
|
|
162
|
+
texture?: number;
|
|
163
|
+
note?: string;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Runner config: whether the shader reads `uOrigin`, and the clock
|
|
167
|
+
* stepping — `"none"` declares the effect's clock NEVER snaps "on twos"
|
|
168
|
+
* (the Canvas2D-panel runner semantics; panel geometry is hand-drawn, so
|
|
169
|
+
* snapping the clock would stutter it). Default: style-driven snapping.
|
|
170
|
+
*/
|
|
171
|
+
config?: {
|
|
172
|
+
usesOrigin?: boolean;
|
|
173
|
+
stepping?: "none";
|
|
174
|
+
};
|
|
175
|
+
backends?: unknown;
|
|
176
|
+
fallbackOrder?: string[];
|
|
177
|
+
};
|
|
178
|
+
/** The uniform-binding contract (see {@link DopeBinding}). */
|
|
179
|
+
binding?: DopeBinding;
|
|
180
|
+
/** Per-mood baseline table (color + non-color baselines), keyed by mood name. */
|
|
181
|
+
baselines: Record<string, Record<string, number>>;
|
|
182
|
+
/** Outline geometry — icon paths + (after the pack/bake step) baked SDFs. */
|
|
183
|
+
geometry?: DopeGeometry;
|
|
184
|
+
/** Free-form per-effect content (word sets, tokens) consumed by renderers. */
|
|
185
|
+
content?: Record<string, unknown>;
|
|
186
|
+
/** Typography tables (mood→face + whimsy/intensity curves) for letter effects. */
|
|
187
|
+
typography?: Record<string, unknown>;
|
|
188
|
+
}
|
|
189
|
+
/** An outline entry: an authored `svgPath` and/or its baked SDF + a role tag. */
|
|
190
|
+
export interface DopeOutline {
|
|
191
|
+
role?: string;
|
|
192
|
+
source?: string;
|
|
193
|
+
svgPath?: string;
|
|
194
|
+
/** Inline baked signed-distance field (a `data:` URI blob); see engine/sdf.ts. */
|
|
195
|
+
sdf?: BakedSdf;
|
|
196
|
+
note?: string;
|
|
197
|
+
}
|
|
198
|
+
export interface DopeGeometry {
|
|
199
|
+
kind?: string;
|
|
200
|
+
viewBox?: [number, number, number, number];
|
|
201
|
+
outlines?: Record<string, DopeOutline>;
|
|
202
|
+
}
|
|
203
|
+
/** Read a named outline from a doc's geometry, or undefined. */
|
|
204
|
+
export declare function getOutline(doc: DopeDoc, name: string): DopeOutline | undefined;
|
|
205
|
+
/**
|
|
206
|
+
* The mood a doc degrades to when asked for one it doesn't declare.
|
|
207
|
+
*
|
|
208
|
+
* Each effect declares its OWN moods (the success trio declares
|
|
209
|
+
* serene/celebratory/electric; the fail effect declares try-again/error/denied),
|
|
210
|
+
* so there is no single hardcoded fallback mood that exists for every effect.
|
|
211
|
+
* An effect's own default is, in order of preference:
|
|
212
|
+
* 1. its `controls.mood.default`, if that mood actually has a baseline, else
|
|
213
|
+
* 2. the first mood key in its `baselines` table.
|
|
214
|
+
* This keeps EVERY declared mood resolvable and makes an unknown mood degrade to
|
|
215
|
+
* the effect's own sensible default instead of throwing on a missing baseline.
|
|
216
|
+
*/
|
|
217
|
+
export declare function defaultMoodKey(doc: DopeDoc): string;
|
|
218
|
+
interface DopePalette {
|
|
219
|
+
hueSpread: number;
|
|
220
|
+
lightness: {
|
|
221
|
+
baseline: string;
|
|
222
|
+
perStop: [number, number, number];
|
|
223
|
+
};
|
|
224
|
+
chroma: {
|
|
225
|
+
from: ExprNode;
|
|
226
|
+
perStop: [number, number, number];
|
|
227
|
+
};
|
|
228
|
+
/** Color register fields per mood: hueCenter, hueRange, lightness, chroma. */
|
|
229
|
+
perMood: Record<string, {
|
|
230
|
+
hueCenter: number;
|
|
231
|
+
hueRange: number;
|
|
232
|
+
lightness: number;
|
|
233
|
+
chroma: number;
|
|
234
|
+
}>;
|
|
235
|
+
}
|
|
236
|
+
interface DopeParamSpec {
|
|
237
|
+
type?: "float" | "int";
|
|
238
|
+
from: ExprNode;
|
|
239
|
+
clamp01?: boolean;
|
|
240
|
+
clampMax?: string;
|
|
241
|
+
clampMin?: string;
|
|
242
|
+
}
|
|
243
|
+
/** The mapping mini-grammar (§4.1) — an expression tree. */
|
|
244
|
+
export type ExprNode = number | {
|
|
245
|
+
const: number;
|
|
246
|
+
} | {
|
|
247
|
+
control: string;
|
|
248
|
+
} | {
|
|
249
|
+
baseline: string;
|
|
250
|
+
} | {
|
|
251
|
+
lerp: [string, number, number];
|
|
252
|
+
} | {
|
|
253
|
+
mul: ExprNode[];
|
|
254
|
+
} | {
|
|
255
|
+
add: ExprNode[];
|
|
256
|
+
} | {
|
|
257
|
+
sub: ExprNode[];
|
|
258
|
+
} | {
|
|
259
|
+
round: ExprNode;
|
|
260
|
+
} | {
|
|
261
|
+
floor: ExprNode;
|
|
262
|
+
} | {
|
|
263
|
+
mix: [ExprNode, ExprNode, string];
|
|
264
|
+
} | {
|
|
265
|
+
max: ExprNode[];
|
|
266
|
+
} | {
|
|
267
|
+
min: ExprNode[];
|
|
268
|
+
};
|
|
269
|
+
/** Evaluation context for the grammar. */
|
|
270
|
+
export interface EvalCtx {
|
|
271
|
+
controls: Record<string, number>;
|
|
272
|
+
baseline: Record<string, number>;
|
|
273
|
+
consts: Record<string, number>;
|
|
274
|
+
}
|
|
275
|
+
/** Evaluate a grammar node to a number. Pure; matches mood.ts arithmetic. */
|
|
276
|
+
export declare function evalExpr(node: ExprNode, ctx: EvalCtx): number;
|
|
277
|
+
export interface DopeResolveInput {
|
|
278
|
+
mood: string;
|
|
279
|
+
intensity: number;
|
|
280
|
+
whimsy: number;
|
|
281
|
+
seed: number;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Resolve a `.dope` doc + a feeling into the flat render-param bag (palette,
|
|
285
|
+
* style, durationMs, seed, scatter seed, and every `render.params` entry). The
|
|
286
|
+
* `scatterKey` is the name the legacy code gave the per-fire scatter offset
|
|
287
|
+
* (`moteSeed` / `inkSeed` / `comicSeed`) so the output keys match exactly.
|
|
288
|
+
*
|
|
289
|
+
* RNG order (the parity anchor): baseHue via buildPalette FIRST, then the
|
|
290
|
+
* scatter `rng()*1000` — identical to `resolve*Params`.
|
|
291
|
+
*/
|
|
292
|
+
export declare function resolveDopeParams(doc: DopeDoc, input: DopeResolveInput, consts: Record<string, number>, scatterKey: string,
|
|
293
|
+
/**
|
|
294
|
+
* Host theme override: three explicit OKLCH stops that REPLACE the generated
|
|
295
|
+
* golden-angle palette (a pinned brand palette). The base-hue rng() is still
|
|
296
|
+
* consumed first, so the per-fire scatter offset stays identical to the
|
|
297
|
+
* generated path — pinning the palette never shifts the mote/spray layout.
|
|
298
|
+
*/
|
|
299
|
+
paletteOverride?: [OKLCH, OKLCH, OKLCH]): Record<string, number | RGB[] | number[]>;
|
|
300
|
+
/**
|
|
301
|
+
* Parse + validate a `.dope` document from a JSON string or already-parsed
|
|
302
|
+
* object. Rejects a wrong/absent magic or major version, any external
|
|
303
|
+
* (remote / absolute-path) asset reference — a `.dope` must be self-contained —
|
|
304
|
+
* and a `tempo.loop` that breaks the seam invariants.
|
|
305
|
+
* (A fuller JSON-Schema validation lives in CI against effect-format.schema.json.)
|
|
306
|
+
*/
|
|
307
|
+
export declare function parseDope(src: string | object): DopeDoc;
|
|
308
|
+
export {};
|
|
309
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/framework/loader.ts"],"names":[],"mappings":"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"}
|