@nexart/codemode-sdk 1.1.0 → 1.1.1

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 (88) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/CODE_MODE_PROTOCOL.md +312 -0
  3. package/README.md +200 -58
  4. package/dist/core-index.d.ts +21 -0
  5. package/dist/core-index.d.ts.map +1 -0
  6. package/dist/core-index.js +26 -0
  7. package/dist/execute.d.ts +46 -0
  8. package/dist/execute.d.ts.map +1 -0
  9. package/dist/execute.js +268 -0
  10. package/dist/index.d.ts +36 -17
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +43 -17
  13. package/dist/loop-engine.d.ts +4 -1
  14. package/dist/loop-engine.d.ts.map +1 -1
  15. package/dist/loop-engine.js +17 -12
  16. package/dist/noise-bridge.d.ts +44 -0
  17. package/dist/noise-bridge.d.ts.map +1 -0
  18. package/dist/noise-bridge.js +68 -0
  19. package/dist/noise-engine.d.ts +74 -0
  20. package/dist/noise-engine.d.ts.map +1 -0
  21. package/dist/noise-engine.js +132 -0
  22. package/dist/noise-sketches/fractalNoise.d.ts +11 -0
  23. package/dist/noise-sketches/fractalNoise.d.ts.map +1 -0
  24. package/dist/noise-sketches/fractalNoise.js +121 -0
  25. package/dist/noise-sketches/index.d.ts +21 -0
  26. package/dist/noise-sketches/index.d.ts.map +1 -0
  27. package/dist/noise-sketches/index.js +28 -0
  28. package/dist/p5-runtime.d.ts +56 -4
  29. package/dist/p5-runtime.d.ts.map +1 -1
  30. package/dist/p5-runtime.js +348 -22
  31. package/dist/sound-bridge.d.ts +89 -0
  32. package/dist/sound-bridge.d.ts.map +1 -0
  33. package/dist/sound-bridge.js +128 -0
  34. package/dist/soundart-engine.d.ts +87 -0
  35. package/dist/soundart-engine.d.ts.map +1 -0
  36. package/dist/soundart-engine.js +173 -0
  37. package/dist/soundart-sketches/chladniBloom.d.ts +3 -0
  38. package/dist/soundart-sketches/chladniBloom.d.ts.map +1 -0
  39. package/dist/soundart-sketches/chladniBloom.js +53 -0
  40. package/dist/soundart-sketches/dualVortex.d.ts +3 -0
  41. package/dist/soundart-sketches/dualVortex.d.ts.map +1 -0
  42. package/dist/soundart-sketches/dualVortex.js +67 -0
  43. package/dist/soundart-sketches/geometryIllusion.d.ts +3 -0
  44. package/dist/soundart-sketches/geometryIllusion.d.ts.map +1 -0
  45. package/dist/soundart-sketches/geometryIllusion.js +89 -0
  46. package/dist/soundart-sketches/index.d.ts +39 -0
  47. package/dist/soundart-sketches/index.d.ts.map +1 -0
  48. package/dist/soundart-sketches/index.js +72 -0
  49. package/dist/soundart-sketches/isoflow.d.ts +3 -0
  50. package/dist/soundart-sketches/isoflow.d.ts.map +1 -0
  51. package/dist/soundart-sketches/isoflow.js +60 -0
  52. package/dist/soundart-sketches/loomWeave.d.ts +3 -0
  53. package/dist/soundart-sketches/loomWeave.d.ts.map +1 -0
  54. package/dist/soundart-sketches/loomWeave.js +59 -0
  55. package/dist/soundart-sketches/noiseTerraces.d.ts +3 -0
  56. package/dist/soundart-sketches/noiseTerraces.d.ts.map +1 -0
  57. package/dist/soundart-sketches/noiseTerraces.js +53 -0
  58. package/dist/soundart-sketches/orb.d.ts +3 -0
  59. package/dist/soundart-sketches/orb.d.ts.map +1 -0
  60. package/dist/soundart-sketches/orb.js +50 -0
  61. package/dist/soundart-sketches/pixelGlyphs.d.ts +3 -0
  62. package/dist/soundart-sketches/pixelGlyphs.d.ts.map +1 -0
  63. package/dist/soundart-sketches/pixelGlyphs.js +72 -0
  64. package/dist/soundart-sketches/prismFlowFields.d.ts +3 -0
  65. package/dist/soundart-sketches/prismFlowFields.d.ts.map +1 -0
  66. package/dist/soundart-sketches/prismFlowFields.js +51 -0
  67. package/dist/soundart-sketches/radialBurst.d.ts +3 -0
  68. package/dist/soundart-sketches/radialBurst.d.ts.map +1 -0
  69. package/dist/soundart-sketches/radialBurst.js +60 -0
  70. package/dist/soundart-sketches/resonantSoundBodies.d.ts +3 -0
  71. package/dist/soundart-sketches/resonantSoundBodies.d.ts.map +1 -0
  72. package/dist/soundart-sketches/resonantSoundBodies.js +89 -0
  73. package/dist/soundart-sketches/rings.d.ts +11 -0
  74. package/dist/soundart-sketches/rings.d.ts.map +1 -0
  75. package/dist/soundart-sketches/rings.js +89 -0
  76. package/dist/soundart-sketches/squares.d.ts +3 -0
  77. package/dist/soundart-sketches/squares.d.ts.map +1 -0
  78. package/dist/soundart-sketches/squares.js +52 -0
  79. package/dist/soundart-sketches/waveStripes.d.ts +3 -0
  80. package/dist/soundart-sketches/waveStripes.d.ts.map +1 -0
  81. package/dist/soundart-sketches/waveStripes.js +44 -0
  82. package/dist/static-engine.d.ts +4 -1
  83. package/dist/static-engine.d.ts.map +1 -1
  84. package/dist/static-engine.js +13 -8
  85. package/dist/types.d.ts +75 -1
  86. package/dist/types.d.ts.map +1 -1
  87. package/dist/types.js +19 -1
  88. package/package.json +23 -17
package/README.md CHANGED
@@ -104,7 +104,8 @@ The SDK enforces the **NexArt Code Mode Protocol v1.0.0** for reproducible, mint
104
104
  ## Installation
105
105
 
106
106
  ```bash
107
- npm install @nexart/codemode-sdk
107
+ # Copy the sdk/codemode folder to your project
108
+ cp -r sdk/codemode your-project/lib/codemode
108
109
  ```
109
110
 
110
111
  ---
@@ -152,7 +153,7 @@ console.log(result.image); // PNG Blob
152
153
  | `width` | `number` | ✅ | Canvas width in pixels |
153
154
  | `height` | `number` | ✅ | Canvas height in pixels |
154
155
  | `seed` | `number` | ✅ | Seed for deterministic randomness |
155
- | `vars` | `number[]` | ❌ | VAR values (0-10 elements, 0-100 range), missing indices return 0 |
156
+ | `vars` | `number[]` | ❌ | VAR[0..9] values (0-100), defaults to all zeros |
156
157
  | `mode` | `'static' \| 'loop'` | ✅ | Execution mode |
157
158
  | `totalFrames` | `number` | ⚠️ | Required for loop mode |
158
159
 
@@ -181,7 +182,63 @@ interface ExecuteCodeModeResult {
181
182
 
182
183
  ---
183
184
 
184
- ## Protocol Variables (VAR[0..9]) — Protocol v1.0.0
185
+ ## Legacy API
186
+
187
+ > ⚠️ **Note**: The `createEngine()` API is still supported but new implementations should use `executeCodeMode()`.
188
+
189
+ ### `createEngine(config: EngineConfig): Engine`
190
+
191
+ Create a rendering engine instance.
192
+
193
+ ```typescript
194
+ import { createEngine } from './codemode';
195
+
196
+ const engine = createEngine({
197
+ mode: 'static', // 'static' | 'loop'
198
+ width: 1950, // Optional, default: 1950
199
+ height: 2400, // Optional, default: 2400
200
+ duration: 2, // Loop mode only, 1-4 seconds
201
+ fps: 30, // Loop mode only, default: 30
202
+ });
203
+ ```
204
+
205
+ ### `engine.run(options: RunOptions): Promise<void>`
206
+
207
+ Execute code and produce output.
208
+
209
+ ```typescript
210
+ await engine.run({
211
+ code: `
212
+ function setup() {
213
+ background(255);
214
+ fill(0);
215
+ // Use VAR for external control
216
+ let size = map(VAR[0], 0, 100, 50, 200);
217
+ ellipse(width/2, height/2, size);
218
+ }
219
+ `,
220
+ seed: 12345, // Optional: seed for deterministic randomness
221
+ vars: [50, 75, 0, 0, 0, 0, 0, 0, 0, 0], // Optional: VAR[0..9] values (0-100)
222
+ onPreview: (canvas) => {
223
+ // Optional: called with canvas after first frame
224
+ },
225
+ onProgress: (info) => {
226
+ // Optional: progress updates
227
+ console.log(info.message, info.percent + '%');
228
+ },
229
+ onComplete: (result) => {
230
+ // Required: called with final result
231
+ console.log(result.type); // 'image' | 'video'
232
+ console.log(result.blob); // Blob
233
+ },
234
+ onError: (error) => {
235
+ // Optional: called on error
236
+ console.error(error);
237
+ },
238
+ });
239
+ ```
240
+
241
+ ### Protocol Variables (VAR[0..9]) — Protocol v1.0.0
185
242
 
186
243
  Protocol variables are first-class inputs that control artwork parameters.
187
244
 
@@ -199,7 +256,20 @@ Protocol variables are first-class inputs that control artwork parameters.
199
256
  | Default | All zeros | If not provided |
200
257
 
201
258
  ```typescript
202
- // Access in sketch code (missing indices return 0)
259
+ // Pass values when running (0-10 elements)
260
+ await engine.run({
261
+ code: myCode,
262
+ vars: [80, 50, 25], // VAR[0]=80, VAR[1]=50, VAR[2]=25, VAR[3..9]=0
263
+ onComplete: (result) => { /* ... */ },
264
+ });
265
+
266
+ // Or omit entirely (all zeros)
267
+ await engine.run({
268
+ code: myCode,
269
+ onComplete: (result) => { /* ... */ },
270
+ });
271
+
272
+ // Access in sketch code
203
273
  function setup() {
204
274
  let density = map(VAR[0], 0, 100, 10, 200);
205
275
  let speed = map(VAR[1], 0, 100, 0.5, 5);
@@ -215,6 +285,14 @@ function setup() {
215
285
  - Values MUST be in range 0-100 (throws if out of range)
216
286
  - Same code + same seed + same VARs = identical output
217
287
 
288
+ ### `engine.stop(): void`
289
+
290
+ Cancel a running render (Loop mode only).
291
+
292
+ ### `engine.getConfig(): EngineConfig`
293
+
294
+ Get the resolved engine configuration.
295
+
218
296
  ---
219
297
 
220
298
  ## Execution Rules
@@ -270,6 +348,76 @@ Additionally in Loop Mode:
270
348
 
271
349
  ---
272
350
 
351
+ ## Example: Static Mode
352
+
353
+ ```typescript
354
+ import { createEngine } from './codemode';
355
+
356
+ const engine = createEngine({ mode: 'static' });
357
+
358
+ await engine.run({
359
+ code: `
360
+ function setup() {
361
+ background(30);
362
+ noStroke();
363
+ for (let i = 0; i < 100; i++) {
364
+ fill(random(255), random(255), random(255));
365
+ ellipse(random(width), random(height), 50);
366
+ }
367
+ }
368
+ `,
369
+ onComplete: (result) => {
370
+ // result.type === 'image'
371
+ // result.blob is a PNG Blob
372
+ const url = URL.createObjectURL(result.blob);
373
+ document.body.innerHTML = `<img src="${url}" />`;
374
+ },
375
+ });
376
+ ```
377
+
378
+ ---
379
+
380
+ ## Example: Loop Mode
381
+
382
+ ```typescript
383
+ import { createEngine } from './codemode';
384
+
385
+ const engine = createEngine({
386
+ mode: 'loop',
387
+ duration: 2, // 2 second loop
388
+ });
389
+
390
+ await engine.run({
391
+ code: `
392
+ function setup() {
393
+ // Called once
394
+ }
395
+
396
+ function draw() {
397
+ background(30);
398
+
399
+ // t goes from 0 to 1 over the loop duration
400
+ let x = width/2 + cos(t * TWO_PI) * 200;
401
+ let y = height/2 + sin(t * TWO_PI) * 200;
402
+
403
+ fill(255);
404
+ ellipse(x, y, 80);
405
+ }
406
+ `,
407
+ onProgress: (info) => {
408
+ console.log(info.message);
409
+ },
410
+ onComplete: (result) => {
411
+ // result.type === 'video'
412
+ // result.blob is an MP4 Blob
413
+ const url = URL.createObjectURL(result.blob);
414
+ document.body.innerHTML = `<video src="${url}" autoplay loop />`;
415
+ },
416
+ });
417
+ ```
418
+
419
+ ---
420
+
273
421
  ## Supported Functions
274
422
 
275
423
  The SDK includes a minimal p5.js-like runtime with:
@@ -310,21 +458,38 @@ All of the following are accepted by `fill()`, `stroke()`, `background()`:
310
458
 
311
459
  ---
312
460
 
313
- ## Frozen Execution Guarantees — v1.0.0
461
+ ## Video Encoding
314
462
 
315
- The following guarantees are LOCKED and will not change in v1.x:
463
+ Loop Mode requires server-side video encoding. The SDK calls:
316
464
 
317
- | Guarantee | Description |
318
- |-----------|-------------|
319
- | Determinism | Same code + same seed + same VARs = identical output |
320
- | Static Mode | `setup()` only, single PNG output |
321
- | Loop Mode | Frame-authoritative, `draw()` per frame, MP4 output |
322
- | Time Semantics | `t` ∈ [0,1), `frameCount` ∈ [0,totalFrames), `time` in seconds |
323
- | Random | Seeded Mulberry32 PRNG via `random()` |
324
- | Noise | Seeded Perlin noise via `noise()` |
325
- | Canvas | Pre-initialized, no `createCanvas()` |
326
- | VAR | Exactly 10 read-only protocol variables |
327
- | Forbidden Patterns | 13 patterns rejected (see above) |
465
+ ```
466
+ POST /api/encode-loop
467
+ ```
468
+
469
+ Ensure your server has this endpoint available (NexArt provides this).
470
+
471
+ ---
472
+
473
+ ## Files
474
+
475
+ ```
476
+ sdk/codemode/
477
+ ├── index.ts # Main export
478
+ ├── engine.ts # createEngine entry point
479
+ ├── types.ts # TypeScript types
480
+ ├── static-engine.ts # Static mode implementation
481
+ ├── loop-engine.ts # Loop mode implementation
482
+ ├── p5-runtime.ts # p5.js-like runtime
483
+ └── README.md # This file
484
+ ```
485
+
486
+ ---
487
+
488
+ ## License
489
+
490
+ MIT License
491
+
492
+ Copyright (c) 2024 NexArt
328
493
 
329
494
  ---
330
495
 
@@ -373,50 +538,27 @@ try {
373
538
 
374
539
  ---
375
540
 
376
- ## Video Encoding
377
-
378
- Loop Mode requires server-side video encoding. The SDK calls:
379
-
380
- ```
381
- POST /api/encode-loop
382
- ```
383
-
384
- Ensure your server has this endpoint available (NexArt provides this).
385
-
386
- ---
387
-
388
- ## Files
389
-
390
- ```
391
- @nexart/codemode-sdk/
392
- ├── index.ts # Main export
393
- ├── engine.ts # createEngine entry point
394
- ├── execute.ts # Canonical executeCodeMode API
395
- ├── types.ts # TypeScript types
396
- ├── static-engine.ts # Static mode implementation
397
- ├── loop-engine.ts # Loop mode implementation
398
- ├── p5-runtime.ts # p5.js-like runtime
399
- └── README.md # This file
400
- ```
401
-
402
- ---
403
-
404
- ## Changelog
405
-
406
- **1.0.2** — VAR is now optional (0-10 elements). Missing indices return 0. Out-of-range throws.
407
-
408
- **1.0.1** — Protocol Lock formalized. VAR specification clarified. CHANGELOG added.
409
-
410
- **1.0.0** — Protocol Lock. Phase 1 execution surface HARD LOCKED. executeCodeMode() canonical API.
541
+ ## Frozen Execution Guarantees — v1.0.0
411
542
 
412
- **0.1.1** Fixed beginShape / vertex / endShape rendering bug.
543
+ The following guarantees are LOCKED and will not change in v1.x:
413
544
 
414
- **0.1.0** Initial release.
545
+ | Guarantee | Description |
546
+ |-----------|-------------|
547
+ | Determinism | Same code + same seed + same VARs = identical output |
548
+ | Static Mode | `setup()` only, single PNG output |
549
+ | Loop Mode | Frame-authoritative, `draw()` per frame, MP4 output |
550
+ | Time Semantics | `t` ∈ [0,1), `frameCount` ∈ [0,totalFrames), `time` in seconds |
551
+ | Random | Seeded Mulberry32 PRNG via `random()` |
552
+ | Noise | Seeded Perlin noise via `noise()` |
553
+ | Canvas | Pre-initialized, no `createCanvas()` |
554
+ | VAR | Exactly 10 read-only protocol variables |
555
+ | Forbidden Patterns | 13 patterns rejected (see above) |
415
556
 
416
557
  ---
417
558
 
418
- ## License
419
-
420
- MIT License
559
+ ## Future Work (Phase 2+)
421
560
 
422
- Copyright (c) 2024 NexArt
561
+ - GSL v1 SDK (protocol layer) separate package
562
+ - Extended p5.js compatibility
563
+ - WebGL rendering support
564
+ - GIF output option
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @nexart/codemode-sdk v1.1.0 — Core Exports
3
+ *
4
+ * Canonical execution engine for NexArt Code Mode.
5
+ * This is the single source of truth for Code Mode semantics.
6
+ *
7
+ * Protocol: v1.0.0 (LOCKED)
8
+ * Enforcement: HARD
9
+ */
10
+ export { executeCodeMode, validateCodeModeSource, } from './execute';
11
+ export { type RenderMode, type TimeVariables, type ProtocolMetadata, type EngineConfig, type RenderResult, type RunOptions, type ProgressInfo, type Engine, type ExecuteCodeModeInput, type ExecuteCodeModeResult, PROTOCOL_IDENTITY, DEFAULT_VARS, DEFAULT_CONFIG, } from './types';
12
+ export { createP5Runtime, injectTimeVariables, createProtocolVAR, VAR_COUNT, VAR_MIN, VAR_MAX, CODE_MODE_PROTOCOL_VERSION, CODE_MODE_PROTOCOL_PHASE, CODE_MODE_ENFORCEMENT, type P5Runtime, type P5RuntimeConfig, } from './p5-runtime';
13
+ export { runStaticMode, } from './static-engine';
14
+ export { runLoopMode, cancelLoopMode, } from './loop-engine';
15
+ export { createEngine, } from './engine';
16
+ /**
17
+ * SDK Identity
18
+ */
19
+ export declare const SDK_VERSION = "1.1.1";
20
+ export declare const SDK_NAME = "@nexart/codemode-sdk";
21
+ //# sourceMappingURL=core-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core-index.d.ts","sourceRoot":"","sources":["../core-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EACL,eAAe,EACf,sBAAsB,GACvB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,MAAM,EACX,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,YAAY,EACZ,cAAc,GACf,MAAM,SAAS,CAAC;AAGjB,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,EACT,OAAO,EACP,OAAO,EACP,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,KAAK,SAAS,EACd,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,aAAa,GACd,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,WAAW,EACX,cAAc,GACf,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,YAAY,GACb,MAAM,UAAU,CAAC;AAElB;;GAEG;AACH,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,QAAQ,yBAAyB,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @nexart/codemode-sdk v1.1.0 — Core Exports
3
+ *
4
+ * Canonical execution engine for NexArt Code Mode.
5
+ * This is the single source of truth for Code Mode semantics.
6
+ *
7
+ * Protocol: v1.0.0 (LOCKED)
8
+ * Enforcement: HARD
9
+ */
10
+ // Core execution
11
+ export { executeCodeMode, validateCodeModeSource, } from './execute';
12
+ // Protocol types
13
+ export { PROTOCOL_IDENTITY, DEFAULT_VARS, DEFAULT_CONFIG, } from './types';
14
+ // Runtime
15
+ export { createP5Runtime, injectTimeVariables, createProtocolVAR, VAR_COUNT, VAR_MIN, VAR_MAX, CODE_MODE_PROTOCOL_VERSION, CODE_MODE_PROTOCOL_PHASE, CODE_MODE_ENFORCEMENT, } from './p5-runtime';
16
+ // Static engine
17
+ export { runStaticMode, } from './static-engine';
18
+ // Loop engine
19
+ export { runLoopMode, cancelLoopMode, } from './loop-engine';
20
+ // Engine utilities
21
+ export { createEngine, } from './engine';
22
+ /**
23
+ * SDK Identity
24
+ */
25
+ export const SDK_VERSION = '1.1.1';
26
+ export const SDK_NAME = '@nexart/codemode-sdk';
@@ -0,0 +1,46 @@
1
+ /**
2
+ * NexArt Code Mode Runtime SDK - Canonical Execution Entry Point
3
+ *
4
+ * ╔══════════════════════════════════════════════════════════════════════════╗
5
+ * ║ CODE MODE PROTOCOL v1.0.0 (Phase 1) — CANONICAL ENTRY POINT ║
6
+ * ║ ║
7
+ * ║ This is the ONLY official way to execute Code Mode. ║
8
+ * ║ All implementations (NexArt, ByX, external) MUST use this function. ║
9
+ * ║ ║
10
+ * ║ Authority: @nexart/codemode-sdk ║
11
+ * ╚══════════════════════════════════════════════════════════════════════════╝
12
+ */
13
+ import { ExecuteCodeModeInput, ExecuteCodeModeResult } from './types';
14
+ /**
15
+ * executeCodeMode — Canonical Code Mode Execution Entry Point
16
+ *
17
+ * This is the ONLY official way to execute Code Mode.
18
+ * All implementations MUST use this function.
19
+ *
20
+ * @param input - Execution parameters
21
+ * @returns Promise<ExecuteCodeModeResult> - Execution result with protocol metadata
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const result = await executeCodeMode({
26
+ * source: `function setup() { background(255); ellipse(width/2, height/2, 100); }`,
27
+ * width: 1950,
28
+ * height: 2400,
29
+ * seed: 12345,
30
+ * vars: [50, 75, 0, 0, 0, 0, 0, 0, 0, 0],
31
+ * mode: 'static'
32
+ * });
33
+ *
34
+ * console.log(result.metadata.protocolVersion); // '1.0.0'
35
+ * console.log(result.image); // PNG Blob
36
+ * ```
37
+ */
38
+ export declare function executeCodeMode(input: ExecuteCodeModeInput): Promise<ExecuteCodeModeResult>;
39
+ /**
40
+ * Validate code without executing
41
+ */
42
+ export declare function validateCodeModeSource(source: string, mode: 'static' | 'loop'): {
43
+ valid: boolean;
44
+ errors: string[];
45
+ };
46
+ //# sourceMappingURL=execute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../execute.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EAKtB,MAAM,SAAS,CAAC;AA4MjB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,qBAAqB,CAAC,CAqBhC;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAuCpH"}
@@ -0,0 +1,268 @@
1
+ /**
2
+ * NexArt Code Mode Runtime SDK - Canonical Execution Entry Point
3
+ *
4
+ * ╔══════════════════════════════════════════════════════════════════════════╗
5
+ * ║ CODE MODE PROTOCOL v1.0.0 (Phase 1) — CANONICAL ENTRY POINT ║
6
+ * ║ ║
7
+ * ║ This is the ONLY official way to execute Code Mode. ║
8
+ * ║ All implementations (NexArt, ByX, external) MUST use this function. ║
9
+ * ║ ║
10
+ * ║ Authority: @nexart/codemode-sdk ║
11
+ * ╚══════════════════════════════════════════════════════════════════════════╝
12
+ */
13
+ import { runStaticMode } from './static-engine';
14
+ import { runLoopMode } from './loop-engine';
15
+ import { PROTOCOL_IDENTITY, DEFAULT_CONFIG, } from './types';
16
+ /**
17
+ * Validate and normalize VAR array to 10 elements.
18
+ *
19
+ * Rules (SDK v1.0.2, Protocol v1.0.0):
20
+ * - VAR is OPTIONAL: omit or pass [] for empty (defaults to all zeros)
21
+ * - VAR input length MUST be 0-10 elements (protocol error if > 10)
22
+ * - VAR values MUST be finite numbers (protocol error if not)
23
+ * - VAR values MUST be in range 0-100 (protocol error if out of range, NO clamping)
24
+ * - VAR is read-only inside sketches
25
+ * - Output is ALWAYS 10 elements (padded with zeros) for protocol consistency
26
+ */
27
+ function normalizeVars(vars) {
28
+ if (!vars || !Array.isArray(vars)) {
29
+ console.log('[CodeMode] No vars provided, using defaults [0,0,0,0,0,0,0,0,0,0]');
30
+ return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
31
+ }
32
+ if (vars.length > 10) {
33
+ throw new Error(`[Code Mode Protocol Error] VAR array must have at most 10 elements, got ${vars.length}`);
34
+ }
35
+ const result = [];
36
+ for (let i = 0; i < vars.length; i++) {
37
+ const v = vars[i];
38
+ if (typeof v !== 'number' || !Number.isFinite(v)) {
39
+ throw new Error(`[Code Mode Protocol Error] VAR[${i}] must be a finite number, got ${typeof v === 'number' ? v : typeof v}`);
40
+ }
41
+ if (v < 0 || v > 100) {
42
+ throw new Error(`[Code Mode Protocol Error] VAR[${i}] = ${v} is out of range. Values must be 0-100.`);
43
+ }
44
+ result.push(v);
45
+ }
46
+ // Pad with zeros to always have 10 elements for protocol consistency
47
+ while (result.length < 10) {
48
+ result.push(0);
49
+ }
50
+ return result;
51
+ }
52
+ /**
53
+ * Validate execution input
54
+ */
55
+ function validateInput(input) {
56
+ if (!input.source || typeof input.source !== 'string') {
57
+ throw new Error('[Code Mode Protocol Error] source is required and must be a string');
58
+ }
59
+ if (typeof input.width !== 'number' || input.width <= 0) {
60
+ throw new Error('[Code Mode Protocol Error] width must be a positive number');
61
+ }
62
+ if (typeof input.height !== 'number' || input.height <= 0) {
63
+ throw new Error('[Code Mode Protocol Error] height must be a positive number');
64
+ }
65
+ if (typeof input.seed !== 'number') {
66
+ throw new Error('[Code Mode Protocol Error] seed is required and must be a number');
67
+ }
68
+ if (input.mode !== 'static' && input.mode !== 'loop') {
69
+ throw new Error('[Code Mode Protocol Error] mode must be "static" or "loop"');
70
+ }
71
+ if (input.mode === 'loop') {
72
+ if (typeof input.totalFrames !== 'number' || input.totalFrames <= 0) {
73
+ throw new Error('[Code Mode Protocol Error] totalFrames is required for loop mode and must be a positive number');
74
+ }
75
+ }
76
+ // Validate forbidden patterns per CODE_MODE_PROTOCOL.md
77
+ const forbiddenPatterns = [
78
+ // Async timing (breaks determinism)
79
+ { pattern: /setTimeout\s*\(/, name: 'setTimeout' },
80
+ { pattern: /setInterval\s*\(/, name: 'setInterval' },
81
+ { pattern: /requestAnimationFrame\s*\(/, name: 'requestAnimationFrame' },
82
+ // Time-based entropy (breaks determinism)
83
+ { pattern: /Date\.now\s*\(/, name: 'Date.now() — use time variable instead' },
84
+ { pattern: /new\s+Date\s*\(/, name: 'new Date() — use time variable instead' },
85
+ // Unseeded random (use random() instead)
86
+ { pattern: /Math\.random\s*\(/, name: 'Math.random() — use random() instead (seeded)' },
87
+ // External IO (breaks determinism)
88
+ { pattern: /fetch\s*\(/, name: 'fetch() — external IO forbidden' },
89
+ { pattern: /XMLHttpRequest/, name: 'XMLHttpRequest — external IO forbidden' },
90
+ // Canvas is pre-initialized
91
+ { pattern: /createCanvas\s*\(/, name: 'createCanvas() — canvas is pre-initialized' },
92
+ // DOM manipulation forbidden
93
+ { pattern: /document\./, name: 'DOM access — document.* forbidden' },
94
+ { pattern: /window\./, name: 'DOM access — window.* forbidden' },
95
+ // External imports forbidden
96
+ { pattern: /\bimport\s+/, name: 'import — external imports forbidden' },
97
+ { pattern: /\brequire\s*\(/, name: 'require() — external imports forbidden' },
98
+ ];
99
+ for (const { pattern, name } of forbiddenPatterns) {
100
+ if (pattern.test(input.source)) {
101
+ throw new Error(`[Code Mode Protocol Error] Forbidden pattern: ${name}`);
102
+ }
103
+ }
104
+ // Loop mode specific validation
105
+ if (input.mode === 'loop') {
106
+ if (!/function\s+draw\s*\(\s*\)/.test(input.source)) {
107
+ throw new Error('[Code Mode Protocol Error] Loop mode requires a draw() function');
108
+ }
109
+ if (/noLoop\s*\(\s*\)/.test(input.source)) {
110
+ throw new Error('[Code Mode Protocol Error] noLoop() is forbidden in Loop mode');
111
+ }
112
+ }
113
+ }
114
+ /**
115
+ * Create protocol metadata for the execution result
116
+ */
117
+ function createMetadata(input, vars) {
118
+ return {
119
+ ...PROTOCOL_IDENTITY,
120
+ seed: input.seed,
121
+ vars,
122
+ width: input.width,
123
+ height: input.height,
124
+ mode: input.mode,
125
+ ...(input.mode === 'loop' && input.totalFrames ? { totalFrames: input.totalFrames } : {}),
126
+ };
127
+ }
128
+ /**
129
+ * Execute Code Mode in Static mode - delegates to static-engine.ts
130
+ */
131
+ async function executeStatic(input, vars) {
132
+ console.log('[CodeMode] Rendered via @nexart/codemode-sdk (Protocol v1.0.0)');
133
+ console.log('[CodeMode] Execution: Static mode — delegating to static-engine');
134
+ return new Promise((resolve, reject) => {
135
+ runStaticMode({
136
+ mode: 'static',
137
+ width: input.width,
138
+ height: input.height,
139
+ }, {
140
+ code: input.source,
141
+ seed: input.seed,
142
+ vars: vars,
143
+ onComplete: (result) => {
144
+ resolve({
145
+ image: result.blob,
146
+ metadata: createMetadata(input, vars),
147
+ });
148
+ },
149
+ onError: (error) => {
150
+ reject(error);
151
+ },
152
+ });
153
+ });
154
+ }
155
+ /**
156
+ * Execute Code Mode in Loop mode - delegates to loop-engine.ts
157
+ */
158
+ async function executeLoop(input, vars) {
159
+ console.log('[CodeMode] Rendered via @nexart/codemode-sdk (Protocol v1.0.0)');
160
+ console.log(`[CodeMode] Execution: Loop mode — delegating to loop-engine (${input.totalFrames} frames)`);
161
+ const fps = DEFAULT_CONFIG.fps;
162
+ const duration = (input.totalFrames || 60) / fps;
163
+ return new Promise((resolve, reject) => {
164
+ runLoopMode({
165
+ mode: 'loop',
166
+ width: input.width,
167
+ height: input.height,
168
+ duration: duration,
169
+ fps: fps,
170
+ }, {
171
+ code: input.source,
172
+ seed: input.seed,
173
+ vars: vars,
174
+ onComplete: (result) => {
175
+ resolve({
176
+ video: result.blob,
177
+ metadata: createMetadata(input, vars),
178
+ });
179
+ },
180
+ onError: (error) => {
181
+ reject(error);
182
+ },
183
+ });
184
+ });
185
+ }
186
+ /**
187
+ * executeCodeMode — Canonical Code Mode Execution Entry Point
188
+ *
189
+ * This is the ONLY official way to execute Code Mode.
190
+ * All implementations MUST use this function.
191
+ *
192
+ * @param input - Execution parameters
193
+ * @returns Promise<ExecuteCodeModeResult> - Execution result with protocol metadata
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * const result = await executeCodeMode({
198
+ * source: `function setup() { background(255); ellipse(width/2, height/2, 100); }`,
199
+ * width: 1950,
200
+ * height: 2400,
201
+ * seed: 12345,
202
+ * vars: [50, 75, 0, 0, 0, 0, 0, 0, 0, 0],
203
+ * mode: 'static'
204
+ * });
205
+ *
206
+ * console.log(result.metadata.protocolVersion); // '1.0.0'
207
+ * console.log(result.image); // PNG Blob
208
+ * ```
209
+ */
210
+ export async function executeCodeMode(input) {
211
+ // Validate input
212
+ validateInput(input);
213
+ // Normalize VAR values
214
+ const vars = normalizeVars(input.vars);
215
+ // Log protocol execution
216
+ console.log('[CodeMode] ════════════════════════════════════════════════');
217
+ console.log('[CodeMode] Protocol v1.0.0 — Phase 1 — HARD Enforcement');
218
+ console.log(`[CodeMode] Mode: ${input.mode}`);
219
+ console.log(`[CodeMode] Seed: ${input.seed}`);
220
+ console.log(`[CodeMode] VAR: [${vars.join(', ')}]`);
221
+ console.log('[CodeMode] ════════════════════════════════════════════════');
222
+ // Execute based on mode
223
+ if (input.mode === 'static') {
224
+ return executeStatic(input, vars);
225
+ }
226
+ else {
227
+ return executeLoop(input, vars);
228
+ }
229
+ }
230
+ /**
231
+ * Validate code without executing
232
+ */
233
+ export function validateCodeModeSource(source, mode) {
234
+ const errors = [];
235
+ // Same forbidden patterns as validateInput per CODE_MODE_PROTOCOL.md
236
+ const forbiddenPatterns = [
237
+ { pattern: /setTimeout\s*\(/, name: 'setTimeout' },
238
+ { pattern: /setInterval\s*\(/, name: 'setInterval' },
239
+ { pattern: /requestAnimationFrame\s*\(/, name: 'requestAnimationFrame' },
240
+ { pattern: /Date\.now\s*\(/, name: 'Date.now() — use time variable instead' },
241
+ { pattern: /new\s+Date\s*\(/, name: 'new Date() — use time variable instead' },
242
+ { pattern: /Math\.random\s*\(/, name: 'Math.random() — use random() instead (seeded)' },
243
+ { pattern: /fetch\s*\(/, name: 'fetch() — external IO forbidden' },
244
+ { pattern: /XMLHttpRequest/, name: 'XMLHttpRequest — external IO forbidden' },
245
+ { pattern: /createCanvas\s*\(/, name: 'createCanvas() — canvas is pre-initialized' },
246
+ { pattern: /document\./, name: 'DOM access — document.* forbidden' },
247
+ { pattern: /window\./, name: 'DOM access — window.* forbidden' },
248
+ { pattern: /\bimport\s+/, name: 'import — external imports forbidden' },
249
+ { pattern: /\brequire\s*\(/, name: 'require() — external imports forbidden' },
250
+ ];
251
+ for (const { pattern, name } of forbiddenPatterns) {
252
+ if (pattern.test(source)) {
253
+ errors.push(`Forbidden pattern: ${name}`);
254
+ }
255
+ }
256
+ if (mode === 'loop') {
257
+ if (!/function\s+draw\s*\(\s*\)/.test(source)) {
258
+ errors.push('Loop mode requires a draw() function');
259
+ }
260
+ if (/noLoop\s*\(\s*\)/.test(source)) {
261
+ errors.push('noLoop() is forbidden in Loop mode');
262
+ }
263
+ }
264
+ return {
265
+ valid: errors.length === 0,
266
+ errors,
267
+ };
268
+ }