@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,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal `.dope` zip (dotLottie-style) reader.
|
|
3
|
+
*
|
|
4
|
+
* A distributed `.dope` may be a zip: a `manifest.json` naming the effect doc
|
|
5
|
+
* plus an `assets/` dir referenced by RELATIVE paths only. This reads the zip
|
|
6
|
+
* entries (STORED or DEFLATE), finds the effect JSON via the manifest (or the
|
|
7
|
+
* first `*.json` under `effects/`), and resolves any relative asset `$ref`s in
|
|
8
|
+
* `geometry.outlines.*` by inlining them as `data:` URIs — so the doc handed to
|
|
9
|
+
* the loader is fully self-contained. Remote/absolute refs are rejected (the
|
|
10
|
+
* loader's standalone guard would reject them anyway; we fail early + clearly).
|
|
11
|
+
*
|
|
12
|
+
* Dependency-free: STORED entries are read directly; DEFLATE entries use the
|
|
13
|
+
* platform `DecompressionStream` when present (browsers + Node ≥18). We don't
|
|
14
|
+
* bundle a zlib.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Read a `.dope` zip → the fully-inlined effect document (a parsed object).
|
|
18
|
+
* Resolves the effect JSON via manifest.json, then inlines relative `$ref`/asset
|
|
19
|
+
* paths under geometry/outlines from the zip's `assets/`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function readDopeZip(buf: Uint8Array): Promise<object>;
|
|
22
|
+
//# sourceMappingURL=dope-zip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dope-zip.d.ts","sourceRoot":"","sources":["../../src/framework/dope-zip.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA2DH;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA8ClE"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal `.dope` zip (dotLottie-style) reader.
|
|
3
|
+
*
|
|
4
|
+
* A distributed `.dope` may be a zip: a `manifest.json` naming the effect doc
|
|
5
|
+
* plus an `assets/` dir referenced by RELATIVE paths only. This reads the zip
|
|
6
|
+
* entries (STORED or DEFLATE), finds the effect JSON via the manifest (or the
|
|
7
|
+
* first `*.json` under `effects/`), and resolves any relative asset `$ref`s in
|
|
8
|
+
* `geometry.outlines.*` by inlining them as `data:` URIs — so the doc handed to
|
|
9
|
+
* the loader is fully self-contained. Remote/absolute refs are rejected (the
|
|
10
|
+
* loader's standalone guard would reject them anyway; we fail early + clearly).
|
|
11
|
+
*
|
|
12
|
+
* Dependency-free: STORED entries are read directly; DEFLATE entries use the
|
|
13
|
+
* platform `DecompressionStream` when present (browsers + Node ≥18). We don't
|
|
14
|
+
* bundle a zlib.
|
|
15
|
+
*/
|
|
16
|
+
function u16(b, o) {
|
|
17
|
+
return b[o] | (b[o + 1] << 8);
|
|
18
|
+
}
|
|
19
|
+
function u32(b, o) {
|
|
20
|
+
return (b[o] | (b[o + 1] << 8) | (b[o + 2] << 16) | (b[o + 3] << 24)) >>> 0;
|
|
21
|
+
}
|
|
22
|
+
/** Parse the local-file-header records of a zip into raw entries. */
|
|
23
|
+
function parseZip(buf) {
|
|
24
|
+
const entries = [];
|
|
25
|
+
const dec = new TextDecoder();
|
|
26
|
+
let i = 0;
|
|
27
|
+
while (i + 4 <= buf.length) {
|
|
28
|
+
const sig = u32(buf, i);
|
|
29
|
+
if (sig !== 0x04034b50)
|
|
30
|
+
break; // local file header; central dir / EOCD follow
|
|
31
|
+
const method = u16(buf, i + 8);
|
|
32
|
+
const compSize = u32(buf, i + 18);
|
|
33
|
+
const nameLen = u16(buf, i + 26);
|
|
34
|
+
const extraLen = u16(buf, i + 28);
|
|
35
|
+
const nameStart = i + 30;
|
|
36
|
+
const name = dec.decode(buf.subarray(nameStart, nameStart + nameLen));
|
|
37
|
+
const dataStart = nameStart + nameLen + extraLen;
|
|
38
|
+
const data = buf.subarray(dataStart, dataStart + compSize);
|
|
39
|
+
entries.push({ name, method, data });
|
|
40
|
+
i = dataStart + compSize;
|
|
41
|
+
}
|
|
42
|
+
if (entries.length === 0)
|
|
43
|
+
throw new Error("dope: not a zip (no local file headers)");
|
|
44
|
+
return entries;
|
|
45
|
+
}
|
|
46
|
+
async function inflate(entry) {
|
|
47
|
+
if (entry.method === 0)
|
|
48
|
+
return entry.data.slice(); // STORED
|
|
49
|
+
if (entry.method === 8) {
|
|
50
|
+
// raw DEFLATE
|
|
51
|
+
if (typeof globalThis.DecompressionStream === "undefined") {
|
|
52
|
+
throw new Error("dope: DEFLATE zip entry but no DecompressionStream available");
|
|
53
|
+
}
|
|
54
|
+
const DS = globalThis
|
|
55
|
+
.DecompressionStream;
|
|
56
|
+
const ds = new DS("deflate-raw");
|
|
57
|
+
// Copy into a standalone ArrayBuffer-backed view for the Blob part.
|
|
58
|
+
const part = new Uint8Array(entry.data.length);
|
|
59
|
+
part.set(entry.data);
|
|
60
|
+
const stream = new Response(new Blob([part]).stream().pipeThrough(ds));
|
|
61
|
+
return new Uint8Array(await stream.arrayBuffer());
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`dope: unsupported zip compression method ${entry.method}`);
|
|
64
|
+
}
|
|
65
|
+
const ABS_OR_REMOTE = /^(?:[a-z][a-z0-9+.-]*:)?\/\/|^\//i;
|
|
66
|
+
/**
|
|
67
|
+
* Read a `.dope` zip → the fully-inlined effect document (a parsed object).
|
|
68
|
+
* Resolves the effect JSON via manifest.json, then inlines relative `$ref`/asset
|
|
69
|
+
* paths under geometry/outlines from the zip's `assets/`.
|
|
70
|
+
*/
|
|
71
|
+
export async function readDopeZip(buf) {
|
|
72
|
+
const entries = parseZip(buf);
|
|
73
|
+
const files = new Map();
|
|
74
|
+
for (const e of entries)
|
|
75
|
+
files.set(e.name.replace(/^\.?\//, ""), e);
|
|
76
|
+
const textOf = async (name) => {
|
|
77
|
+
const e = files.get(name);
|
|
78
|
+
if (!e)
|
|
79
|
+
throw new Error(`dope zip: missing entry "${name}"`);
|
|
80
|
+
return new TextDecoder().decode(await inflate(e));
|
|
81
|
+
};
|
|
82
|
+
// Locate the effect doc.
|
|
83
|
+
let effectPath;
|
|
84
|
+
if (files.has("manifest.json")) {
|
|
85
|
+
const manifest = JSON.parse(await textOf("manifest.json"));
|
|
86
|
+
effectPath = manifest.effects?.[0]?.path?.replace(/^\.?\//, "");
|
|
87
|
+
}
|
|
88
|
+
if (!effectPath) {
|
|
89
|
+
effectPath = [...files.keys()].find((n) => /^effects\/.+\.json$/.test(n)) ?? "effect.json";
|
|
90
|
+
}
|
|
91
|
+
const doc = JSON.parse(await textOf(effectPath));
|
|
92
|
+
// Inline relative asset refs in geometry.outlines.*.sdf when stored as a path.
|
|
93
|
+
const geo = doc.geometry;
|
|
94
|
+
if (geo?.outlines) {
|
|
95
|
+
for (const outline of Object.values(geo.outlines)) {
|
|
96
|
+
const sdf = outline.sdf;
|
|
97
|
+
const ref = (sdf?.data ?? outline.sdfRef);
|
|
98
|
+
if (typeof ref === "string" && !ref.startsWith("data:")) {
|
|
99
|
+
if (ABS_OR_REMOTE.test(ref)) {
|
|
100
|
+
throw new Error(`dope zip: outline asset must be a relative path, got "${ref}"`);
|
|
101
|
+
}
|
|
102
|
+
const e = files.get(ref.replace(/^\.?\//, ""));
|
|
103
|
+
if (!e)
|
|
104
|
+
throw new Error(`dope zip: missing asset "${ref}"`);
|
|
105
|
+
const bytes = await inflate(e);
|
|
106
|
+
const b64 = typeof Buffer !== "undefined"
|
|
107
|
+
? Buffer.from(bytes).toString("base64")
|
|
108
|
+
: btoa(String.fromCharCode(...bytes));
|
|
109
|
+
if (sdf)
|
|
110
|
+
sdf.data = `data:application/octet-stream;base64,${b64}`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return doc;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=dope-zip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dope-zip.js","sourceRoot":"","sources":["../../src/framework/dope-zip.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Dopamine effect framework — the backbone every visual effect plugs into.
|
|
3
|
+
*
|
|
4
|
+
* An *effect* (Solarbloom, Calligraphic Verdict, Comic Impact, and future
|
|
5
|
+
* progress / error / attention effects) is a self-contained module that knows
|
|
6
|
+
* two things:
|
|
7
|
+
*
|
|
8
|
+
* 1. how to turn the human-facing "feeling" knobs (mood / intensity / whimsy)
|
|
9
|
+
* plus a seed into its own concrete, deterministic render parameters, and
|
|
10
|
+
* 2. how to draw a single frame at an arbitrary `elapsedMs` into a shared GPU
|
|
11
|
+
* surface — both the light pass and (if present) the multiply shadow pass.
|
|
12
|
+
*
|
|
13
|
+
* Effects never create the DOM overlay, the GL context, or the RAF loop — the
|
|
14
|
+
* runtime (the conductor) owns all of that. That separation is what lets a new
|
|
15
|
+
* effect be a small file that self-registers, and keeps the library
|
|
16
|
+
* tree-shakeable: importing one effect pulls in nothing from the others.
|
|
17
|
+
*/
|
|
18
|
+
import type { GLContext } from "../engine/context.js";
|
|
19
|
+
import type { ResolvedMood } from "./mood-registry.js";
|
|
20
|
+
/** Origin/anchor in CSS pixels, relative to the render surface's top-left. */
|
|
21
|
+
export interface Anchor {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The "feeling" API, shared by every effect. Individual effects map these onto
|
|
27
|
+
* their own low-level parameters via {@link EffectFactory.resolve}. This is the
|
|
28
|
+
* deliberate seam between *what a developer expresses* (a feeling) and *what the
|
|
29
|
+
* shader consumes* (numbers).
|
|
30
|
+
*/
|
|
31
|
+
export interface FeelingInput {
|
|
32
|
+
/** Emotional register — a registered mood name. */
|
|
33
|
+
mood: string;
|
|
34
|
+
/** 0..1 — arousal/valence: saturation, brightness, scale, overshoot. */
|
|
35
|
+
intensity: number;
|
|
36
|
+
/** 0..1 — stylization: photoreal (0) ↔ cel / hand-drawn "animate on twos" (1). */
|
|
37
|
+
whimsy: number;
|
|
38
|
+
/** Deterministic seed for the algorithmic color + motion. */
|
|
39
|
+
seed: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Everything an effect instance needs to draw, supplied by the runtime. The
|
|
43
|
+
* effect draws its light pass into `light` and, when `shadow` is non-null, its
|
|
44
|
+
* occlusion silhouette into `shadow` (a separate `mix-blend-mode: multiply`
|
|
45
|
+
* canvas + context). Both contexts are persistent + program-cached.
|
|
46
|
+
*/
|
|
47
|
+
export interface EffectContext {
|
|
48
|
+
/** Shared WebGL2 light context (`screen` blend) + program cache. */
|
|
49
|
+
readonly light: GLContext;
|
|
50
|
+
/** Shared WebGL2 shadow context (`multiply` blend), or null if disabled. */
|
|
51
|
+
readonly shadow: GLContext | null;
|
|
52
|
+
/** Where the effect is anchored, in CSS px relative to the surface. */
|
|
53
|
+
readonly anchor: Anchor;
|
|
54
|
+
/**
|
|
55
|
+
* Size (CSS px) of the underlying element the effect targets, centred on
|
|
56
|
+
* {@link anchor}. The centrepiece (checkmark, ✗, comic word, hero heart, ink
|
|
57
|
+
* gesture) is sized to THIS box so it matches the page element. Omitted ⇒ the
|
|
58
|
+
* full render surface (the centrepiece fills the canvas, as before).
|
|
59
|
+
*/
|
|
60
|
+
readonly targetSize?: {
|
|
61
|
+
width: number;
|
|
62
|
+
height: number;
|
|
63
|
+
};
|
|
64
|
+
/** Device-pixel ratio to render at (already capped by the runtime). */
|
|
65
|
+
readonly dpr: number;
|
|
66
|
+
/**
|
|
67
|
+
* Present when the host composites against a known backdrop colour rather than
|
|
68
|
+
* the default `mix-blend-mode: screen`. The runners then emit PREMULTIPLIED
|
|
69
|
+
* light (alpha = brightness) on the light pass so the effect stays visible on
|
|
70
|
+
* any surface — white included — composited source-over. Absent ⇒ the classic
|
|
71
|
+
* screen/opaque path (byte-identical to before).
|
|
72
|
+
*/
|
|
73
|
+
readonly composite?: {
|
|
74
|
+
premultiplied: boolean;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** A live, drawable effect. Pure function of time: same `elapsedMs` → same frame. */
|
|
78
|
+
export interface EffectInstance {
|
|
79
|
+
/** Total length in ms after which the effect has fully played out. */
|
|
80
|
+
readonly durationMs: number;
|
|
81
|
+
/** Draw the frame at `elapsedMs` since the effect started. */
|
|
82
|
+
renderAt(elapsedMs: number): void;
|
|
83
|
+
/** Release any per-instance GPU resources (not shared/cached ones). */
|
|
84
|
+
dispose(): void;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The contract a new effect implements. `Params` is the effect's private,
|
|
88
|
+
* fully-resolved parameter shape — opaque to the runtime.
|
|
89
|
+
*/
|
|
90
|
+
export interface EffectFactory<Params = unknown> {
|
|
91
|
+
/** Stable, unique id, e.g. `"solarbloom"`. Used by the registry + API. */
|
|
92
|
+
readonly name: string;
|
|
93
|
+
/**
|
|
94
|
+
* Map the shared feeling knobs + a resolved mood into this effect's own
|
|
95
|
+
* deterministic params. Pure — no DOM, no GL, no randomness beyond the seed.
|
|
96
|
+
*/
|
|
97
|
+
resolve(feeling: FeelingInput, mood: ResolvedMood): Params;
|
|
98
|
+
/** Build a drawable instance for the given resolved params + context. */
|
|
99
|
+
create(params: Params, ctx: EffectContext): EffectInstance;
|
|
100
|
+
/**
|
|
101
|
+
* Whether this effect wants a shadow (multiply) companion canvas. Defaults to
|
|
102
|
+
* true; an effect that casts no shadow can opt out to skip the second context.
|
|
103
|
+
*/
|
|
104
|
+
readonly castsShadow?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Optional reduced-motion handling: which `elapsedMs` of the timeline best
|
|
107
|
+
* represents a calm peak, and how long to hold that single static frame
|
|
108
|
+
* instead of animating. Sensible defaults are used if omitted.
|
|
109
|
+
*/
|
|
110
|
+
readonly reducedMotion?: {
|
|
111
|
+
/** How long to hold the minimal frame, ms. Default 360. */
|
|
112
|
+
holdMs?: number;
|
|
113
|
+
/** Which `elapsedMs` of the full timeline best represents a calm peak. */
|
|
114
|
+
peakMs?: number;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* CONTINUOUS-loop contract (from `tempo.loop`): the effect repeats seamlessly
|
|
118
|
+
* with this period and `durationMs` is a whole number of periods. The
|
|
119
|
+
* conductor re-arms it at `durationMs` instead of tearing down — the host
|
|
120
|
+
* stops it via the handle `play()` returns. Absent for one-shot effects.
|
|
121
|
+
*/
|
|
122
|
+
readonly loop?: {
|
|
123
|
+
periodMs: number;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** Public alias: an `Effect` is what you register and play by name. */
|
|
127
|
+
export type Effect<Params = unknown> = EffectFactory<Params>;
|
|
128
|
+
//# sourceMappingURL=effect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../../src/framework/effect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,8EAA8E;AAC9E,MAAM,WAAW,MAAM;IACrB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IAClC,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,uEAAuE;IACvE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,aAAa,EAAE,OAAO,CAAA;KAAE,CAAC;CACjD;AAED,qFAAqF;AACrF,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,uEAAuE;IACvE,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,MAAM,GAAG,OAAO;IAC7C,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC;IAC3D,yEAAyE;IACzE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,cAAc,CAAC;IAC3D;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE;QACvB,2DAA2D;QAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,0EAA0E;QAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACtC;AAED,uEAAuE;AACvE,MAAM,MAAM,MAAM,CAAC,MAAM,GAAG,OAAO,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Dopamine effect framework — the backbone every visual effect plugs into.
|
|
3
|
+
*
|
|
4
|
+
* An *effect* (Solarbloom, Calligraphic Verdict, Comic Impact, and future
|
|
5
|
+
* progress / error / attention effects) is a self-contained module that knows
|
|
6
|
+
* two things:
|
|
7
|
+
*
|
|
8
|
+
* 1. how to turn the human-facing "feeling" knobs (mood / intensity / whimsy)
|
|
9
|
+
* plus a seed into its own concrete, deterministic render parameters, and
|
|
10
|
+
* 2. how to draw a single frame at an arbitrary `elapsedMs` into a shared GPU
|
|
11
|
+
* surface — both the light pass and (if present) the multiply shadow pass.
|
|
12
|
+
*
|
|
13
|
+
* Effects never create the DOM overlay, the GL context, or the RAF loop — the
|
|
14
|
+
* runtime (the conductor) owns all of that. That separation is what lets a new
|
|
15
|
+
* effect be a small file that self-registers, and keeps the library
|
|
16
|
+
* tree-shakeable: importing one effect pulls in nothing from the others.
|
|
17
|
+
*/
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=effect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect.js","sourceRoot":"","sources":["../../src/framework/effect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-FRAME expression evaluator — the datafied form of an effect's `frame()` /
|
|
3
|
+
* `shadowHeightFrac` logic hooks.
|
|
4
|
+
*
|
|
5
|
+
* The resolve-time grammar (`loader.ts` `evalExpr`) maps a feeling into the
|
|
6
|
+
* resolved param bag ONCE per fire. This module is its per-frame sibling: it
|
|
7
|
+
* evaluates the `.dope` `tempo.frame` / `render.shadowHeightFrac` expression
|
|
8
|
+
* trees EVERY frame against the live clocks (`animMs` / `life` / `elapsedMs`,
|
|
9
|
+
* plus the `loopS` / `phase` loop clocks for effects with `tempo.loop`) and
|
|
10
|
+
* the resolved params — so the per-frame logic, like the resolve mapping,
|
|
11
|
+
* is authored once in the `.dope` and interpreted identically on every
|
|
12
|
+
* platform. The same grammar also powers the PER-PASS `render.pass`
|
|
13
|
+
* expressions ({@link evalPassExpr}): params plus the pass-geometry inputs
|
|
14
|
+
* (`targetMinDimPx` / `sdfRange` / `sdfViewBoxW`), with the frame clocks
|
|
15
|
+
* rejected — pass values are computed once per pass, not per frame.
|
|
16
|
+
*
|
|
17
|
+
* Like `evalExpr`, nodes are evaluated RAW (no decode step) and anything
|
|
18
|
+
* outside the grammar THROWS. The tempo primitives (`envelope`, `easeOutBack`,
|
|
19
|
+
* `easeOutCubic`, `clamp01`) are the SAME functions the hand-written hooks
|
|
20
|
+
* called (imported from `engine/tempo.ts`), so a datafied effect's output is
|
|
21
|
+
* bit-identical to the code it replaced.
|
|
22
|
+
*/
|
|
23
|
+
/** The per-frame expression grammar — an expression tree over the frame ctx. */
|
|
24
|
+
export type FrameExprNode = number | {
|
|
25
|
+
const: number;
|
|
26
|
+
} | {
|
|
27
|
+
param: string;
|
|
28
|
+
} | {
|
|
29
|
+
input: "animMs" | "life" | "elapsedMs" | "loopS" | "phase" | "targetMinDimPx" | "sdfRange" | "sdfViewBoxW" | "dpr";
|
|
30
|
+
} | {
|
|
31
|
+
add: FrameExprNode[];
|
|
32
|
+
} | {
|
|
33
|
+
sub: FrameExprNode[];
|
|
34
|
+
} | {
|
|
35
|
+
mul: FrameExprNode[];
|
|
36
|
+
} | {
|
|
37
|
+
div: FrameExprNode[];
|
|
38
|
+
} | {
|
|
39
|
+
min: FrameExprNode[];
|
|
40
|
+
} | {
|
|
41
|
+
max: FrameExprNode[];
|
|
42
|
+
} | {
|
|
43
|
+
pow: [FrameExprNode, FrameExprNode];
|
|
44
|
+
} | {
|
|
45
|
+
sin: FrameExprNode;
|
|
46
|
+
} | {
|
|
47
|
+
cos: FrameExprNode;
|
|
48
|
+
} | {
|
|
49
|
+
exp: FrameExprNode;
|
|
50
|
+
} | {
|
|
51
|
+
clamp01: FrameExprNode;
|
|
52
|
+
} | {
|
|
53
|
+
lt: [FrameExprNode, FrameExprNode, FrameExprNode, FrameExprNode];
|
|
54
|
+
} | {
|
|
55
|
+
envelope: [FrameExprNode, FrameExprNode];
|
|
56
|
+
} | {
|
|
57
|
+
easeOutCubic: FrameExprNode;
|
|
58
|
+
} | {
|
|
59
|
+
easeOutBack: [FrameExprNode, FrameExprNode];
|
|
60
|
+
};
|
|
61
|
+
/** Evaluation context for a per-frame expression. */
|
|
62
|
+
export interface FrameExprCtx {
|
|
63
|
+
/** The "on twos"-snapped animation clock in ms (stepping already applied). */
|
|
64
|
+
animMs: number;
|
|
65
|
+
/** Normalized life 0..1 (animMs / durationMs, clamped). */
|
|
66
|
+
life: number;
|
|
67
|
+
/** The REAL un-stepped wall clock in ms (mirrors the Swift/Android runners). */
|
|
68
|
+
elapsedMs: number;
|
|
69
|
+
/** The resolved render-param bag (numeric entries are addressable). */
|
|
70
|
+
params: Record<string, unknown>;
|
|
71
|
+
/**
|
|
72
|
+
* Seconds within the current loop (`(animMs % tempo.loop.periodMs) / 1000`).
|
|
73
|
+
* 0 for an effect with no `tempo.loop` — the caller (the dope-pass frame
|
|
74
|
+
* derivation) fills these from the doc's loop contract.
|
|
75
|
+
*/
|
|
76
|
+
loopS?: number;
|
|
77
|
+
/** Normalized loop phase in [0, 1) (`animMs % periodMs / periodMs`); 0 without a loop. */
|
|
78
|
+
phase?: number;
|
|
79
|
+
/** Pass-geometry inputs (see {@link PassExprInputs}); only read in "pass" mode. */
|
|
80
|
+
pass?: PassExprInputs;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The pass-geometry inputs a `render.pass` expression may read (evaluated ONCE
|
|
84
|
+
* per pass by the runners, never per resolve or per frame).
|
|
85
|
+
*/
|
|
86
|
+
export interface PassExprInputs {
|
|
87
|
+
/**
|
|
88
|
+
* Min dimension of the TARGETED element box in device px, falling back to
|
|
89
|
+
* the full canvas when untargeted — the same target-fallback the standard
|
|
90
|
+
* `uTarget` uniform uses, so a pass-sized centrepiece tracks the element.
|
|
91
|
+
*/
|
|
92
|
+
targetMinDimPx: number;
|
|
93
|
+
/**
|
|
94
|
+
* The declared `range` of the SDF behind the first `binding.samplers` entry
|
|
95
|
+
* with an `outline` source (author units → the full byte range); 0 when no
|
|
96
|
+
* sampler declares one.
|
|
97
|
+
*/
|
|
98
|
+
sdfRange: number;
|
|
99
|
+
/** That SDF's `viewBox[2]` (author-units width); 0 when absent. */
|
|
100
|
+
sdfViewBoxW: number;
|
|
101
|
+
/**
|
|
102
|
+
* The device-pixel ratio (web `devicePixelRatio` / Android `density` / the
|
|
103
|
+
* Metal layer's content scale) the surface renders at — so a pass value can
|
|
104
|
+
* be expressed in CSS-ish units and scaled to device px (e.g. heartburst's
|
|
105
|
+
* halftone cell `uDotSize = dotSize · dpr`).
|
|
106
|
+
*/
|
|
107
|
+
dpr: number;
|
|
108
|
+
}
|
|
109
|
+
/** Evaluate a per-frame grammar node to a number. Pure; throws outside the grammar. */
|
|
110
|
+
export declare function evalFrameExpr(node: FrameExprNode, ctx: FrameExprCtx): number;
|
|
111
|
+
/**
|
|
112
|
+
* Evaluate a PARAMS-ONLY expression (e.g. `render.shadowHeightFrac`): the same
|
|
113
|
+
* grammar, but `{input}` nodes THROW — a shadow-geometry expression must be a
|
|
114
|
+
* pure function of the resolved params, never of the frame clock.
|
|
115
|
+
*/
|
|
116
|
+
export declare function evalParamExpr(node: FrameExprNode, params: Record<string, unknown>): number;
|
|
117
|
+
/**
|
|
118
|
+
* Evaluate a PER-PASS expression (`render.pass`): the same grammar over the
|
|
119
|
+
* resolved params plus the pass-geometry inputs (`targetMinDimPx` / `sdfRange`
|
|
120
|
+
* / `sdfViewBoxW`). Frame clocks (`animMs` / `life` / …) THROW — a pass
|
|
121
|
+
* expression is evaluated once per pass, not per frame.
|
|
122
|
+
*/
|
|
123
|
+
export declare function evalPassExpr(node: FrameExprNode, params: Record<string, unknown>, pass: PassExprInputs): number;
|
|
124
|
+
//# sourceMappingURL=frame-expr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-expr.d.ts","sourceRoot":"","sources":["../../src/framework/frame-expr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,gFAAgF;AAChF,MAAM,MAAM,aAAa,GACrB,MAAM,GACN;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB;IACE,KAAK,EACD,QAAQ,GACR,MAAM,GACN,WAAW,GACX,OAAO,GACP,OAAO,GAGP,gBAAgB,GAChB,UAAU,GACV,aAAa,GACb,KAAK,CAAC;CACX,GACD;IAAE,GAAG,EAAE,aAAa,EAAE,CAAA;CAAE,GACxB;IAAE,GAAG,EAAE,aAAa,EAAE,CAAA;CAAE,GACxB;IAAE,GAAG,EAAE,aAAa,EAAE,CAAA;CAAE,GACxB;IAAE,GAAG,EAAE,aAAa,EAAE,CAAA;CAAE,GACxB;IAAE,GAAG,EAAE,aAAa,EAAE,CAAA;CAAE,GACxB;IAAE,GAAG,EAAE,aAAa,EAAE,CAAA;CAAE,GACxB;IAAE,GAAG,EAAE,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;CAAE,GACvC;IAAE,GAAG,EAAE,aAAa,CAAA;CAAE,GACtB;IAAE,GAAG,EAAE,aAAa,CAAA;CAAE,GACtB;IAAE,GAAG,EAAE,aAAa,CAAA;CAAE,GACtB;IAAE,OAAO,EAAE,aAAa,CAAA;CAAE,GAC1B;IAAE,EAAE,EAAE,CAAC,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,CAAC,CAAA;CAAE,GACpE;IAAE,QAAQ,EAAE,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;CAAE,GAC5C;IAAE,YAAY,EAAE,aAAa,CAAA;CAAE,GAC/B;IAAE,WAAW,EAAE,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;CAAE,CAAC;AAEpD,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,GAAG,EAAE,MAAM,CAAC;CACb;AAkFD,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,YAAY,GAAG,MAAM,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAE1F;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,EAAE,cAAc,GACnB,MAAM,CAER"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-FRAME expression evaluator — the datafied form of an effect's `frame()` /
|
|
3
|
+
* `shadowHeightFrac` logic hooks.
|
|
4
|
+
*
|
|
5
|
+
* The resolve-time grammar (`loader.ts` `evalExpr`) maps a feeling into the
|
|
6
|
+
* resolved param bag ONCE per fire. This module is its per-frame sibling: it
|
|
7
|
+
* evaluates the `.dope` `tempo.frame` / `render.shadowHeightFrac` expression
|
|
8
|
+
* trees EVERY frame against the live clocks (`animMs` / `life` / `elapsedMs`,
|
|
9
|
+
* plus the `loopS` / `phase` loop clocks for effects with `tempo.loop`) and
|
|
10
|
+
* the resolved params — so the per-frame logic, like the resolve mapping,
|
|
11
|
+
* is authored once in the `.dope` and interpreted identically on every
|
|
12
|
+
* platform. The same grammar also powers the PER-PASS `render.pass`
|
|
13
|
+
* expressions ({@link evalPassExpr}): params plus the pass-geometry inputs
|
|
14
|
+
* (`targetMinDimPx` / `sdfRange` / `sdfViewBoxW`), with the frame clocks
|
|
15
|
+
* rejected — pass values are computed once per pass, not per frame.
|
|
16
|
+
*
|
|
17
|
+
* Like `evalExpr`, nodes are evaluated RAW (no decode step) and anything
|
|
18
|
+
* outside the grammar THROWS. The tempo primitives (`envelope`, `easeOutBack`,
|
|
19
|
+
* `easeOutCubic`, `clamp01`) are the SAME functions the hand-written hooks
|
|
20
|
+
* called (imported from `engine/tempo.ts`), so a datafied effect's output is
|
|
21
|
+
* bit-identical to the code it replaced.
|
|
22
|
+
*/
|
|
23
|
+
import { clamp01, easeOutBack, easeOutCubic, envelope } from "../engine/tempo.js";
|
|
24
|
+
const FRAME_INPUTS = ["animMs", "life", "elapsedMs", "loopS", "phase"];
|
|
25
|
+
const PASS_INPUTS = ["targetMinDimPx", "sdfRange", "sdfViewBoxW", "dpr"];
|
|
26
|
+
function evalInput(name, ctx, mode) {
|
|
27
|
+
const isFrame = FRAME_INPUTS.includes(name);
|
|
28
|
+
const isPass = PASS_INPUTS.includes(name);
|
|
29
|
+
if (mode === "pass") {
|
|
30
|
+
if (isFrame) {
|
|
31
|
+
throw new Error(`dope: frame input "${name}" is not allowed in a render.pass expression (pass expressions are not frame-clocked)`);
|
|
32
|
+
}
|
|
33
|
+
if (isPass)
|
|
34
|
+
return ctx.pass?.[name] ?? 0;
|
|
35
|
+
throw new Error(`dope: unknown frame input "${name}"`);
|
|
36
|
+
}
|
|
37
|
+
if (isPass) {
|
|
38
|
+
throw new Error(`dope: pass input "${name}" is only allowed in a render.pass expression`);
|
|
39
|
+
}
|
|
40
|
+
if (mode === "params") {
|
|
41
|
+
throw new Error(`dope: {input} is not allowed in a params-only expression (got "${name}")`);
|
|
42
|
+
}
|
|
43
|
+
if (name === "animMs")
|
|
44
|
+
return ctx.animMs;
|
|
45
|
+
if (name === "life")
|
|
46
|
+
return ctx.life;
|
|
47
|
+
if (name === "elapsedMs")
|
|
48
|
+
return ctx.elapsedMs;
|
|
49
|
+
if (name === "loopS")
|
|
50
|
+
return ctx.loopS ?? 0;
|
|
51
|
+
if (name === "phase")
|
|
52
|
+
return ctx.phase ?? 0;
|
|
53
|
+
throw new Error(`dope: unknown frame input "${name}"`);
|
|
54
|
+
}
|
|
55
|
+
function evalNode(node, ctx, mode) {
|
|
56
|
+
if (typeof node === "number")
|
|
57
|
+
return node;
|
|
58
|
+
if ("const" in node)
|
|
59
|
+
return node.const;
|
|
60
|
+
if ("param" in node) {
|
|
61
|
+
const raw = ctx.params[node.param];
|
|
62
|
+
if (typeof raw !== "number") {
|
|
63
|
+
throw new Error(`dope: frame expr references missing/non-numeric param "${node.param}"`);
|
|
64
|
+
}
|
|
65
|
+
return Number(raw);
|
|
66
|
+
}
|
|
67
|
+
if ("input" in node)
|
|
68
|
+
return evalInput(String(node.input), ctx, mode);
|
|
69
|
+
if ("add" in node)
|
|
70
|
+
return node.add.reduce((p, n) => p + evalNode(n, ctx, mode), 0);
|
|
71
|
+
if ("sub" in node) {
|
|
72
|
+
const parts = node.sub.map((n) => evalNode(n, ctx, mode));
|
|
73
|
+
return parts.slice(1).reduce((p, n) => p - n, parts[0] ?? 0);
|
|
74
|
+
}
|
|
75
|
+
if ("mul" in node)
|
|
76
|
+
return node.mul.reduce((p, n) => p * evalNode(n, ctx, mode), 1);
|
|
77
|
+
if ("div" in node) {
|
|
78
|
+
const parts = node.div.map((n) => evalNode(n, ctx, mode));
|
|
79
|
+
return parts.slice(1).reduce((p, n) => p / n, parts[0] ?? 0);
|
|
80
|
+
}
|
|
81
|
+
if ("min" in node)
|
|
82
|
+
return Math.min(...node.min.map((n) => evalNode(n, ctx, mode)));
|
|
83
|
+
if ("max" in node)
|
|
84
|
+
return Math.max(...node.max.map((n) => evalNode(n, ctx, mode)));
|
|
85
|
+
if ("pow" in node) {
|
|
86
|
+
return Math.pow(evalNode(node.pow[0], ctx, mode), evalNode(node.pow[1], ctx, mode));
|
|
87
|
+
}
|
|
88
|
+
if ("sin" in node)
|
|
89
|
+
return Math.sin(evalNode(node.sin, ctx, mode));
|
|
90
|
+
if ("cos" in node)
|
|
91
|
+
return Math.cos(evalNode(node.cos, ctx, mode));
|
|
92
|
+
if ("exp" in node)
|
|
93
|
+
return Math.exp(evalNode(node.exp, ctx, mode));
|
|
94
|
+
if ("clamp01" in node)
|
|
95
|
+
return clamp01(evalNode(node.clamp01, ctx, mode));
|
|
96
|
+
if ("lt" in node) {
|
|
97
|
+
// Branches are evaluated LAZILY (only the taken branch), so a guard like
|
|
98
|
+
// `0 < elapsedMs ? f(elapsedMs) : 0` never evaluates f outside its domain.
|
|
99
|
+
const [a, b, then, otherwise] = node.lt;
|
|
100
|
+
return evalNode(a, ctx, mode) < evalNode(b, ctx, mode)
|
|
101
|
+
? evalNode(then, ctx, mode)
|
|
102
|
+
: evalNode(otherwise, ctx, mode);
|
|
103
|
+
}
|
|
104
|
+
if ("envelope" in node) {
|
|
105
|
+
return envelope(evalNode(node.envelope[0], ctx, mode), evalNode(node.envelope[1], ctx, mode));
|
|
106
|
+
}
|
|
107
|
+
if ("easeOutCubic" in node)
|
|
108
|
+
return easeOutCubic(evalNode(node.easeOutCubic, ctx, mode));
|
|
109
|
+
if ("easeOutBack" in node) {
|
|
110
|
+
return easeOutBack(evalNode(node.easeOutBack[0], ctx, mode), evalNode(node.easeOutBack[1], ctx, mode));
|
|
111
|
+
}
|
|
112
|
+
throw new Error(`dope: unknown frame expr node ${JSON.stringify(node)}`);
|
|
113
|
+
}
|
|
114
|
+
/** Evaluate a per-frame grammar node to a number. Pure; throws outside the grammar. */
|
|
115
|
+
export function evalFrameExpr(node, ctx) {
|
|
116
|
+
return evalNode(node, ctx, "frame");
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Evaluate a PARAMS-ONLY expression (e.g. `render.shadowHeightFrac`): the same
|
|
120
|
+
* grammar, but `{input}` nodes THROW — a shadow-geometry expression must be a
|
|
121
|
+
* pure function of the resolved params, never of the frame clock.
|
|
122
|
+
*/
|
|
123
|
+
export function evalParamExpr(node, params) {
|
|
124
|
+
return evalNode(node, { animMs: 0, life: 0, elapsedMs: 0, params }, "params");
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Evaluate a PER-PASS expression (`render.pass`): the same grammar over the
|
|
128
|
+
* resolved params plus the pass-geometry inputs (`targetMinDimPx` / `sdfRange`
|
|
129
|
+
* / `sdfViewBoxW`). Frame clocks (`animMs` / `life` / …) THROW — a pass
|
|
130
|
+
* expression is evaluated once per pass, not per frame.
|
|
131
|
+
*/
|
|
132
|
+
export function evalPassExpr(node, params, pass) {
|
|
133
|
+
return evalNode(node, { animMs: 0, life: 0, elapsedMs: 0, params, pass }, "pass");
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=frame-expr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-expr.js","sourceRoot":"","sources":["../../src/framework/frame-expr.ts"],"names":[],"mappings":"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"}
|