@viji-dev/core 0.12.0 → 0.13.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,181 @@
1
+ class o {
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 s = this.stripCommentsAndStrings(e), i = {
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(s, i) : this.detectScriptCapabilities(s, i), i;
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 s = e.length;
78
+ let i = 0;
79
+ for (; i < s; ) {
80
+ const r = e[i], a = i + 1 < s ? e[i + 1] : "";
81
+ if (r === "/" && a === "/") {
82
+ for (i += 2; i < s && e[i] !== `
83
+ `; ) i++;
84
+ continue;
85
+ }
86
+ if (r === "/" && a === "*") {
87
+ for (i += 2; i < s && !(e[i] === "*" && e[i + 1] === "/"); ) i++;
88
+ i += 2, t += " ";
89
+ continue;
90
+ }
91
+ if (r === '"' || r === "'" || r === "`") {
92
+ const u = r;
93
+ for (i++; i < s; ) {
94
+ if (e[i] === "\\") {
95
+ i += 2;
96
+ continue;
97
+ }
98
+ if (e[i] === u) {
99
+ i++;
100
+ break;
101
+ }
102
+ i++;
103
+ }
104
+ t += " ";
105
+ continue;
106
+ }
107
+ t += r, i++;
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 s = this.stripCommentsAndStrings(e), i = {
167
+ mouse: { position: !1, left: !1, right: !1, middle: !1 },
168
+ pointer: { position: !1, down: !1 },
169
+ touch: !1
170
+ };
171
+ return t === "shader" ? (i.mouse.position = /\bu_mouse(\b|InCanvas|Delta|Wheel)/.test(s), i.mouse.left = /\bu_mouse(Left|Pressed|WasPressed|WasReleased)\b/.test(s), i.mouse.right = /\bu_mouseRight\b/.test(s), i.mouse.middle = /\bu_mouseMiddle\b/.test(s), i.pointer.position = /\bu_pointer(\b|Delta|InCanvas)/.test(s), i.pointer.down = /\bu_pointer(Down|WasPressed|WasReleased)\b/.test(s), i.touch = /\bu_touch/.test(s)) : (i.mouse.position = /\bmouse\.(x|y|deltaX|deltaY|wheelDelta|wheelX|wheelY|wasMoved)\b/.test(s), i.mouse.left = /\bmouse\.(leftButton|isPressed|wasPressed|wasReleased)\b/.test(s), i.mouse.right = /\bmouse\.rightButton\b/.test(s), i.mouse.middle = /\bmouse\.middleButton\b/.test(s), i.pointer.position = /\bpointer\.(x|y|deltaX|deltaY)\b/.test(s), i.pointer.down = /\bpointer\.(isDown|wasPressed|wasReleased)\b/.test(s), i.touch = /\btouches\./.test(s)), i;
172
+ }
173
+ }
174
+ function b(n) {
175
+ const e = o.detectRendererType(n);
176
+ return o.detectCapabilities(n, e);
177
+ }
178
+ export {
179
+ o as S,
180
+ b as a
181
+ };
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Analyzes a scene's source code and returns the capabilities it declares,
3
+ * without constructing a core. Composes {@link SceneAnalyzer.detectRendererType}
4
+ * and {@link SceneAnalyzer.detectCapabilities} — the same two steps `VijiCore`
5
+ * performs at construction — so for a given core version the result is
6
+ * identical to a booted core's `getSceneData().capabilities`.
7
+ *
8
+ * Intended for out-of-engine consumers (e.g. server-side persistence of
9
+ * per-scene capabilities). The following properties are an intentional, kept
10
+ * contract:
11
+ * - **Pure and Node-safe** — static analysis only; the scene is never executed
12
+ * and no DOM, canvas, or worker API is touched. Callable in a bare Node
13
+ * process.
14
+ * - **Deterministic** — same code string, same result, within a core version.
15
+ * - **Inclusive-biased** — a capability the scene uses is never hidden; a
16
+ * rare ambiguous case may report an extra one.
17
+ * - **Safe on untrusted input** — linear-time scan and regexes with no throw
18
+ * paths on any string input.
19
+ *
20
+ * Note for consumers filtering on `video`: the flag means the scene reads the
21
+ * video *image* (pixels/texture). Shader scenes that consume only CV result
22
+ * uniforms report `cv.*` without `video`, so a "reacts to the camera" filter
23
+ * should test `video || any cv key`.
24
+ *
25
+ * @param sceneCode - The artist's scene code (native, p5, or shader)
26
+ * @returns The set of capabilities the scene declares it uses
27
+ * @example
28
+ * ```ts
29
+ * const caps = analyzeSceneCapabilities(scene.code);
30
+ * if (caps.audio) tags.push('audio');
31
+ * ```
32
+ */
33
+ export declare function analyzeSceneCapabilities(sceneCode: string): SceneCapabilities;
34
+
35
+ /**
36
+ * The set of engine capabilities a scene's code declares it uses, derived by
37
+ * static analysis of the scene source (no execution). Detection is
38
+ * **inclusive-biased**: a capability the scene actually uses is never hidden,
39
+ * but a rarely-ambiguous case may show an extra one. Shader scenes are
40
+ * detected from built-in uniform usage (exact); native/p5 scenes from
41
+ * `viji.*` usage tokens.
42
+ *
43
+ * The input keys here are pinned to {@link INPUT_CAPABILITY_KEYS} and the `cv`
44
+ * keys to {@link CV_FEATURE_KEYS} by a compile-time guard (below), so this shape
45
+ * cannot drift from the runtime vocabulary.
46
+ */
47
+ declare interface SceneCapabilities {
48
+ /** Scene reads audio analysis (volume, bands, beat, FFT/waveform, or audio streams). */
49
+ audio: boolean;
50
+ /** Scene reads video input (camera frame, video streams, or device cameras). */
51
+ video: boolean;
52
+ /** Scene reads mouse state. */
53
+ mouse: boolean;
54
+ /** Scene reads keyboard state. */
55
+ keyboard: boolean;
56
+ /** Scene reads the unified pointer (mouse/touch) state. */
57
+ pointer: boolean;
58
+ /** Scene reads multi-touch state. */
59
+ touch: boolean;
60
+ /** Scene declares tunable parameters. */
61
+ parameters: boolean;
62
+ /** Scene reads internal device motion/orientation sensors (`viji.device`). */
63
+ sensors: boolean;
64
+ /** Scene reads external connected devices (`viji.devices`). */
65
+ devices: boolean;
66
+ /** Per-feature computer-vision usage. */
67
+ cv: {
68
+ /** Scene uses face detection (bounding boxes). */
69
+ faceDetection: boolean;
70
+ /** Scene uses face mesh / landmarks / blendshapes. */
71
+ faceMesh: boolean;
72
+ /** Scene uses emotion / expression detection. */
73
+ emotion: boolean;
74
+ /** Scene uses hand tracking. */
75
+ handTracking: boolean;
76
+ /** Scene uses body pose detection. */
77
+ poseDetection: boolean;
78
+ /** Scene uses body segmentation. */
79
+ segmentation: boolean;
80
+ };
81
+ }
82
+
83
+ export { }
@@ -0,0 +1,4 @@
1
+ import { a as i } from "./scene-analysis-DNN8jTaH.js";
2
+ export {
3
+ i as analyzeSceneCapabilities
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.13.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",