@pixerate/flair 0.0.0-stage → 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 (53) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +254 -2
  4. package/dist/catalog/index.d.ts +74 -0
  5. package/dist/catalog/index.js +47 -0
  6. package/dist/catalog/index.js.map +1 -0
  7. package/dist/chunk-36DTNSHU.js +160 -0
  8. package/dist/chunk-36DTNSHU.js.map +1 -0
  9. package/dist/chunk-3FAUZOGL.js +331 -0
  10. package/dist/chunk-3FAUZOGL.js.map +1 -0
  11. package/dist/chunk-CFCLT2XL.js +1 -0
  12. package/dist/chunk-CFCLT2XL.js.map +1 -0
  13. package/dist/chunk-EHDJ3CPJ.js +327 -0
  14. package/dist/chunk-EHDJ3CPJ.js.map +1 -0
  15. package/dist/chunk-G5FNZDTA.js +536 -0
  16. package/dist/chunk-G5FNZDTA.js.map +1 -0
  17. package/dist/chunk-HKXOHRCD.js +763 -0
  18. package/dist/chunk-HKXOHRCD.js.map +1 -0
  19. package/dist/chunk-J55UBNAT.js +164 -0
  20. package/dist/chunk-J55UBNAT.js.map +1 -0
  21. package/dist/chunk-JWZCPMFG.js +2074 -0
  22. package/dist/chunk-JWZCPMFG.js.map +1 -0
  23. package/dist/chunk-MWVTQFV5.js +1894 -0
  24. package/dist/chunk-MWVTQFV5.js.map +1 -0
  25. package/dist/chunk-UQQNZSYL.js +594 -0
  26. package/dist/chunk-UQQNZSYL.js.map +1 -0
  27. package/dist/chunk-WMZQCUFJ.js +73 -0
  28. package/dist/chunk-WMZQCUFJ.js.map +1 -0
  29. package/dist/cli.d.ts +1 -0
  30. package/dist/cli.js +331 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/clock-BhdXWH-n.d.ts +47 -0
  33. package/dist/controls-DdXMbovi.d.ts +97 -0
  34. package/dist/editor/index.d.ts +413 -0
  35. package/dist/editor/index.js +1009 -0
  36. package/dist/editor/index.js.map +1 -0
  37. package/dist/export-FEBPEEO7.js +22 -0
  38. package/dist/export-FEBPEEO7.js.map +1 -0
  39. package/dist/index.d.ts +1431 -0
  40. package/dist/index.js +1263 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/motion-D0TVv2CF.d.ts +148 -0
  43. package/dist/node.d.ts +24 -0
  44. package/dist/node.js +10 -0
  45. package/dist/node.js.map +1 -0
  46. package/dist/recorder-WJTWMEQN.js +10 -0
  47. package/dist/recorder-WJTWMEQN.js.map +1 -0
  48. package/dist/renderer-Oyynz-fs.d.ts +293 -0
  49. package/dist/types-CkKkavvB.d.ts +71 -0
  50. package/dist/vector/index.d.ts +83 -0
  51. package/dist/vector/index.js +39 -0
  52. package/dist/vector/index.js.map +1 -0
  53. package/package.json +96 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @pixerate/flair
2
+
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - f4849b5: First public release: WebGL2 shader effects with image controls, animated vector effects, a catalog of 59 ready-made effects, and a UI-agnostic, agent-ready effect editor built on `@pixerate/editor`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jack James
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,255 @@
1
- # Temporary Holding Version
1
+ # @pixerate/flair
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ <p align="center">
4
+ <strong>Visual effects and motion graphics for the web: WebGL2 shader effects, animated vector effects, a catalog of ready-made looks, and a UI-agnostic, agent-ready effect editor.</strong>
5
+ </p>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@pixerate/flair"><img src="https://img.shields.io/npm/v/@pixerate/flair.svg?style=flat-square&color=violet" alt="npm version" /></a>
9
+ <a href="https://github.com/Pixerate/flair/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/Pixerate/flair/ci.yml?branch=main&style=flat-square" alt="CI build status" /></a>
10
+ <a href="https://pixerate.github.io/flair/"><img src="https://img.shields.io/badge/demo-live-a855f7.svg?style=flat-square" alt="Live demo" /></a>
11
+ <a href="https://github.com/Pixerate/flair/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="MIT License" /></a>
12
+ </p>
13
+
14
+ ---
15
+
16
+ ## 🌟 Overview
17
+
18
+ Flair gives products a library of good-looking, configurable visual effects (hero backgrounds, textures, light, image treatments, transitions, loaders, animated icons and charts) and the tools to make more of them, by hand or with an agent.
19
+
20
+ ### Core Capabilities
21
+
22
+ - 🎨 **Effect catalog (`@pixerate/flair/catalog`)**: 59 effects, each with controls and presets. There are 44 WebGL2 shaders (gradients, organic textures, patterns, light, space, retro, image effects, transitions) and 15 animated SVG effects (loaders, status icons, charts, counters). [Browse them live](https://pixerate.github.io/flair/).
23
+ - ⚡ **Shader engine**:
24
+ - Shadertoy-style GLSL ES 3.00 fragment shaders, with controls declared in the source (`// @control`), including image inputs.
25
+ - Compile errors come back with line numbers that match the source.
26
+ - Live previews (`ShaderRenderer`) and many animated thumbnails on one context (`ThumbnailPool`).
27
+ - Frames at exact times (`ShaderFrames`), looping GIFs, and standalone HTML pages.
28
+ - ✒️ **Vector motion (`@pixerate/flair/vector`)**: animated SVG described as data. It covers attribute tweens, draw-on strokes, motion along paths, counters and view zooms. Every frame is a pure function of time (`svgFrame`), and `SvgPlayer` plays it.
29
+ - 🎛️ **Effect editor (`@pixerate/flair/editor`)**:
30
+ - A headless editor for an effect's source, values, keyframes, presets and timeline.
31
+ - Built on [`@pixerate/editor`](https://github.com/Pixerate/editor)'s undo history and command registry, with no UI framework assumed.
32
+ - 🤖 **Agent-native, bring your own model**:
33
+ - Every editing action is a command, and the commands are exposed as MCP-shaped tools.
34
+ - Ships instructions for the model. The host supplies the model, keys and agent loop.
35
+ - 🎬 **Directing and interchange**: multi-shot scenes with camera moves, procedural effects, validation and fast headless simulation. Also blend modes, Oklab colour and grading, retiming, timecode, and export to Lottie, Apple Motion, FCP7 XML and CMX 3600 EDL.
36
+
37
+ ---
38
+
39
+ ## 📦 Entry points
40
+
41
+ | Import | What it provides | Runtime dependencies |
42
+ | :--- | :--- | :--- |
43
+ | `@pixerate/flair` | Shader engine, vector motion, time and easing, colour, blending, transitions, scenes, interchange exporters | None (browser-safe) |
44
+ | `@pixerate/flair/catalog` | `EFFECTS`, `getEffect`, `findEffects`, `effectDefaults`, `renderVectorEffect`, GLSL helpers, sample images | None |
45
+ | `@pixerate/flair/vector` | `SvgMotion`, `svgFrame`, `svgView`, `SvgPlayer`, `svgMotionIssues` | None |
46
+ | `@pixerate/flair/editor` | `EffectEditor`, effect documents, keyframe tracks, renderer bindings, agent tools and instructions | `@pixerate/editor` (optional peer) |
47
+ | `@pixerate/flair/node` | `exportMotionGraphic`: renders a shader to GIF/MP4 through headless Chrome and ffmpeg | Node.js |
48
+
49
+ The `flair` CLI inspects shaders, writes standalone pages and directs scenes (see [CLI](#-cli)).
50
+
51
+ ---
52
+
53
+ ## 🏗️ Architecture
54
+
55
+ ```mermaid
56
+ graph TD
57
+ subgraph Effects["Effects (no dependencies)"]
58
+ Catalog["catalog: 59 effects + presets"]
59
+ Shader["shader engine: controls, compile, render, GIF, HTML"]
60
+ Vector["vector motion: SvgMotion, SvgPlayer"]
61
+ Time["time: clocks, easing, keyframes, noise"]
62
+ end
63
+ subgraph Editing["Editing (@pixerate/flair/editor)"]
64
+ Doc["EffectDocument: source, values, tracks, presets"]
65
+ Editor["EffectEditor: state, playhead"]
66
+ Cmds["commands → MCP tools"]
67
+ end
68
+ PE["@pixerate/editor: history, commands"]
69
+ Host["Your app: UI (any framework) + your model"]
70
+
71
+ Catalog --> Shader
72
+ Catalog --> Vector
73
+ Doc --> Editor
74
+ Editor --> Cmds
75
+ PE --> Editor
76
+ PE --> Cmds
77
+ Editor -- bindShaderRenderer / bindSvgView --> Shader
78
+ Editor --> Vector
79
+ Host --> Editor
80
+ Host -- tool calls --> Cmds
81
+ ```
82
+
83
+ Flair stays free of LLM SDKs and UI frameworks. Your app owns the interface and the model. Flair owns the rendering, the effect model and the tool surface.
84
+
85
+ ---
86
+
87
+ ## 🚀 Quickstart
88
+
89
+ ```bash
90
+ npm install @pixerate/flair
91
+ # For the editor:
92
+ npm install @pixerate/flair @pixerate/editor
93
+ ```
94
+
95
+ ### 1. Drop in a catalog effect
96
+
97
+ ```ts
98
+ import { ShaderRenderer, SvgPlayer } from "@pixerate/flair";
99
+ import { getEffect, effectDefaults, renderVectorEffect } from "@pixerate/flair/catalog";
100
+
101
+ // A shader background
102
+ const aurora = getEffect("aurora")!;
103
+ if (aurora.kind === "shader") {
104
+ const preview = new ShaderRenderer(document.querySelector("#hero")!);
105
+ preview.setSource(aurora.source);
106
+ preview.setValues(effectDefaults(aurora, { preset: "Ember", values: { uSpeed: 0.5 } }));
107
+ }
108
+
109
+ // An animated SVG loader, recoloured
110
+ const spinner = getEffect("spinner")!;
111
+ if (spinner.kind === "vector") {
112
+ new SvgPlayer(document.querySelector("#loading")!, renderVectorEffect(spinner, { accent: "#0ea5e9" }), {
113
+ hold: spinner.hold,
114
+ });
115
+ }
116
+ ```
117
+
118
+ Find effects with `findEffects({ text: "glow", category: "light", kind: "shader" })`. Each effect has an `id`, `name`, `description`, `category`, `tags` and optional `presets`. Image effects default to built-in sample pictures, so they look right before you set `uImage` to your own URL.
119
+
120
+ ### 2. Write your own shader
121
+
122
+ ```glsl
123
+ // Controls are uniforms annotated on the same line.
124
+ uniform vec3 uTint; // @control color default=#77C16A label="Tint"
125
+ uniform float uSpeed; // @control min=0 max=4 default=1 label="Speed"
126
+ uniform sampler2D uPhoto; // @control filter=linear wrap=clamp label="Photo"
127
+
128
+ void mainImage(out vec4 fragColor, in vec2 fragCoord) {
129
+ vec2 uv = fragCoord / iResolution.xy;
130
+ vec3 photo = texture(uPhoto, uv + 0.01 * sin(uv.yx * 20.0 + iTime * uSpeed)).rgb;
131
+ fragColor = vec4(photo * uTint, 1.0);
132
+ }
133
+ ```
134
+
135
+ ```ts
136
+ import { ShaderRenderer, ShaderFrames, recordGif, standaloneHtml, parseControls } from "@pixerate/flair";
137
+
138
+ const status = renderer.setSource(source); // { ok, errors: [{ line, message }] }
139
+ parseControls(source); // [{ name: "uTint", type: "vec3", color: true, default: [...] }, ...]
140
+ const gif = await recordGif({ source, width: 480, height: 270, fps: 30, duration: 3 });
141
+ const page = standaloneHtml("My effect", source, { uSpeed: 2 });
142
+ ```
143
+
144
+ ### 3. Build an editor (any UI)
145
+
146
+ ```ts
147
+ import { createEffectEditor, bindShaderRenderer, bindSvgView } from "@pixerate/flair/editor";
148
+ import { ShaderRenderer } from "@pixerate/flair";
149
+
150
+ const editor = createEffectEditor({ from: "nebula" });
151
+ const renderer = new ShaderRenderer(previewElement);
152
+ bindShaderRenderer(editor, renderer); // source, values at the playhead, time; compile errors flow back
153
+
154
+ editor.subscribe((state) => render(state)); // state: document, controls, values, issues, compile, time, history
155
+ editor.setValue("uDensity", 1.4); // checked and undoable; slider drags merge into one step
156
+ editor.setKeyframe("uSpeed", 2000, 0.2, "ease-in-out");
157
+ editor.applyPreset("Ember");
158
+ editor.play();
159
+ editor.undo();
160
+
161
+ // Menus, shortcuts and command palettes run the same commands by id:
162
+ editor.commands.execute("values.randomize");
163
+ window.addEventListener("keydown", (e) => editor.commands.handleKeyDown(e)); // Space plays/pauses
164
+ ```
165
+
166
+ `getState()` returns the same object until something changes, so React's `useSyncExternalStore` works as is. Documents are plain JSON (`EffectDocument`), and keyframe tracks use `@pixerate/editor`'s keyframe shape and easing names.
167
+
168
+ ### 4. Let an agent drive it
169
+
170
+ ```ts
171
+ import { createEffectToolProvider, toolDefinitions, callTool, EFFECT_AGENT_INSTRUCTIONS } from "@pixerate/flair/editor";
172
+
173
+ const tools = createEffectToolProvider(editor, {
174
+ capture: () => renderer.capture({ type: "image/png" }), // adds a `view_effect` tool so the model can look
175
+ });
176
+
177
+ // Give your model EFFECT_AGENT_INSTRUCTIONS and toolDefinitions(tools), then for each tool call:
178
+ const result = await callTool(tools, call.name, call.input); // MCP tools/call result
179
+
180
+ // Or register the provider with @pixerate/editor's ToolRegistry, or bridge it to an MCP server.
181
+ ```
182
+
183
+ The tools are `list_commands`, `run_command` and `run_commands`, plus `view_effect` when you can capture the preview. The commands they run:
184
+
185
+ - **Inspect and start:** `effect.describe`, `catalog.search`, `effect.load`.
186
+ - **Edit the effect:** `effect.setSource`.
187
+ - **Values and presets:** `values.set`, `values.reset`, `values.randomize`, `preset.apply` and `preset.save`.
188
+ - **Keyframes:** `keyframe.set`, `keyframe.remove`, `keyframe.setEasing` and `keyframe.clear`.
189
+ - **Timeline:** `timeline.setTiming`, `timeline.play` and `timeline.seek`.
190
+ - **History:** `history.undo` and `history.redo`.
191
+
192
+ Every change is one undo step, and refusals come back as messages the model can act on.
193
+
194
+ ---
195
+
196
+ ## 🎨 The catalog
197
+
198
+ | Category | Effects |
199
+ | :--- | :--- |
200
+ | gradient | mesh gradient, aurora, gradient flow, conic sweep, silk |
201
+ | organic | liquid marble, smoke, lava lamp, plasma, caustics, flames, blob morph |
202
+ | pattern | dot wave, Truchet flow, hex pulse, living cells, moiré rings, kaleidoscope, stripes |
203
+ | light / space | bokeh, god rays, sparkles, neon ripple, warp starfield, nebula, event horizon |
204
+ | retro | synthwave, digital rain, dithered gradient, TV static |
205
+ | image | ripple, glitch, duotone, halftone, pixel reveal, CRT screen, film look |
206
+ | transition | wipe, iris, block dissolve, grid wipe, glass wipe, twister, light leak, cross zoom |
207
+ | loader / icon / data | spinner, bouncing dots, pulse ping, equalizer, progress ring, bar chart, line chart, stat counter, route, success check, error cross, heartbeat, signature, confetti |
208
+
209
+ Every shader is self-contained and compiles on WebGL2. Open [`#check`](https://pixerate.github.io/flair/#check) on the demo to compile the catalog on your own GPU.
210
+
211
+ ---
212
+
213
+ ## 💻 CLI
214
+
215
+ ```bash
216
+ npx flair controls ./effect.frag # list @control uniforms (--json for JSON)
217
+ npx flair html ./effect.frag --out page.html --open
218
+ npx flair scene validate ./scene.json # layout, framing and timing checks
219
+ npx flair scene review ./scene.json # fast headless simulation + review
220
+ npx flair scene lottie ./scene.json out.json # also: fcp7, edl, motn
221
+ ```
222
+
223
+ ---
224
+
225
+ ## 🧪 Interactive Browser Demo
226
+
227
+ The [live demo](https://pixerate.github.io/flair/) has three parts:
228
+
229
+ - **Gallery:** the whole catalog, live.
230
+ - **Editor:** controls, presets, keyframes, source and export, built with React on the headless editor.
231
+ - **Agent tools:** the tool surface, plus a sample agent plan you can run.
232
+
233
+ To run it locally:
234
+
235
+ ```bash
236
+ pnpm install
237
+ pnpm dev # http://localhost:3100
238
+ ```
239
+
240
+ ---
241
+
242
+ ## 🛠️ Development
243
+
244
+ ```bash
245
+ pnpm typecheck && pnpm build && pnpm test
246
+ pnpm changeset # describe consumer-facing changes; merging to main publishes them
247
+ ```
248
+
249
+ See [AGENTS.md](./AGENTS.md) for the conventions contributors and coding agents follow.
250
+
251
+ ---
252
+
253
+ ## 📄 License
254
+
255
+ MIT © Pixerate
@@ -0,0 +1,74 @@
1
+ import { a as ControlDef, C as ControlValue } from '../controls-DdXMbovi.js';
2
+ import { E as EffectDefinition, a as EffectCategory, S as ShaderEffect } from '../types-CkKkavvB.js';
3
+ export { b as EFFECT_CATEGORIES, c as EffectPreset, V as VectorControl, d as VectorEffect, e as colorControl, n as numberControl, r as renderVectorEffect, v as vectorControlDef } from '../types-CkKkavvB.js';
4
+ import '../motion-D0TVv2CF.js';
5
+
6
+ /**
7
+ * Sample pictures for the catalog's image effects: small SVGs as `data:` URLs,
8
+ * so image controls have something to show with nothing to download.
9
+ */
10
+ /** An ASCII SVG as a base64 `data:image/svg+xml` URL. */
11
+ declare function svgDataUrl(svg: string): string;
12
+ /** Built-in sample pictures, as image control values. */
13
+ declare const SAMPLE_IMAGES: {
14
+ readonly landscape: string;
15
+ readonly city: string;
16
+ readonly portrait: string;
17
+ };
18
+
19
+ /**
20
+ * GLSL helpers the catalog's shaders are built from. Each effect's source
21
+ * inlines the helpers it uses, so a source stays self-contained: copy it into
22
+ * any Shadertoy-style host and it compiles.
23
+ */
24
+ /** Hashes: `hash12` (vec2 → float), `hash22` (vec2 → vec2), both 0–1. */
25
+ declare const HASH: string;
26
+ /** Smooth value noise, 0–1 (needs {@link HASH}). */
27
+ declare const NOISE: string;
28
+ /** Fractal noise: `fbm(p, octaves)`, about 0–1 (needs {@link NOISE}). */
29
+ declare const FBM: string;
30
+ /** Inigo Quilez's cosine palette: `palette(t, a, b, c, d)`. */
31
+ declare const PALETTE: string;
32
+ /** Mixes colours in Oklab, so blends stay bright: `oklabMix(a, b, t)` on sRGB colours. */
33
+ declare const OKLAB_MIX: string;
34
+ /** 2D rotation matrix: `rot(angle)`. */
35
+ declare const ROTATE: string;
36
+ /** Joins helpers and a body into one source, a blank line apart. */
37
+ declare function glsl(...parts: string[]): string;
38
+
39
+ /**
40
+ * The effect catalog: ready-made shader and vector effects, each with
41
+ * controls and presets, to drop into a product or start an edit from.
42
+ *
43
+ * - Browsing: `EFFECTS`, `getEffect`, `findEffects`, `EFFECT_CATEGORIES`.
44
+ * - Controls: `effectControls`, `effectDefaults`.
45
+ * - Vector effects: `renderVectorEffect` fills in their controls.
46
+ *
47
+ * @packageDocumentation
48
+ */
49
+
50
+ /** The catalog's shader effects. */
51
+ declare const SHADER_EFFECTS: readonly ShaderEffect[];
52
+ /** Every effect in the catalog, shaders first, grouped by category. */
53
+ declare const EFFECTS: readonly EffectDefinition[];
54
+ /** The effect with this id, or undefined. */
55
+ declare function getEffect(id: string): EffectDefinition | undefined;
56
+ interface EffectQuery {
57
+ /** Words to look for in the name, description, tags and id (all must match). */
58
+ text?: string;
59
+ category?: EffectCategory;
60
+ kind?: EffectDefinition["kind"];
61
+ /** Effects with every one of these tags. */
62
+ tags?: readonly string[];
63
+ }
64
+ /** Effects matching a query, in catalog order. */
65
+ declare function findEffects(query?: EffectQuery): EffectDefinition[];
66
+ /** An effect's controls: a shader's `@control` uniforms, or a vector effect's declared controls. */
67
+ declare function effectControls(effect: EffectDefinition): ControlDef[];
68
+ /** An effect's values: each control's default, overridden by `values` (and a preset by name, when given). */
69
+ declare function effectDefaults(effect: EffectDefinition, options?: {
70
+ preset?: string;
71
+ values?: Record<string, ControlValue>;
72
+ }): Record<string, ControlValue>;
73
+
74
+ export { EFFECTS, EffectCategory, EffectDefinition, type EffectQuery, FBM, HASH, NOISE, OKLAB_MIX, PALETTE, ROTATE, SAMPLE_IMAGES, SHADER_EFFECTS, ShaderEffect, effectControls, effectDefaults, findEffects, getEffect, glsl, svgDataUrl };
@@ -0,0 +1,47 @@
1
+ import {
2
+ EFFECTS,
3
+ EFFECT_CATEGORIES,
4
+ FBM,
5
+ HASH,
6
+ NOISE,
7
+ OKLAB_MIX,
8
+ PALETTE,
9
+ ROTATE,
10
+ SAMPLE_IMAGES,
11
+ SHADER_EFFECTS,
12
+ colorControl,
13
+ effectControls,
14
+ effectDefaults,
15
+ findEffects,
16
+ getEffect,
17
+ glsl,
18
+ numberControl,
19
+ renderVectorEffect,
20
+ svgDataUrl,
21
+ vectorControlDef
22
+ } from "../chunk-MWVTQFV5.js";
23
+ import "../chunk-EHDJ3CPJ.js";
24
+ import "../chunk-J55UBNAT.js";
25
+ export {
26
+ EFFECTS,
27
+ EFFECT_CATEGORIES,
28
+ FBM,
29
+ HASH,
30
+ NOISE,
31
+ OKLAB_MIX,
32
+ PALETTE,
33
+ ROTATE,
34
+ SAMPLE_IMAGES,
35
+ SHADER_EFFECTS,
36
+ colorControl,
37
+ effectControls,
38
+ effectDefaults,
39
+ findEffects,
40
+ getEffect,
41
+ glsl,
42
+ numberControl,
43
+ renderVectorEffect,
44
+ svgDataUrl,
45
+ vectorControlDef
46
+ };
47
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,160 @@
1
+ // src/scene/types.ts
2
+ function isElementCommand(cmd) {
3
+ return cmd.type === "element" && "element" in cmd && !!cmd.element;
4
+ }
5
+ function isUpdateCommand(cmd) {
6
+ return cmd.type === "update" && "id" in cmd && typeof cmd.id === "string";
7
+ }
8
+ function isDeleteCommand(cmd) {
9
+ return cmd.type === "delete" && "id" in cmd && typeof cmd.id === "string";
10
+ }
11
+
12
+ // src/scene/geometry.ts
13
+ function boundsOf(e) {
14
+ if (e.points?.length) {
15
+ const xs = e.points.map((p) => e.x + p[0]);
16
+ const ys = e.points.map((p) => e.y + p[1]);
17
+ const x = Math.min(...xs);
18
+ const y = Math.min(...ys);
19
+ return {
20
+ x,
21
+ y,
22
+ width: Math.max(1, Math.max(...xs) - x),
23
+ height: Math.max(1, Math.max(...ys) - y)
24
+ };
25
+ }
26
+ return { x: e.x, y: e.y, width: Math.max(1, e.width), height: Math.max(1, e.height) };
27
+ }
28
+ function overlapArea(a, b) {
29
+ const w = Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x);
30
+ const h = Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y);
31
+ return w > 0 && h > 0 ? w * h : 0;
32
+ }
33
+ var areaOf = (r) => r.width * r.height;
34
+
35
+ // src/scene/camera.ts
36
+ var DEFAULT_STAGE = {
37
+ width: 1920,
38
+ height: 1080,
39
+ caption: 0
40
+ };
41
+ var CAMERA_MS = 600;
42
+ var boardHeight = (stage) => stage.height - (stage.caption ?? 0);
43
+ function viewAt(cx, cy, zoom, stage) {
44
+ return {
45
+ zoom,
46
+ scrollX: stage.width / (2 * zoom) - cx,
47
+ scrollY: boardHeight(stage) / (2 * zoom) - cy
48
+ };
49
+ }
50
+ function centreOf(view, stage) {
51
+ return [
52
+ stage.width / (2 * view.zoom) - view.scrollX,
53
+ boardHeight(stage) / (2 * view.zoom) - view.scrollY
54
+ ];
55
+ }
56
+ function frame(rect, stage) {
57
+ if (!(rect.width > 0 && rect.height > 0)) {
58
+ throw new Error("A camera rectangle needs a positive width and height");
59
+ }
60
+ const zoom = Math.min(stage.width / rect.width, boardHeight(stage) / rect.height);
61
+ return viewAt(rect.x + rect.width / 2, rect.y + rect.height / 2, zoom, stage);
62
+ }
63
+ function calculateFramingRect(elements, stage, options = {}) {
64
+ const activeElements = elements.filter((e) => !e.isDeleted);
65
+ const targetH = boardHeight(stage);
66
+ const stageAspect = stage.width / Math.max(1, targetH);
67
+ if (activeElements.length === 0) {
68
+ return {
69
+ x: 0,
70
+ y: 0,
71
+ width: stage.width,
72
+ height: targetH
73
+ };
74
+ }
75
+ let minX = Infinity;
76
+ let minY = Infinity;
77
+ let maxX = -Infinity;
78
+ let maxY = -Infinity;
79
+ for (const el of activeElements) {
80
+ const b = boundsOf(el);
81
+ if (b.x < minX) minX = b.x;
82
+ if (b.y < minY) minY = b.y;
83
+ if (b.x + b.width > maxX) maxX = b.x + b.width;
84
+ if (b.y + b.height > maxY) maxY = b.y + b.height;
85
+ }
86
+ let width = maxX - minX;
87
+ let height = maxY - minY;
88
+ const padding = options.padding ?? 0.15;
89
+ if (padding > 0) {
90
+ const padX = width * padding;
91
+ const padY = height * padding;
92
+ minX -= padX;
93
+ minY -= padY;
94
+ width += padX * 2;
95
+ height += padY * 2;
96
+ }
97
+ if (options.minWidth && width < options.minWidth) {
98
+ const diff = options.minWidth - width;
99
+ minX -= diff / 2;
100
+ width = options.minWidth;
101
+ }
102
+ if (options.minHeight && height < options.minHeight) {
103
+ const diff = options.minHeight - height;
104
+ minY -= diff / 2;
105
+ height = options.minHeight;
106
+ }
107
+ const currentAspect = width / Math.max(1, height);
108
+ if (currentAspect < stageAspect) {
109
+ const targetWidth = height * stageAspect;
110
+ const diff = targetWidth - width;
111
+ minX -= diff / 2;
112
+ width = targetWidth;
113
+ } else if (currentAspect > stageAspect) {
114
+ const targetHeight = width / stageAspect;
115
+ const diff = targetHeight - height;
116
+ minY -= diff / 2;
117
+ height = targetHeight;
118
+ }
119
+ return {
120
+ x: minX,
121
+ y: minY,
122
+ width,
123
+ height
124
+ };
125
+ }
126
+ function between(from, to, t, stage) {
127
+ const [x0, y0] = centreOf(from, stage);
128
+ const [x1, y1] = centreOf(to, stage);
129
+ const zoom = from.zoom * Math.pow(to.zoom / from.zoom, t);
130
+ return viewAt(x0 + (x1 - x0) * t, y0 + (y1 - y0) * t, zoom, stage);
131
+ }
132
+ function visibleRect(view, stage) {
133
+ return {
134
+ x: -view.scrollX,
135
+ y: -view.scrollY,
136
+ width: stage.width / view.zoom,
137
+ height: boardHeight(stage) / view.zoom
138
+ };
139
+ }
140
+ var easeInOutCubic = (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
141
+
142
+ export {
143
+ isElementCommand,
144
+ isUpdateCommand,
145
+ isDeleteCommand,
146
+ boundsOf,
147
+ overlapArea,
148
+ areaOf,
149
+ DEFAULT_STAGE,
150
+ CAMERA_MS,
151
+ boardHeight,
152
+ viewAt,
153
+ centreOf,
154
+ frame,
155
+ calculateFramingRect,
156
+ between,
157
+ visibleRect,
158
+ easeInOutCubic
159
+ };
160
+ //# sourceMappingURL=chunk-36DTNSHU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/scene/types.ts","../src/scene/geometry.ts","../src/scene/camera.ts"],"sourcesContent":["import type { Rect, SceneElement } from './geometry.js';\nimport type { Stage } from './camera.js';\nimport type { Effect } from './effects.js';\nimport type { Behavior } from './behavior.js';\nimport type { SceneRig } from './rig.js';\n\n/** Shader or external visual stream in the scene. */\nexport interface SceneMedia {\n type: 'shader' | string;\n source?: string;\n values?: Record<string, unknown>;\n [field: string]: unknown;\n}\n\nexport interface ElementCommand {\n type: 'element';\n element: SceneElement;\n}\n\nexport interface UpdateCommand {\n type: 'update';\n id: string;\n props: Partial<SceneElement>;\n}\n\nexport interface DeleteCommand {\n type: 'delete';\n id: string;\n}\n\nexport interface ClearCommand {\n type: 'clear';\n}\n\nexport interface CustomCommand {\n type: string;\n [key: string]: unknown;\n}\n\n/** A command to add, move, or style elements in a shot. */\nexport type SceneCommand =\n | ElementCommand\n | UpdateCommand\n | DeleteCommand\n | ClearCommand\n | CustomCommand;\n\nexport function isElementCommand(cmd: SceneCommand): cmd is ElementCommand {\n return cmd.type === 'element' && 'element' in cmd && !!cmd.element;\n}\n\nexport function isUpdateCommand(cmd: SceneCommand): cmd is UpdateCommand {\n return cmd.type === 'update' && 'id' in cmd && typeof cmd.id === 'string';\n}\n\nexport function isDeleteCommand(cmd: SceneCommand): cmd is DeleteCommand {\n return cmd.type === 'delete' && 'id' in cmd && typeof cmd.id === 'string';\n}\n\nexport interface DynamicFraming {\n /** Element IDs to frame. */\n frame: string[];\n /** Proportional padding (default 0.15 for 15%). */\n padding?: number;\n /** Minimum width in scene units. */\n minWidth?: number;\n /** Minimum height in scene units. */\n minHeight?: number;\n}\n\nexport type ShotCamera = Rect | DynamicFraming;\n\n/** One beat of a scene: camera framing, title, narration/caption, commands, and procedural effects. */\nexport interface Shot {\n /** Narration / caption spoken or displayed during this beat. */\n caption?: string;\n /** High-level title or callout displayed on screen. */\n title?: string;\n /** Camera framing box in scene units, or dynamic auto-framing target. */\n camera?: ShotCamera;\n /** Pause/dwell duration after this shot's actions run (in milliseconds). Default: 800ms. */\n hold?: number;\n /** Drawing or state change commands played during this shot. */\n run?: SceneCommand[];\n /** Procedural visual effects started in this shot. */\n effects?: Effect[];\n /** IDs of active effects to stop/fade at the start of this shot. */\n stopEffects?: string[];\n /** Continuous procedural parameter and physics behaviors played during this shot. */\n behaviors?: Behavior[];\n}\n\n/** Complete animated scene specification. */\nexport interface Scene {\n name: string;\n title?: string;\n description?: string;\n stage?: Partial<Stage>;\n /** Embedded media (e.g. bespoke WebGL fragment shaders). */\n media?: Record<string, SceneMedia>;\n /** Target duration [minSeconds, maxSeconds]. */\n target?: [number, number];\n /** Interactive macro rigs binding high-level controls to uniforms or element properties. */\n rig?: SceneRig;\n shots: Shot[];\n}\n","export type Point = [number, number];\n\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** An element placed or animated in a scene. */\nexport interface SceneElement {\n id: string;\n type: string;\n x: number;\n y: number;\n width: number;\n height: number;\n points?: readonly (readonly [number, number])[];\n fontSize?: number;\n text?: string;\n containerId?: string | null;\n isDeleted?: boolean;\n opacity?: number;\n}\n\n/** Bounds in scene units, ignoring rotation. */\nexport function boundsOf(e: SceneElement): Rect {\n if (e.points?.length) {\n const xs = e.points.map((p) => e.x + p[0]);\n const ys = e.points.map((p) => e.y + p[1]);\n const x = Math.min(...xs);\n const y = Math.min(...ys);\n return {\n x,\n y,\n width: Math.max(1, Math.max(...xs) - x),\n height: Math.max(1, Math.max(...ys) - y),\n };\n }\n return { x: e.x, y: e.y, width: Math.max(1, e.width), height: Math.max(1, e.height) };\n}\n\n/** Area of the overlap of two rectangles (0 when they do not meet). */\nexport function overlapArea(a: Rect, b: Rect): number {\n const w = Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x);\n const h = Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y);\n return w > 0 && h > 0 ? w * h : 0;\n}\n\nexport const areaOf = (r: Rect): number => r.width * r.height;\n","import { type Rect, type SceneElement, boundsOf } from './geometry.js';\n\nexport interface Stage {\n width: number;\n height: number;\n caption?: number;\n}\n\nexport const DEFAULT_STAGE: Stage = {\n width: 1920,\n height: 1080,\n caption: 0,\n};\n\nexport const CAMERA_MS = 600;\n\n/** Camera view into the scene: drawn at (point + scroll) × zoom. */\nexport interface View {\n zoom: number;\n scrollX: number;\n scrollY: number;\n}\n\nexport const boardHeight = (stage: Stage): number => stage.height - (stage.caption ?? 0);\n\n/** View with `(cx, cy)` in the middle of the board at `zoom`. */\nexport function viewAt(cx: number, cy: number, zoom: number, stage: Stage): View {\n return {\n zoom,\n scrollX: stage.width / (2 * zoom) - cx,\n scrollY: boardHeight(stage) / (2 * zoom) - cy,\n };\n}\n\n/** Scene point in the middle of the board. */\nexport function centreOf(view: View, stage: Stage): [number, number] {\n return [\n stage.width / (2 * view.zoom) - view.scrollX,\n boardHeight(stage) / (2 * view.zoom) - view.scrollY,\n ];\n}\n\n/** The view that fits `rect` on the board, centred and with its aspect kept. */\nexport function frame(rect: Rect, stage: Stage): View {\n if (!(rect.width > 0 && rect.height > 0)) {\n throw new Error('A camera rectangle needs a positive width and height');\n }\n const zoom = Math.min(stage.width / rect.width, boardHeight(stage) / rect.height);\n return viewAt(rect.x + rect.width / 2, rect.y + rect.height / 2, zoom, stage);\n}\n\nexport interface FramingOptions {\n /** Proportional padding added to all sides (e.g., 0.15 for 15%). Default: 0.15 */\n padding?: number;\n /** Minimum width in scene units. */\n minWidth?: number;\n /** Minimum height in scene units. */\n minHeight?: number;\n}\n\n/**\n * Calculates a camera framing rectangle that encloses target elements\n * while preserving the stage aspect ratio and applying optional margin padding.\n */\nexport function calculateFramingRect(\n elements: readonly SceneElement[],\n stage: Stage,\n options: FramingOptions = {},\n): Rect {\n const activeElements = elements.filter((e) => !e.isDeleted);\n const targetH = boardHeight(stage);\n const stageAspect = stage.width / Math.max(1, targetH);\n\n if (activeElements.length === 0) {\n return {\n x: 0,\n y: 0,\n width: stage.width,\n height: targetH,\n };\n }\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n for (const el of activeElements) {\n const b = boundsOf(el);\n if (b.x < minX) minX = b.x;\n if (b.y < minY) minY = b.y;\n if (b.x + b.width > maxX) maxX = b.x + b.width;\n if (b.y + b.height > maxY) maxY = b.y + b.height;\n }\n\n let width = maxX - minX;\n let height = maxY - minY;\n\n // Apply padding (default 15%)\n const padding = options.padding ?? 0.15;\n if (padding > 0) {\n const padX = width * padding;\n const padY = height * padding;\n minX -= padX;\n minY -= padY;\n width += padX * 2;\n height += padY * 2;\n }\n\n // Apply min dimensions\n if (options.minWidth && width < options.minWidth) {\n const diff = options.minWidth - width;\n minX -= diff / 2;\n width = options.minWidth;\n }\n if (options.minHeight && height < options.minHeight) {\n const diff = options.minHeight - height;\n minY -= diff / 2;\n height = options.minHeight;\n }\n\n // Preserve stage aspect ratio centered around midpoint\n const currentAspect = width / Math.max(1, height);\n if (currentAspect < stageAspect) {\n // Taller than stage: expand width\n const targetWidth = height * stageAspect;\n const diff = targetWidth - width;\n minX -= diff / 2;\n width = targetWidth;\n } else if (currentAspect > stageAspect) {\n // Wider than stage: expand height\n const targetHeight = width / stageAspect;\n const diff = targetHeight - height;\n minY -= diff / 2;\n height = targetHeight;\n }\n\n return {\n x: minX,\n y: minY,\n width,\n height,\n };\n}\n\n/**\n * The view part-way (`t` from 0 to 1) from one view to another.\n * Centre moves linearly and zoom scales exponentially for smooth motion.\n */\nexport function between(from: View, to: View, t: number, stage: Stage): View {\n const [x0, y0] = centreOf(from, stage);\n const [x1, y1] = centreOf(to, stage);\n const zoom = from.zoom * Math.pow(to.zoom / from.zoom, t);\n return viewAt(x0 + (x1 - x0) * t, y0 + (y1 - y0) * t, zoom, stage);\n}\n\n/** The part of the scene the camera currently shows. */\nexport function visibleRect(view: View, stage: Stage): Rect {\n return {\n x: -view.scrollX,\n y: -view.scrollY,\n width: stage.width / view.zoom,\n height: boardHeight(stage) / view.zoom,\n };\n}\n\n/** Smooth cubic ease in / ease out. */\nexport const easeInOutCubic = (t: number): number =>\n t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;\n"],"mappings":"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","names":[]}