@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.
Files changed (136) hide show
  1. package/dist/engine/color.d.ts +71 -0
  2. package/dist/engine/color.d.ts.map +1 -0
  3. package/dist/engine/color.js +107 -0
  4. package/dist/engine/color.js.map +1 -0
  5. package/dist/engine/context.d.ts +54 -0
  6. package/dist/engine/context.d.ts.map +1 -0
  7. package/dist/engine/context.js +0 -0
  8. package/dist/engine/context.js.map +1 -0
  9. package/dist/engine/gl.d.ts +9 -0
  10. package/dist/engine/gl.d.ts.map +1 -0
  11. package/dist/engine/gl.js +39 -0
  12. package/dist/engine/gl.js.map +1 -0
  13. package/dist/engine/look/glsl.d.ts +95 -0
  14. package/dist/engine/look/glsl.d.ts.map +1 -0
  15. package/dist/engine/look/glsl.js +171 -0
  16. package/dist/engine/look/glsl.js.map +1 -0
  17. package/dist/engine/look/particles.glsl.d.ts +21 -0
  18. package/dist/engine/look/particles.glsl.d.ts.map +1 -0
  19. package/dist/engine/look/particles.glsl.js +44 -0
  20. package/dist/engine/look/particles.glsl.js.map +1 -0
  21. package/dist/engine/sdf.d.ts +77 -0
  22. package/dist/engine/sdf.d.ts.map +1 -0
  23. package/dist/engine/sdf.js +255 -0
  24. package/dist/engine/sdf.js.map +1 -0
  25. package/dist/engine/seed.d.ts +10 -0
  26. package/dist/engine/seed.d.ts.map +1 -0
  27. package/dist/engine/seed.js +20 -0
  28. package/dist/engine/seed.js.map +1 -0
  29. package/dist/engine/shadow.d.ts +41 -0
  30. package/dist/engine/shadow.d.ts.map +1 -0
  31. package/dist/engine/shadow.js +39 -0
  32. package/dist/engine/shadow.js.map +1 -0
  33. package/dist/engine/tempo.d.ts +33 -0
  34. package/dist/engine/tempo.d.ts.map +1 -0
  35. package/dist/engine/tempo.js +51 -0
  36. package/dist/engine/tempo.js.map +1 -0
  37. package/dist/framework/conductor.d.ts +100 -0
  38. package/dist/framework/conductor.d.ts.map +1 -0
  39. package/dist/framework/conductor.js +493 -0
  40. package/dist/framework/conductor.js.map +1 -0
  41. package/dist/framework/content.d.ts +67 -0
  42. package/dist/framework/content.d.ts.map +1 -0
  43. package/dist/framework/content.js +72 -0
  44. package/dist/framework/content.js.map +1 -0
  45. package/dist/framework/dope-pass.d.ts +131 -0
  46. package/dist/framework/dope-pass.d.ts.map +1 -0
  47. package/dist/framework/dope-pass.js +346 -0
  48. package/dist/framework/dope-pass.js.map +1 -0
  49. package/dist/framework/dope-zip.d.ts +22 -0
  50. package/dist/framework/dope-zip.d.ts.map +1 -0
  51. package/dist/framework/dope-zip.js +116 -0
  52. package/dist/framework/dope-zip.js.map +1 -0
  53. package/dist/framework/effect.d.ts +128 -0
  54. package/dist/framework/effect.d.ts.map +1 -0
  55. package/dist/framework/effect.js +19 -0
  56. package/dist/framework/effect.js.map +1 -0
  57. package/dist/framework/frame-expr.d.ts +124 -0
  58. package/dist/framework/frame-expr.d.ts.map +1 -0
  59. package/dist/framework/frame-expr.js +135 -0
  60. package/dist/framework/frame-expr.js.map +1 -0
  61. package/dist/framework/load-effect.d.ts +77 -0
  62. package/dist/framework/load-effect.d.ts.map +1 -0
  63. package/dist/framework/load-effect.js +135 -0
  64. package/dist/framework/load-effect.js.map +1 -0
  65. package/dist/framework/loader.d.ts +309 -0
  66. package/dist/framework/loader.d.ts.map +1 -0
  67. package/dist/framework/loader.js +266 -0
  68. package/dist/framework/loader.js.map +1 -0
  69. package/dist/framework/mood-registry.d.ts +58 -0
  70. package/dist/framework/mood-registry.d.ts.map +1 -0
  71. package/dist/framework/mood-registry.js +58 -0
  72. package/dist/framework/mood-registry.js.map +1 -0
  73. package/dist/framework/panel-runner.d.ts +96 -0
  74. package/dist/framework/panel-runner.d.ts.map +1 -0
  75. package/dist/framework/panel-runner.js +137 -0
  76. package/dist/framework/panel-runner.js.map +1 -0
  77. package/dist/framework/pass-common.d.ts +97 -0
  78. package/dist/framework/pass-common.d.ts.map +1 -0
  79. package/dist/framework/pass-common.js +178 -0
  80. package/dist/framework/pass-common.js.map +1 -0
  81. package/dist/framework/pass-runner.d.ts +183 -0
  82. package/dist/framework/pass-runner.d.ts.map +1 -0
  83. package/dist/framework/pass-runner.js +212 -0
  84. package/dist/framework/pass-runner.js.map +1 -0
  85. package/dist/framework/programs.d.ts +54 -0
  86. package/dist/framework/programs.d.ts.map +1 -0
  87. package/dist/framework/programs.js +33 -0
  88. package/dist/framework/programs.js.map +1 -0
  89. package/dist/framework/registry.d.ts +29 -0
  90. package/dist/framework/registry.d.ts.map +1 -0
  91. package/dist/framework/registry.js +38 -0
  92. package/dist/framework/registry.js.map +1 -0
  93. package/dist/framework/runtime.d.ts +19 -0
  94. package/dist/framework/runtime.d.ts.map +1 -0
  95. package/dist/framework/runtime.js +37 -0
  96. package/dist/framework/runtime.js.map +1 -0
  97. package/dist/index.d.ts +63 -0
  98. package/dist/index.d.ts.map +1 -0
  99. package/dist/index.js +126 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/overlay.d.ts +46 -0
  102. package/dist/overlay.d.ts.map +1 -0
  103. package/dist/overlay.js +79 -0
  104. package/dist/overlay.js.map +1 -0
  105. package/dist/types.d.ts +68 -0
  106. package/dist/types.d.ts.map +1 -0
  107. package/dist/types.js +10 -0
  108. package/dist/types.js.map +1 -0
  109. package/package.json +37 -0
  110. package/src/engine/color.ts +154 -0
  111. package/src/engine/context.ts +0 -0
  112. package/src/engine/gl.ts +46 -0
  113. package/src/engine/look/glsl.ts +183 -0
  114. package/src/engine/look/particles.glsl.ts +44 -0
  115. package/src/engine/sdf.ts +298 -0
  116. package/src/engine/seed.ts +23 -0
  117. package/src/engine/shadow.ts +66 -0
  118. package/src/engine/tempo.ts +54 -0
  119. package/src/framework/conductor.ts +604 -0
  120. package/src/framework/content.ts +113 -0
  121. package/src/framework/dope-pass.ts +432 -0
  122. package/src/framework/dope-zip.ts +125 -0
  123. package/src/framework/effect.ts +127 -0
  124. package/src/framework/frame-expr.ts +217 -0
  125. package/src/framework/load-effect.ts +204 -0
  126. package/src/framework/loader.ts +502 -0
  127. package/src/framework/mood-registry.ts +87 -0
  128. package/src/framework/panel-runner.ts +233 -0
  129. package/src/framework/pass-common.ts +222 -0
  130. package/src/framework/pass-runner.ts +391 -0
  131. package/src/framework/programs.ts +62 -0
  132. package/src/framework/registry.ts +44 -0
  133. package/src/framework/runtime.ts +38 -0
  134. package/src/index.ts +227 -0
  135. package/src/overlay.ts +109 -0
  136. package/src/types.ts +63 -0
@@ -0,0 +1,100 @@
1
+ /**
2
+ * The conductor — the single runtime that owns everything an effect must NOT:
3
+ * the overlay canvases (light + shadow), their shared WebGL contexts (+ program
4
+ * caches), the RAF loop, device-pixel-ratio + resize handling, document
5
+ * visibility pausing, and the reduced-motion fallback.
6
+ *
7
+ * Key design choices:
8
+ * - **One persistent host per target.** A target (usually `document.body`) gets
9
+ * a single overlay (light + shadow canvas) + two GL contexts that live until
10
+ * explicitly torn down. Firing N effects reuses that one overlay and those
11
+ * contexts — so the expensive shader LINK happens once per page, not per fire,
12
+ * and we never leak the per-fire WebGL contexts that browsers cap at ~16.
13
+ * - **Concurrent effects.** Many effects can play at once on the same host. The
14
+ * conductor clears each canvas once per frame and composites the active
15
+ * effects: the light canvas blends ADDITIVELY (`ONE, ONE`) so layers sum as
16
+ * light (matching the `screen` overlay); the shadow canvas blends with `MIN`
17
+ * so the darkest occlusion wins (a faithful single-effect identity, a sane
18
+ * stack for many). For a single effect both reduce to exactly the legacy
19
+ * output (additive over black == replace; min over white == replace).
20
+ * - **Frame budgeting.** A single RAF drives every active effect; when nothing
21
+ * is active the loop stops (no idle RAF churn). Hidden tabs skip the GPU work
22
+ * but keep timing so effects still resolve.
23
+ * - **Reduced motion.** When the user prefers reduced motion, an effect renders
24
+ * a single calm frame held briefly instead of the full animation.
25
+ * - **SSR-safe.** Every browser global is reached through `runtime.ts`; off-DOM,
26
+ * `play()` resolves immediately and `prepare()` returns null.
27
+ */
28
+ import type { Anchor, EffectFactory, FeelingInput } from "./effect.js";
29
+ /**
30
+ * Backdrop-aware compositing for a host. When set, the host composites against a
31
+ * known surface colour: the light canvas uses premultiplied source-over
32
+ * (`mix-blend-mode: normal`) instead of `screen` — so the effect stays visible
33
+ * on any surface, white included — and the multiply shadow is strengthened as
34
+ * the surface lightens (where the source-over light reads faintest). `null` is
35
+ * the classic dark path (screen light + multiply shadow, byte-identical).
36
+ */
37
+ export interface CompositeMode {
38
+ /** Backdrop relative luminance 0 (black) .. 1 (white). */
39
+ luminance: number;
40
+ }
41
+ /**
42
+ * Fully release the persistent host(s): cancel RAF, drop the GL contexts, remove
43
+ * the overlay. Called rarely (test teardown, an SPA route that wants a hard
44
+ * reset, offline capture between effects). With no arg, tears down every host.
45
+ */
46
+ export declare function teardown(target?: HTMLElement): void;
47
+ export interface PlayRequest {
48
+ factory: EffectFactory;
49
+ target: HTMLElement;
50
+ /** Anchor in CSS px relative to the *target's* box (overlay-local). */
51
+ anchor: Anchor;
52
+ /** Targeted element size (CSS px); the centrepiece is sized to this box. */
53
+ targetSize?: {
54
+ width: number;
55
+ height: number;
56
+ };
57
+ feeling: FeelingInput;
58
+ /**
59
+ * Backdrop-aware compositing for this fire (from the public `backdrop`
60
+ * option). `null`/omitted ⇒ the classic screen/multiply path. All effects on
61
+ * one target share a compositing mode; a fire that changes it rebuilds the host.
62
+ */
63
+ composite?: CompositeMode | null;
64
+ }
65
+ /**
66
+ * What `play()` returns: awaitable as before (resolves when the effect has
67
+ * fully played out — or, for a CONTINUOUS effect, when the host stops it), plus
68
+ * lifecycle controls. `stop()` ends it (a one-shot early; an already-finished
69
+ * effect: a no-op). `pause()`/`resume()` FREEZE and RESUME the timeline — for a
70
+ * perpetual loop in a long-lived view, pausing parks it so it costs no battery,
71
+ * and resuming continues drift-free (the loop seam is preserved). All three are
72
+ * no-ops off-DOM or once the effect has resolved.
73
+ */
74
+ export type PlayHandle = Promise<void> & {
75
+ stop(): void;
76
+ pause(): void;
77
+ resume(): void;
78
+ };
79
+ /**
80
+ * Play an effect in real time. Resolves when it has fully played out. A
81
+ * CONTINUOUS effect (`factory.loop`) instead re-arms at every `durationMs`
82
+ * seam and plays until the host calls the returned handle's `stop()`. The host
83
+ * (overlay + contexts + loop) is created lazily and kept warm for reuse when
84
+ * idle; the RAF loop stops between fires. Call {@link teardown} to release it.
85
+ */
86
+ export declare function play(req: PlayRequest): PlayHandle;
87
+ /**
88
+ * Build a frame-perfect, manually-driven instance (no RAF, no auto-teardown) for
89
+ * offline capture or external timelines. The caller owns `renderAt` + `dispose`.
90
+ * Returns `null` off-DOM. The host stays alive until `dispose()`.
91
+ */
92
+ export interface PreparedHandle {
93
+ readonly durationMs: number;
94
+ renderAt(elapsedMs: number): void;
95
+ dispose(): void;
96
+ }
97
+ export declare function prepare(req: PlayRequest): PreparedHandle | null;
98
+ /** Test/SSR helper: how many live hosts (overlay+contexts) currently exist. */
99
+ export declare function activeHostCount(): number;
100
+ //# sourceMappingURL=conductor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conductor.d.ts","sourceRoot":"","sources":["../../src/framework/conductor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAiB,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAqCtF;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;CACnB;AA4SD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,CAsBnD;AAmBD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,WAAW,CAAC;IACpB,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,UAAU,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,OAAO,EAAE,YAAY,CAAC;IACtB;;;;OAIG;IACH,SAAS,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG;IACvC,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,IAAI,CAAC;CAChB,CAAC;AAKF;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,GAAG,EAAE,WAAW,GAAG,UAAU,CAoDjD;AAoCD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,WAAW,GAAG,cAAc,GAAG,IAAI,CAkC/D;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
@@ -0,0 +1,493 @@
1
+ /**
2
+ * The conductor — the single runtime that owns everything an effect must NOT:
3
+ * the overlay canvases (light + shadow), their shared WebGL contexts (+ program
4
+ * caches), the RAF loop, device-pixel-ratio + resize handling, document
5
+ * visibility pausing, and the reduced-motion fallback.
6
+ *
7
+ * Key design choices:
8
+ * - **One persistent host per target.** A target (usually `document.body`) gets
9
+ * a single overlay (light + shadow canvas) + two GL contexts that live until
10
+ * explicitly torn down. Firing N effects reuses that one overlay and those
11
+ * contexts — so the expensive shader LINK happens once per page, not per fire,
12
+ * and we never leak the per-fire WebGL contexts that browsers cap at ~16.
13
+ * - **Concurrent effects.** Many effects can play at once on the same host. The
14
+ * conductor clears each canvas once per frame and composites the active
15
+ * effects: the light canvas blends ADDITIVELY (`ONE, ONE`) so layers sum as
16
+ * light (matching the `screen` overlay); the shadow canvas blends with `MIN`
17
+ * so the darkest occlusion wins (a faithful single-effect identity, a sane
18
+ * stack for many). For a single effect both reduce to exactly the legacy
19
+ * output (additive over black == replace; min over white == replace).
20
+ * - **Frame budgeting.** A single RAF drives every active effect; when nothing
21
+ * is active the loop stops (no idle RAF churn). Hidden tabs skip the GPU work
22
+ * but keep timing so effects still resolve.
23
+ * - **Reduced motion.** When the user prefers reduced motion, an effect renders
24
+ * a single calm frame held briefly instead of the full animation.
25
+ * - **SSR-safe.** Every browser global is reached through `runtime.ts`; off-DOM,
26
+ * `play()` resolves immediately and `prepare()` returns null.
27
+ */
28
+ import { createGLContext } from "../engine/context.js";
29
+ import { createOverlay } from "../overlay.js";
30
+ import { resolveMood } from "./mood-registry.js";
31
+ import { deviceDpr, isBrowser, isDocumentHidden, prefersReducedMotion, } from "./runtime.js";
32
+ const hosts = new Map();
33
+ // Cap the overlay's drawing-buffer area so a heavy fullscreen effect (confetti,
34
+ // lightning, solarbloom — large per-fragment loops) doesn't pay for millions of
35
+ // retina pixels on a big viewport. Past the budget the EFFECTIVE dpr is scaled
36
+ // down — the buffer shrinks and the browser upscales the canvas (CSS size
37
+ // unchanged), which is imperceptible for soft glow but a big fill-cost win. Small
38
+ // surfaces (phones) stay at full dpr. The SAME effective dpr drives the effect's
39
+ // coordinate math (ctx.dpr), so origin/resolution stay consistent.
40
+ const MAX_OVERLAY_PIXELS = 2_000_000;
41
+ function effectiveDpr(c) {
42
+ const dpr = deviceDpr();
43
+ const cw = Math.max(1, c.clientWidth);
44
+ const ch = Math.max(1, c.clientHeight);
45
+ const px = cw * ch * dpr * dpr;
46
+ return px > MAX_OVERLAY_PIXELS ? Math.max(1, dpr * Math.sqrt(MAX_OVERLAY_PIXELS / px)) : dpr;
47
+ }
48
+ function syncCanvasSize(c, dpr) {
49
+ const w = Math.max(1, Math.round(c.clientWidth * dpr));
50
+ const h = Math.max(1, Math.round(c.clientHeight * dpr));
51
+ if (c.width !== w || c.height !== h) {
52
+ c.width = w;
53
+ c.height = h;
54
+ }
55
+ }
56
+ function syncHostSize(host) {
57
+ syncCanvasSize(host.light.canvas, host.dpr);
58
+ if (host.shadow)
59
+ syncCanvasSize(host.shadow.canvas, host.dpr);
60
+ }
61
+ function getHost(target, wantShadow, composite) {
62
+ let host = hosts.get(target);
63
+ if (host) {
64
+ // The light canvas's premultiplied-alpha buffer is a context-CREATION
65
+ // attribute, so flipping between the screen path and the backdrop path means
66
+ // rebuilding the host. (A backdrop COLOUR change within the same mode just
67
+ // updates the luminance-driven styles below — no rebuild.) Switching modes
68
+ // is a deliberate host-level action (a theme toggle), so dropping the warm
69
+ // contexts + any in-flight effect is acceptable and rare.
70
+ if (!!host.composite !== !!composite) {
71
+ teardown(target);
72
+ host = undefined;
73
+ }
74
+ else {
75
+ // A later effect may need a shadow canvas the host wasn't created with.
76
+ if (wantShadow && !host.shadow) {
77
+ const shadowCanvas = host.overlay.ensureShadow();
78
+ host.shadow = createGLContext(shadowCanvas);
79
+ }
80
+ host.composite = composite;
81
+ applyCompositeStyles(host);
82
+ return host;
83
+ }
84
+ }
85
+ const overlay = createOverlay(target, { shadow: wantShadow });
86
+ const light = createGLContext(overlay.canvas, { premultiplied: !!composite });
87
+ const shadow = overlay.shadow ? createGLContext(overlay.shadow) : null;
88
+ const h = {
89
+ overlay,
90
+ light,
91
+ shadow,
92
+ dpr: deviceDpr(),
93
+ active: new Set(),
94
+ raf: 0,
95
+ resize: () => { },
96
+ composite,
97
+ };
98
+ h.resize = () => {
99
+ h.dpr = effectiveDpr(h.light.canvas);
100
+ syncHostSize(h);
101
+ };
102
+ h.dpr = effectiveDpr(overlay.canvas);
103
+ syncHostSize(h);
104
+ applyCompositeStyles(h);
105
+ window.addEventListener("resize", h.resize);
106
+ hosts.set(target, h);
107
+ return h;
108
+ }
109
+ /**
110
+ * Clear the light canvas + arm additive blending. The default screen path
111
+ * clears to OPAQUE black (screen identity); the backdrop path clears to
112
+ * TRANSPARENT black so the premultiplied light composites source-over (dark
113
+ * regions stay transparent, the page shows through). Both accumulate concurrent
114
+ * effects additively (`ONE, ONE`).
115
+ */
116
+ function beginLight(host) {
117
+ const { gl, canvas } = host.light;
118
+ gl.viewport(0, 0, canvas.width, canvas.height);
119
+ gl.clearColor(0, 0, 0, host.composite ? 0 : 1);
120
+ gl.clear(gl.COLOR_BUFFER_BIT);
121
+ gl.enable(gl.BLEND);
122
+ gl.blendEquation(gl.FUNC_ADD);
123
+ gl.blendFunc(gl.ONE, gl.ONE);
124
+ }
125
+ const clamp01 = (x) => (x < 0 ? 0 : x > 1 ? 1 : x);
126
+ /**
127
+ * Reflect the host's compositing mode onto the canvas CSS: the light layer
128
+ * blends `normal` (source-over) in backdrop mode vs `screen` by default, and
129
+ * the shadow layer's opacity ramps with backdrop luminance (a near-black
130
+ * surface hides multiply shadow anyway, while a light surface leans on it for
131
+ * depth). In the default path the styles are left exactly as the overlay set
132
+ * them (screen + full-strength shadow), so nothing changes.
133
+ */
134
+ function applyCompositeStyles(host) {
135
+ host.light.canvas.style.mixBlendMode = host.composite ? "normal" : "screen";
136
+ if (host.shadow) {
137
+ host.shadow.canvas.style.opacity = host.composite
138
+ ? String(clamp01(0.4 + 0.6 * host.composite.luminance))
139
+ : "";
140
+ }
141
+ }
142
+ /** Clear the shadow canvas to white (multiply identity) + arm MIN blending. */
143
+ function beginShadow(host) {
144
+ if (!host.shadow)
145
+ return;
146
+ const { gl, canvas } = host.shadow;
147
+ gl.viewport(0, 0, canvas.width, canvas.height);
148
+ gl.clearColor(1, 1, 1, 1);
149
+ gl.clear(gl.COLOR_BUFFER_BIT);
150
+ gl.enable(gl.BLEND);
151
+ gl.blendEquation(gl.MIN);
152
+ gl.blendFunc(gl.ONE, gl.ONE);
153
+ }
154
+ /** Clear both canvases (no draw) — used to wipe the last held frame on idle. */
155
+ function clearHost(host) {
156
+ beginLight(host);
157
+ beginShadow(host);
158
+ }
159
+ /**
160
+ * Stop the RAF loop and clear the last frame when a host goes idle, but KEEP the
161
+ * overlay + contexts (and thus the compiled-program caches) alive for the page's
162
+ * lifetime. Re-firing reuses everything — the expensive shader link happens once
163
+ * per page, not once per fire.
164
+ */
165
+ function quiesce(host) {
166
+ if (host.raf) {
167
+ cancelAnimationFrame(host.raf);
168
+ host.raf = 0;
169
+ }
170
+ if (!isDocumentHidden()) {
171
+ syncHostSize(host);
172
+ clearHost(host);
173
+ }
174
+ }
175
+ function ensureLoop(host) {
176
+ if (host.raf)
177
+ return;
178
+ const frame = (now) => {
179
+ host.raf = 0;
180
+ if (host.active.size === 0)
181
+ return;
182
+ // Visibility economics: a perpetual loop (or any effect) in a hidden tab is
183
+ // AUTO-PAUSED — its timeline freezes so it costs no battery in a long-lived
184
+ // background view — and resumes drift-free when the tab is shown again.
185
+ if (isDocumentHidden())
186
+ autoPauseHidden(host);
187
+ const hidden = isDocumentHidden();
188
+ if (!hidden) {
189
+ syncHostSize(host);
190
+ beginLight(host);
191
+ beginShadow(host);
192
+ }
193
+ for (const fx of [...host.active]) {
194
+ if (fx.stopRequested) {
195
+ host.active.delete(fx);
196
+ fx.dispose();
197
+ fx.resolve();
198
+ continue;
199
+ }
200
+ // A paused effect (manual pause() or the hidden-tab auto-pause) holds: its
201
+ // clock does not advance and it is not redrawn. The last drawn frame stays
202
+ // on screen until resume() (or a stop/teardown).
203
+ if (fx.pausedAt)
204
+ continue;
205
+ const elapsed = now - fx.startedAt;
206
+ // Skip the (invisible) draw on hidden tabs, but keep the timeline moving.
207
+ if (!hidden)
208
+ fx.renderAt(Math.min(elapsed, fx.durationMs));
209
+ if (elapsed >= fx.durationMs) {
210
+ if (fx.loop) {
211
+ // CONTINUOUS effect: re-arm at the seam instead of tearing down. The
212
+ // .dope loop contract guarantees t == durationMs renders as t == 0, so
213
+ // advancing startedAt by whole durations (several at once if frames
214
+ // stalled, e.g. a backgrounded tab) is seamless and drift-free.
215
+ fx.startedAt += Math.floor(elapsed / fx.durationMs) * fx.durationMs;
216
+ }
217
+ else {
218
+ host.active.delete(fx);
219
+ fx.dispose();
220
+ fx.resolve();
221
+ }
222
+ }
223
+ }
224
+ if (host.active.size === 0) {
225
+ quiesce(host);
226
+ return;
227
+ }
228
+ // When EVERY live effect is paused there is nothing to advance or draw, so
229
+ // we stop spinning the RAF (no idle churn). The pause's resume() — or, for
230
+ // the hidden-tab auto-pause, the visibilitychange listener — re-arms it.
231
+ if (allPaused(host)) {
232
+ if (host.raf) {
233
+ cancelAnimationFrame(host.raf);
234
+ host.raf = 0;
235
+ }
236
+ return;
237
+ }
238
+ host.raf = requestAnimationFrame(frame);
239
+ };
240
+ host.raf = requestAnimationFrame(frame);
241
+ }
242
+ /** True when every live effect on the host is paused (manual or auto). */
243
+ function allPaused(host) {
244
+ for (const fx of host.active)
245
+ if (!fx.pausedAt)
246
+ return false;
247
+ return host.active.size > 0;
248
+ }
249
+ /**
250
+ * Pause an effect: freeze its timeline at `now` so it neither advances nor
251
+ * draws. `auto` marks a hidden-tab auto-pause (lifted only by the tab becoming
252
+ * visible). A re-pause keeps the original `pausedAt` so the frozen clock is
253
+ * stable; `auto` only ever escalates (a manual pause that later goes hidden
254
+ * stays manual; an auto-pause that the host later pauses manually becomes
255
+ * manual, so showing the tab won't auto-resume it).
256
+ */
257
+ function pauseEffect(fx, now, auto) {
258
+ if (!fx.pausedAt)
259
+ fx.pausedAt = now;
260
+ if (!auto)
261
+ fx.autoPaused = false;
262
+ }
263
+ /**
264
+ * Resume a paused effect: shift `startedAt` forward by the span it was paused,
265
+ * so its clock continues exactly where it froze (drift-free; a loop's seam is
266
+ * preserved). No-op if it isn't paused.
267
+ */
268
+ function resumeEffect(fx, now) {
269
+ if (!fx.pausedAt)
270
+ return;
271
+ fx.startedAt += now - fx.pausedAt;
272
+ fx.pausedAt = 0;
273
+ fx.autoPaused = false;
274
+ }
275
+ /** Auto-pause every running effect on a host because the document went hidden. */
276
+ function autoPauseHidden(host) {
277
+ const now = performance.now();
278
+ for (const fx of host.active) {
279
+ if (!fx.pausedAt) {
280
+ fx.pausedAt = now;
281
+ fx.autoPaused = true;
282
+ }
283
+ }
284
+ }
285
+ /** Auto-resume the effects a hidden-tab auto-pause paused (the tab is visible). */
286
+ function autoResumeVisible(host) {
287
+ const now = performance.now();
288
+ let any = false;
289
+ for (const fx of host.active) {
290
+ if (fx.pausedAt && fx.autoPaused) {
291
+ resumeEffect(fx, now);
292
+ any = true;
293
+ }
294
+ }
295
+ if (any)
296
+ ensureLoop(host);
297
+ }
298
+ /**
299
+ * Install ONE document-level `visibilitychange` listener that auto-resumes
300
+ * every host when the tab is shown again (the hide path is handled in-loop, so
301
+ * a tab that's already hidden when an effect fires is covered too). Idempotent.
302
+ */
303
+ let visibilityListenerInstalled = false;
304
+ function ensureVisibilityListener() {
305
+ if (visibilityListenerInstalled || typeof document === "undefined")
306
+ return;
307
+ visibilityListenerInstalled = true;
308
+ document.addEventListener("visibilitychange", () => {
309
+ if (isDocumentHidden())
310
+ return;
311
+ for (const host of hosts.values())
312
+ autoResumeVisible(host);
313
+ });
314
+ }
315
+ /**
316
+ * Fully release the persistent host(s): cancel RAF, drop the GL contexts, remove
317
+ * the overlay. Called rarely (test teardown, an SPA route that wants a hard
318
+ * reset, offline capture between effects). With no arg, tears down every host.
319
+ */
320
+ export function teardown(target) {
321
+ const release = (t, host) => {
322
+ if (host.raf)
323
+ cancelAnimationFrame(host.raf);
324
+ for (const fx of host.active) {
325
+ fx.dispose();
326
+ fx.resolve();
327
+ }
328
+ host.active.clear();
329
+ if (typeof window !== "undefined") {
330
+ window.removeEventListener("resize", host.resize);
331
+ }
332
+ host.light.destroy();
333
+ host.shadow?.destroy();
334
+ host.overlay.destroy();
335
+ hosts.delete(t);
336
+ };
337
+ if (target) {
338
+ const host = hosts.get(target);
339
+ if (host)
340
+ release(target, host);
341
+ return;
342
+ }
343
+ for (const [t, host] of [...hosts])
344
+ release(t, host);
345
+ }
346
+ function buildEffectContext(host, anchor, targetSize) {
347
+ return {
348
+ light: host.light,
349
+ shadow: host.shadow,
350
+ anchor,
351
+ targetSize,
352
+ get dpr() {
353
+ return host.dpr;
354
+ },
355
+ composite: host.composite ? { premultiplied: true } : undefined,
356
+ };
357
+ }
358
+ const resolvedHandle = () => Object.assign(Promise.resolve(), { stop() { }, pause() { }, resume() { } });
359
+ /**
360
+ * Play an effect in real time. Resolves when it has fully played out. A
361
+ * CONTINUOUS effect (`factory.loop`) instead re-arms at every `durationMs`
362
+ * seam and plays until the host calls the returned handle's `stop()`. The host
363
+ * (overlay + contexts + loop) is created lazily and kept warm for reuse when
364
+ * idle; the RAF loop stops between fires. Call {@link teardown} to release it.
365
+ */
366
+ export function play(req) {
367
+ if (!isBrowser())
368
+ return resolvedHandle();
369
+ const wantShadow = req.factory.castsShadow !== false;
370
+ const host = getHost(req.target, wantShadow, req.composite ?? null);
371
+ const mood = resolveMood(req.feeling.mood);
372
+ const params = req.factory.resolve(req.feeling, mood);
373
+ let instance;
374
+ try {
375
+ instance = req.factory.create(params, buildEffectContext(host, req.anchor, req.targetSize));
376
+ }
377
+ catch (err) {
378
+ if (host.active.size === 0)
379
+ quiesce(host);
380
+ return Object.assign(Promise.reject(err), { stop() { }, pause() { }, resume() { } });
381
+ }
382
+ // Reduced motion: draw one calm frame, hold briefly (a looping effect holds
383
+ // until stopped — it never animates, let alone loops), done.
384
+ if (prefersReducedMotion()) {
385
+ return playReduced(host, instance, req.factory);
386
+ }
387
+ let resolve;
388
+ const done = new Promise((res) => (resolve = res));
389
+ const fx = {
390
+ renderAt: (ms) => instance.renderAt(ms),
391
+ dispose: () => instance.dispose(),
392
+ startedAt: performance.now(),
393
+ durationMs: instance.durationMs,
394
+ resolve,
395
+ loop: !!req.factory.loop,
396
+ stopRequested: false,
397
+ pausedAt: 0,
398
+ autoPaused: false,
399
+ };
400
+ host.active.add(fx);
401
+ ensureVisibilityListener();
402
+ ensureLoop(host);
403
+ return Object.assign(done, {
404
+ stop: () => {
405
+ fx.stopRequested = true;
406
+ // Stopping a paused effect must still wake the loop so the next frame
407
+ // disposes + resolves it (the loop is parked while everything's paused).
408
+ fx.pausedAt = 0;
409
+ ensureLoop(host);
410
+ },
411
+ pause: () => pauseEffect(fx, performance.now(), false),
412
+ resume: () => {
413
+ resumeEffect(fx, performance.now());
414
+ ensureLoop(host);
415
+ },
416
+ });
417
+ }
418
+ function playReduced(host, instance, factory) {
419
+ const rm = factory.reducedMotion ?? {};
420
+ const peakMs = rm.peakMs ?? Math.min(260, instance.durationMs * 0.18);
421
+ const holdMs = rm.holdMs ?? 360;
422
+ if (!isDocumentHidden()) {
423
+ syncHostSize(host);
424
+ beginLight(host);
425
+ beginShadow(host);
426
+ instance.renderAt(peakMs);
427
+ }
428
+ let resolve;
429
+ const done = new Promise((res) => (resolve = res));
430
+ let finished = false;
431
+ const finish = () => {
432
+ if (finished)
433
+ return;
434
+ finished = true;
435
+ instance.dispose();
436
+ // Clear the held frame; keep the (reusable) host alive but quiesced.
437
+ if (host.active.size === 0)
438
+ quiesce(host);
439
+ resolve();
440
+ };
441
+ // A CONTINUOUS effect's calm frame holds until the host stops it (the
442
+ // reduced-motion analog of the loop); a one-shot's holds for holdMs.
443
+ if (!factory.loop)
444
+ setTimeout(finish, holdMs);
445
+ // Reduced motion renders one static held frame (no animation, no loop), so
446
+ // pause/resume have nothing to freeze — they are no-ops, but present so the
447
+ // handle's shape is identical to the animated path.
448
+ return Object.assign(done, { stop: finish, pause() { }, resume() { } });
449
+ }
450
+ export function prepare(req) {
451
+ if (!isBrowser())
452
+ return null;
453
+ const wantShadow = req.factory.castsShadow !== false;
454
+ const host = getHost(req.target, wantShadow, req.composite ?? null);
455
+ const mood = resolveMood(req.feeling.mood);
456
+ const params = req.factory.resolve(req.feeling, mood);
457
+ let instance;
458
+ try {
459
+ instance = req.factory.create(params, buildEffectContext(host, req.anchor, req.targetSize));
460
+ }
461
+ catch (err) {
462
+ if (host.active.size === 0)
463
+ quiesce(host);
464
+ throw err;
465
+ }
466
+ let disposed = false;
467
+ return {
468
+ durationMs: instance.durationMs,
469
+ renderAt(elapsedMs) {
470
+ if (disposed)
471
+ return;
472
+ syncHostSize(host);
473
+ beginLight(host);
474
+ beginShadow(host);
475
+ instance.renderAt(elapsedMs);
476
+ },
477
+ dispose() {
478
+ if (disposed)
479
+ return;
480
+ disposed = true;
481
+ instance.dispose();
482
+ // Manually-driven handles fully release their host (offline capture wants
483
+ // a clean slate between effects), unless live effects are still animating.
484
+ if (host.active.size === 0)
485
+ teardown(req.target);
486
+ },
487
+ };
488
+ }
489
+ /** Test/SSR helper: how many live hosts (overlay+contexts) currently exist. */
490
+ export function activeHostCount() {
491
+ return hosts.size;
492
+ }
493
+ //# sourceMappingURL=conductor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conductor.js","sourceRoot":"","sources":["../../src/framework/conductor.ts"],"names":[],"mappings":"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"}