@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.
- package/CHANGELOG.md +109 -0
- package/CODE_MODE_PROTOCOL.md +312 -0
- package/README.md +200 -58
- package/dist/core-index.d.ts +21 -0
- package/dist/core-index.d.ts.map +1 -0
- package/dist/core-index.js +26 -0
- package/dist/execute.d.ts +46 -0
- package/dist/execute.d.ts.map +1 -0
- package/dist/execute.js +268 -0
- package/dist/index.d.ts +36 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -17
- package/dist/loop-engine.d.ts +4 -1
- package/dist/loop-engine.d.ts.map +1 -1
- package/dist/loop-engine.js +17 -12
- package/dist/noise-bridge.d.ts +44 -0
- package/dist/noise-bridge.d.ts.map +1 -0
- package/dist/noise-bridge.js +68 -0
- package/dist/noise-engine.d.ts +74 -0
- package/dist/noise-engine.d.ts.map +1 -0
- package/dist/noise-engine.js +132 -0
- package/dist/noise-sketches/fractalNoise.d.ts +11 -0
- package/dist/noise-sketches/fractalNoise.d.ts.map +1 -0
- package/dist/noise-sketches/fractalNoise.js +121 -0
- package/dist/noise-sketches/index.d.ts +21 -0
- package/dist/noise-sketches/index.d.ts.map +1 -0
- package/dist/noise-sketches/index.js +28 -0
- package/dist/p5-runtime.d.ts +56 -4
- package/dist/p5-runtime.d.ts.map +1 -1
- package/dist/p5-runtime.js +348 -22
- package/dist/sound-bridge.d.ts +89 -0
- package/dist/sound-bridge.d.ts.map +1 -0
- package/dist/sound-bridge.js +128 -0
- package/dist/soundart-engine.d.ts +87 -0
- package/dist/soundart-engine.d.ts.map +1 -0
- package/dist/soundart-engine.js +173 -0
- package/dist/soundart-sketches/chladniBloom.d.ts +3 -0
- package/dist/soundart-sketches/chladniBloom.d.ts.map +1 -0
- package/dist/soundart-sketches/chladniBloom.js +53 -0
- package/dist/soundart-sketches/dualVortex.d.ts +3 -0
- package/dist/soundart-sketches/dualVortex.d.ts.map +1 -0
- package/dist/soundart-sketches/dualVortex.js +67 -0
- package/dist/soundart-sketches/geometryIllusion.d.ts +3 -0
- package/dist/soundart-sketches/geometryIllusion.d.ts.map +1 -0
- package/dist/soundart-sketches/geometryIllusion.js +89 -0
- package/dist/soundart-sketches/index.d.ts +39 -0
- package/dist/soundart-sketches/index.d.ts.map +1 -0
- package/dist/soundart-sketches/index.js +72 -0
- package/dist/soundart-sketches/isoflow.d.ts +3 -0
- package/dist/soundart-sketches/isoflow.d.ts.map +1 -0
- package/dist/soundart-sketches/isoflow.js +60 -0
- package/dist/soundart-sketches/loomWeave.d.ts +3 -0
- package/dist/soundart-sketches/loomWeave.d.ts.map +1 -0
- package/dist/soundart-sketches/loomWeave.js +59 -0
- package/dist/soundart-sketches/noiseTerraces.d.ts +3 -0
- package/dist/soundart-sketches/noiseTerraces.d.ts.map +1 -0
- package/dist/soundart-sketches/noiseTerraces.js +53 -0
- package/dist/soundart-sketches/orb.d.ts +3 -0
- package/dist/soundart-sketches/orb.d.ts.map +1 -0
- package/dist/soundart-sketches/orb.js +50 -0
- package/dist/soundart-sketches/pixelGlyphs.d.ts +3 -0
- package/dist/soundart-sketches/pixelGlyphs.d.ts.map +1 -0
- package/dist/soundart-sketches/pixelGlyphs.js +72 -0
- package/dist/soundart-sketches/prismFlowFields.d.ts +3 -0
- package/dist/soundart-sketches/prismFlowFields.d.ts.map +1 -0
- package/dist/soundart-sketches/prismFlowFields.js +51 -0
- package/dist/soundart-sketches/radialBurst.d.ts +3 -0
- package/dist/soundart-sketches/radialBurst.d.ts.map +1 -0
- package/dist/soundart-sketches/radialBurst.js +60 -0
- package/dist/soundart-sketches/resonantSoundBodies.d.ts +3 -0
- package/dist/soundart-sketches/resonantSoundBodies.d.ts.map +1 -0
- package/dist/soundart-sketches/resonantSoundBodies.js +89 -0
- package/dist/soundart-sketches/rings.d.ts +11 -0
- package/dist/soundart-sketches/rings.d.ts.map +1 -0
- package/dist/soundart-sketches/rings.js +89 -0
- package/dist/soundart-sketches/squares.d.ts +3 -0
- package/dist/soundart-sketches/squares.d.ts.map +1 -0
- package/dist/soundart-sketches/squares.js +52 -0
- package/dist/soundart-sketches/waveStripes.d.ts +3 -0
- package/dist/soundart-sketches/waveStripes.d.ts.map +1 -0
- package/dist/soundart-sketches/waveStripes.js +44 -0
- package/dist/static-engine.d.ts +4 -1
- package/dist/static-engine.d.ts.map +1 -1
- package/dist/static-engine.js +13 -8
- package/dist/types.d.ts +75 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +19 -1
- 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
|
-
|
|
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-
|
|
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
|
-
##
|
|
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
|
-
//
|
|
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
|
-
##
|
|
461
|
+
## Video Encoding
|
|
314
462
|
|
|
315
|
-
|
|
463
|
+
Loop Mode requires server-side video encoding. The SDK calls:
|
|
316
464
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
543
|
+
The following guarantees are LOCKED and will not change in v1.x:
|
|
413
544
|
|
|
414
|
-
|
|
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
|
-
##
|
|
419
|
-
|
|
420
|
-
MIT License
|
|
559
|
+
## Future Work (Phase 2+)
|
|
421
560
|
|
|
422
|
-
|
|
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"}
|
package/dist/execute.js
ADDED
|
@@ -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
|
+
}
|