@viji-dev/core 0.12.0 → 0.14.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.
@@ -0,0 +1,186 @@
1
+ class a {
2
+ /**
3
+ * Detects the renderer type from scene code comments
4
+ *
5
+ * Looks for:
6
+ * - // @renderer shader
7
+ * - /* @renderer shader *\/
8
+ * - // @renderer p5
9
+ * - /* @renderer p5 *\/
10
+ *
11
+ * @param sceneCode - The artist's scene code to analyze
12
+ * @returns The detected renderer type ('shader', 'p5', or 'native')
13
+ */
14
+ static detectRendererType(e) {
15
+ return /\/\/\s*@renderer\s+shader|\/\*\s*@renderer\s+shader\s*\*\//.test(e) ? "shader" : /\/\/\s*@renderer\s+p5|\/\*\s*@renderer\s+p5\s*\*\//.test(e) ? "p5" : "native";
16
+ }
17
+ /**
18
+ * P5 main-canvas mode from the renderer directive (only meaningful when
19
+ * {@link detectRendererType} is `'p5'`).
20
+ *
21
+ * - `// @renderer p5` → 2D (default)
22
+ * - `// @renderer p5 webgl` → WEBGL
23
+ */
24
+ static detectP5CanvasMode(e) {
25
+ return /\/\/\s*@renderer\s+p5\s+webgl\b|\/\*\s*@renderer\s+p5\s+webgl\s*\*\//i.test(
26
+ e
27
+ ) ? "webgl" : "2d";
28
+ }
29
+ /**
30
+ * Detects which engine capabilities the scene's code declares it uses.
31
+ *
32
+ * Static analysis only — the scene is never executed. Comments and string
33
+ * literals are stripped first (so capabilities cannot be spoofed via
34
+ * commented-out code), then capability tokens are matched. Detection is
35
+ * **inclusive-biased**: a capability the scene actually uses is never
36
+ * hidden, but a rarely-ambiguous case may report an extra one (a false
37
+ * "show" is harmless; a false "hide" would break a working scene).
38
+ *
39
+ * - Shader scenes: matched against built-in `u_*` uniform usage (exact).
40
+ * - Native / p5 scenes: matched against `viji.*` usage tokens.
41
+ *
42
+ * @param sceneCode - The artist's scene code to analyze
43
+ * @param renderer - The renderer type (from {@link detectRendererType})
44
+ * @returns The set of capabilities the scene declares it uses
45
+ */
46
+ static detectCapabilities(e, t) {
47
+ const i = this.stripCommentsAndStrings(e), s = {
48
+ audio: !1,
49
+ video: !1,
50
+ mouse: !1,
51
+ keyboard: !1,
52
+ pointer: !1,
53
+ touch: !1,
54
+ parameters: !1,
55
+ sensors: !1,
56
+ devices: !1,
57
+ cv: {
58
+ faceDetection: !1,
59
+ faceMesh: !1,
60
+ emotion: !1,
61
+ handTracking: !1,
62
+ poseDetection: !1,
63
+ segmentation: !1
64
+ }
65
+ };
66
+ return t === "shader" ? this.detectShaderCapabilities(i, s) : this.detectScriptCapabilities(i, s), s;
67
+ }
68
+ /**
69
+ * Replaces comment spans and string/template literals with whitespace via a
70
+ * single forward scan. Robust against the regex-ordering pitfalls of
71
+ * stripping comments and strings independently (a `//` inside a string, or a
72
+ * quote inside a comment). Over-stripping is acceptable for capability
73
+ * detection; under-detection is not.
74
+ */
75
+ static stripCommentsAndStrings(e) {
76
+ let t = "";
77
+ const i = e.length;
78
+ let s = 0;
79
+ for (; s < i; ) {
80
+ const r = e[s], o = s + 1 < i ? e[s + 1] : "";
81
+ if (r === "/" && o === "/") {
82
+ for (s += 2; s < i && e[s] !== `
83
+ `; ) s++;
84
+ continue;
85
+ }
86
+ if (r === "/" && o === "*") {
87
+ for (s += 2; s < i && !(e[s] === "*" && e[s + 1] === "/"); ) s++;
88
+ s += 2, t += " ";
89
+ continue;
90
+ }
91
+ if (r === '"' || r === "'" || r === "`") {
92
+ const u = r;
93
+ for (s++; s < i; ) {
94
+ if (e[s] === "\\") {
95
+ s += 2;
96
+ continue;
97
+ }
98
+ if (e[s] === u) {
99
+ s++;
100
+ break;
101
+ }
102
+ s++;
103
+ }
104
+ t += " ";
105
+ continue;
106
+ }
107
+ t += r, s++;
108
+ }
109
+ return t;
110
+ }
111
+ /**
112
+ * Shader (GLSL) capability detection from built-in `u_*` uniform usage.
113
+ * The uniform-name SOT is `ShaderWorkerAdapter.getBuiltInUniforms()`.
114
+ * The `u_device*` family is suffix-aware: camera uniforms
115
+ * (`u_device0`, `u_device0Resolution/Connected`) map to video+devices,
116
+ * sensor uniforms (`u_device0Acceleration`, …) map to sensors+devices, and
117
+ * the internal-device sensors (`u_deviceAcceleration`, …) map to sensors.
118
+ */
119
+ static detectShaderCapabilities(e, t) {
120
+ /\bu_audio\w*/.test(e) && (t.audio = !0), /\bu_video\w*/.test(e) && (t.video = !0), /\bu_mouse\w*/.test(e) && (t.mouse = !0), /\bu_key\w*/.test(e) && (t.keyboard = !0), /\bu_touch\w*/.test(e) && (t.touch = !0), /\bu_pointer\w*/.test(e) && (t.pointer = !0), /\bu_device(Acceleration|AccelerationGravity|RotationRate|OrientationAbsolute|Orientation)\b/.test(e) && (t.sensors = !0), /\bu_device[0-7](AccelerationGravity|Acceleration|RotationRate|Orientation)\b/.test(e) && (t.sensors = !0, t.devices = !0), /\bu_externalDeviceCount\b/.test(e) && (t.devices = !0, t.sensors = !0), (/\bu_deviceCount\b/.test(e) || /\bu_device[0-7](Resolution|Connected)?\b/.test(e)) && (t.video = !0, t.devices = !0), /\bu_face\w*/.test(e) && (t.cv.faceDetection = !0), /\bu_face0(Neutral|Happy|Sad|Angry|Surprised|Disgusted|Fearful)\b/.test(e) && (t.cv.emotion = !0), (/\bu_face0HeadPose\b/.test(e) || /\bu_videoAnalysed\w*/.test(e) || /\bu_face0(Brow|Cheek|Eye|Jaw|Mouth|Nose|Tongue)\w*/.test(e)) && (t.cv.faceMesh = !0), (/\bu_handCount\b/.test(e) || /\bu_(left|right)Hand\w*/.test(e)) && (t.cv.handTracking = !0), (/\bu_pose\w*/.test(e) || /\bu_(nose|leftShoulder|rightShoulder|leftElbow|rightElbow|leftWrist|rightWrist|leftHip|rightHip|leftKnee|rightKnee|leftAnkle|rightAnkle)Position\b/.test(e)) && (t.cv.poseDetection = !0), /\bu_segmentation\w*/.test(e) && (t.cv.segmentation = !0);
121
+ }
122
+ /**
123
+ * Native / p5 capability detection from `viji.*` usage tokens. CV features
124
+ * are keyed on their canonical `enable*` method names (the canonical
125
+ * signal — a scene must enable a feature to receive its data).
126
+ */
127
+ static detectScriptCapabilities(e, t) {
128
+ /\bviji\.audio/.test(e) && (t.audio = !0), /\bviji\.video/.test(e) && (t.video = !0), /\bviji\.mouse/.test(e) && (t.mouse = !0), /\bviji\.keyboard/.test(e) && (t.keyboard = !0), /\bviji\.touches/.test(e) && (t.touch = !0), /\bviji\.pointer/.test(e) && (t.pointer = !0), /\bviji\.device\b/.test(e) && (t.sensors = !0), /\bviji\.devices/.test(e) && (t.devices = !0), /\bviji\.(slider|color|toggle|select|text|number|image|button|coordinate)\s*\(/.test(e) && (t.parameters = !0), /\benableFaceDetection\b/.test(e) && (t.cv.faceDetection = !0), /\benableFaceMesh\b/.test(e) && (t.cv.faceMesh = !0), /\benableEmotionDetection\b/.test(e) && (t.cv.emotion = !0), /\benableHandTracking\b/.test(e) && (t.cv.handTracking = !0), /\benablePoseDetection\b/.test(e) && (t.cv.poseDetection = !0), /\benableBodySegmentation\b/.test(e) && (t.cv.segmentation = !0);
129
+ }
130
+ /**
131
+ * Detects which specific interaction inputs a scene reads (positions and
132
+ * mouse buttons), for the worker's consumed-meaningfully evaluation. Renderer-
133
+ * aware: shader scenes are read from built-in uniform usage, native/p5 from
134
+ * `mouse.*` / `pointer.*` / `touches.*` member access. Comments/strings are
135
+ * stripped first. Inclusive-biased like {@link detectCapabilities}.
136
+ *
137
+ * @param sceneCode - The artist's scene code to analyze
138
+ * @param renderer - The renderer type (from {@link detectRendererType})
139
+ * @returns The interaction-input usage mask
140
+ */
141
+ /**
142
+ * Whether the scene statically consumes the CV analysed frame. Gates
143
+ * per-sink `analysedFrame` bitmap delivery from the shared CV engine to
144
+ * zero for non-consumers.
145
+ *
146
+ * Three arms, inclusive-biased (over-detection is safe — the sink merely
147
+ * receives bitmaps it ignores; under-detection breaks consumers SILENTLY):
148
+ * - `analysedFrame` / `getAnalysedFrameData` — the JS surface
149
+ * (native / p5 scenes, any stream).
150
+ * - `u_videoAnalysed*` — the SHADER arm: GLSL scenes consume the
151
+ * analysed frame as a texture bound by ShaderWorkerAdapter and never
152
+ * contain the JS names; without this arm they would be classified as
153
+ * non-consumers and permanently sample the 1×1 black fallback.
154
+ * (Same source pattern as the capability mapping above, which routes
155
+ * `u_videoAnalysed*` to `cv.faceMesh` — this is a separate consumer
156
+ * flag, NOT a capability: it must not move cohort keys.)
157
+ *
158
+ * @param sceneCode - The artist's scene code to analyze
159
+ * @returns true when the scene reads the analysed frame
160
+ */
161
+ static detectAnalysedFrameUse(e) {
162
+ const t = this.stripCommentsAndStrings(e);
163
+ return /\b(analysedFrame|getAnalysedFrameData)\b/.test(t) || /\bu_videoAnalysed\w*/.test(t);
164
+ }
165
+ static detectUsage(e, t) {
166
+ const i = this.stripCommentsAndStrings(e), s = {
167
+ mouse: { position: !1, left: !1, right: !1, middle: !1 },
168
+ pointer: { position: !1, down: !1 },
169
+ touch: !1
170
+ };
171
+ return t === "shader" ? (s.mouse.position = /\bu_mouse(\b|InCanvas|Delta|Wheel)/.test(i), s.mouse.left = /\bu_mouse(Left|Pressed|WasPressed|WasReleased)\b/.test(i), s.mouse.right = /\bu_mouseRight\b/.test(i), s.mouse.middle = /\bu_mouseMiddle\b/.test(i), s.pointer.position = /\bu_pointer(\b|Delta|InCanvas)/.test(i), s.pointer.down = /\bu_pointer(Down|WasPressed|WasReleased)\b/.test(i), s.touch = /\bu_touch/.test(i)) : (s.mouse.position = /\bmouse\.(x|y|deltaX|deltaY|wheelDelta|wheelX|wheelY|wasMoved)\b/.test(i), s.mouse.left = /\bmouse\.(leftButton|isPressed|wasPressed|wasReleased)\b/.test(i), s.mouse.right = /\bmouse\.rightButton\b/.test(i), s.mouse.middle = /\bmouse\.middleButton\b/.test(i), s.pointer.position = /\bpointer\.(x|y|deltaX|deltaY)\b/.test(i), s.pointer.down = /\bpointer\.(isDown|wasPressed|wasReleased)\b/.test(i), s.touch = /\btouches\./.test(i)), s;
172
+ }
173
+ }
174
+ function b(n) {
175
+ const e = a.detectRendererType(n), t = e === "p5" ? a.detectP5CanvasMode(n) : void 0;
176
+ return {
177
+ renderer: e,
178
+ ...t !== void 0 && { p5CanvasMode: t },
179
+ capabilities: a.detectCapabilities(n, e),
180
+ consumesAnalysedFrame: a.detectAnalysedFrameUse(n)
181
+ };
182
+ }
183
+ export {
184
+ a as S,
185
+ b as a
186
+ };
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Full static scene analysis — everything the worker's `scene-analysis` ack
3
+ * carries, computed without constructing a core. Composes the same four
4
+ * statics the worker runs in phase 1 of scene load ({@link
5
+ * SceneAnalyzer.detectRendererType} → {@link SceneAnalyzer.detectP5CanvasMode}
6
+ * → {@link SceneAnalyzer.detectCapabilities} → {@link
7
+ * SceneAnalyzer.detectAnalysedFrameUse}), and the worker itself consumes this
8
+ * function to build the ack — so for a given core version the result is the
9
+ * exact payload a booted core's `initialize()` resolves its scene analysis
10
+ * with. Parity holds through shared code, not parallel composition.
11
+ *
12
+ * Intended for out-of-engine consumers (e.g. server-side persistence of
13
+ * per-scene capabilities; migration tooling that needs the renderer without
14
+ * booting a core). The following properties are an intentional, kept
15
+ * contract, covering all four fields:
16
+ * - **Pure and Node-safe** — static analysis only; the scene is never
17
+ * executed and no DOM, canvas, or worker API is touched. Callable in a
18
+ * bare Node process.
19
+ * - **Deterministic** — same code string, same result, within a core version.
20
+ * - **Raw-code input** — `renderer` and `p5CanvasMode` are comment-directive
21
+ * scans over the artist's original source, before any transpilation (the
22
+ * worker applies sucrase only after this analysis, and only to script
23
+ * scenes). Pass stored scene code as-is.
24
+ * - **Inclusive-biased** (`capabilities`) — a capability the scene uses is
25
+ * never hidden; a rare ambiguous case may report an extra one.
26
+ * - **Safe on untrusted input** — linear-time scans and regexes with no
27
+ * throw paths on any string input.
28
+ *
29
+ * `p5CanvasMode` is present only when `renderer` is `'p5'`, mirroring the
30
+ * ack shape exactly.
31
+ *
32
+ * Note for consumers filtering on `capabilities.video`: the flag means the
33
+ * scene reads the video *image* (pixels/texture). Shader scenes that consume
34
+ * only CV result uniforms report `cv.*` without `video`, so a "reacts to the
35
+ * camera" filter should test `video || any cv key`.
36
+ *
37
+ * @param sceneCode - The artist's scene code (native, p5, or shader), raw
38
+ * @returns The complete static analysis — the worker's ack payload
39
+ * @example
40
+ * ```ts
41
+ * const analysis = analyzeScene(scene.code);
42
+ * if (analysis.renderer === 'shader') return skip(scene);
43
+ * if (analysis.capabilities.audio) tags.push('audio');
44
+ * ```
45
+ */
46
+ export declare function analyzeScene(sceneCode: string): SceneAnalysisData;
47
+
48
+ /**
49
+ * P5 main-canvas mode. Only meaningful when {@link SceneData.renderer} is
50
+ * `'p5'`: `'2d'` for the default 2D canvas, `'webgl'` for a WEBGL canvas.
51
+ */
52
+ declare type P5CanvasMode = '2d' | 'webgl';
53
+
54
+ declare type RendererType = 'native' | 'p5' | 'shader';
55
+
56
+ /**
57
+ * Payload of the worker's `scene-analysis` ack — the correlated response to
58
+ * `set-scene-code`. The worker runs static analysis (renderer, capabilities,
59
+ * p5 canvas mode, analysedFrame consumption) after receiving the scene code
60
+ * and **before** compiling it, and the host's `initialize()` awaits this ack
61
+ * to assign the four `SceneData` fields exactly once. Carries booleans/enums
62
+ * only — never scene source.
63
+ *
64
+ * Public since 0.14.0: this is also the return type of `analyzeScene`
65
+ * (`@viji-dev/core/scene-analysis`), which the worker itself calls to build
66
+ * the ack — one shape, one producer, two transports.
67
+ */
68
+ declare interface SceneAnalysisData {
69
+ /** Detected renderer the scene targets. */
70
+ renderer: RendererType;
71
+ /** P5 canvas mode; present only when `renderer` is `'p5'`. */
72
+ p5CanvasMode?: P5CanvasMode;
73
+ /** Capabilities the scene's code declares it uses (inclusive-biased). */
74
+ capabilities: SceneCapabilities;
75
+ /** Whether the scene consumes per-frame analysed-frame bitmaps (CV). */
76
+ consumesAnalysedFrame: boolean;
77
+ }
78
+
79
+ /**
80
+ * The set of engine capabilities a scene's code declares it uses, derived by
81
+ * static analysis of the scene source (no execution). Detection is
82
+ * **inclusive-biased**: a capability the scene actually uses is never hidden,
83
+ * but a rarely-ambiguous case may show an extra one. Shader scenes are
84
+ * detected from built-in uniform usage (exact); native/p5 scenes from
85
+ * `viji.*` usage tokens.
86
+ *
87
+ * The input keys here are pinned to {@link INPUT_CAPABILITY_KEYS} and the `cv`
88
+ * keys to {@link CV_FEATURE_KEYS} by a compile-time guard (below), so this shape
89
+ * cannot drift from the runtime vocabulary.
90
+ */
91
+ declare interface SceneCapabilities {
92
+ /** Scene reads audio analysis (volume, bands, beat, FFT/waveform, or audio streams). */
93
+ audio: boolean;
94
+ /** Scene reads video input (camera frame, video streams, or device cameras). */
95
+ video: boolean;
96
+ /** Scene reads mouse state. */
97
+ mouse: boolean;
98
+ /** Scene reads keyboard state. */
99
+ keyboard: boolean;
100
+ /** Scene reads the unified pointer (mouse/touch) state. */
101
+ pointer: boolean;
102
+ /** Scene reads multi-touch state. */
103
+ touch: boolean;
104
+ /** Scene declares tunable parameters. */
105
+ parameters: boolean;
106
+ /** Scene reads internal device motion/orientation sensors (`viji.device`). */
107
+ sensors: boolean;
108
+ /** Scene reads external connected devices (`viji.devices`). */
109
+ devices: boolean;
110
+ /** Per-feature computer-vision usage. */
111
+ cv: {
112
+ /** Scene uses face detection (bounding boxes). */
113
+ faceDetection: boolean;
114
+ /** Scene uses face mesh / landmarks / blendshapes. */
115
+ faceMesh: boolean;
116
+ /** Scene uses emotion / expression detection. */
117
+ emotion: boolean;
118
+ /** Scene uses hand tracking. */
119
+ handTracking: boolean;
120
+ /** Scene uses body pose detection. */
121
+ poseDetection: boolean;
122
+ /** Scene uses body segmentation. */
123
+ segmentation: boolean;
124
+ };
125
+ }
126
+
127
+ export { }
@@ -0,0 +1,4 @@
1
+ import { a as n } from "./scene-analysis-CEQRlNUL.js";
2
+ export {
3
+ n as analyzeScene
4
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viji-dev/core",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Universal execution engine for Viji Creative scenes",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -12,6 +12,15 @@
12
12
  "import": "./dist/index.js",
13
13
  "types": "./dist/index.d.ts"
14
14
  },
15
+ "./scene-analysis": {
16
+ "import": "./dist/scene-analysis.js",
17
+ "types": "./dist/scene-analysis.d.ts"
18
+ },
19
+ "./param-inference": {
20
+ "import": "./dist/param-inference.js",
21
+ "types": "./dist/param-inference.d.ts"
22
+ },
23
+ "./package.json": "./package.json",
15
24
  "./artist-global": {
16
25
  "types": "./dist/artist-global.d.ts"
17
26
  },
@@ -49,6 +58,7 @@
49
58
  "README.md"
50
59
  ],
51
60
  "scripts": {
61
+ "audio-lab": "vite --config audio-lab/vite.config.mjs",
52
62
  "prebuild": "node scripts/prebuild-clean.mjs && node scripts/sync-version.mjs",
53
63
  "version": "npm run build && git add -A",
54
64
  "build": "vite build && node scripts/copy-tasks-assets.mjs && node scripts/minify-dist.mjs && node scripts/build-artist-types.mjs && node scripts/lint-artist-types-drift.mjs && node scripts/build-docs-api.mjs",