@nexart/codemode-sdk 1.4.0 → 1.5.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.
- package/README.md +13 -3
- package/dist/engine.d.ts +39 -17
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +253 -52
- package/dist/index.d.ts +13 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -11
- package/dist/loop-engine.d.ts +5 -1
- package/dist/loop-engine.d.ts.map +1 -1
- package/dist/loop-engine.js +25 -14
- package/dist/p5-runtime.d.ts +56 -4
- package/dist/p5-runtime.d.ts.map +1 -1
- package/dist/p5-runtime.js +743 -32
- 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 +3 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# NexArt Code Mode Runtime SDK
|
|
2
2
|
|
|
3
|
-
**Version: 1.
|
|
3
|
+
**Version: 1.5.0 (Protocol v1.2.0)**
|
|
4
4
|
|
|
5
5
|
╔══════════════════════════════════════════════════════════════════════════════╗
|
|
6
6
|
║ @nexart/codemode-sdk — Canonical Code Mode Authority ║
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
║ ║
|
|
11
11
|
║ Protocol: nexart ║
|
|
12
12
|
║ Engine: codemode ║
|
|
13
|
-
║ SDK Version: 1.
|
|
13
|
+
║ SDK Version: 1.5.0 ║
|
|
14
14
|
║ Protocol Version: 1.2.0 ║
|
|
15
15
|
║ Phase: 3 ║
|
|
16
16
|
║ Enforcement: HARD ║
|
|
@@ -54,7 +54,17 @@ The answer is: "Whatever @nexart/codemode-sdk does — that is the protocol."
|
|
|
54
54
|
|
|
55
55
|
---
|
|
56
56
|
|
|
57
|
-
## What's New in v1.
|
|
57
|
+
## What's New in v1.5.0
|
|
58
|
+
|
|
59
|
+
**Critical Fix — NPM Package Sync**
|
|
60
|
+
|
|
61
|
+
- **Restored seeded Mulberry32 PRNG** for `random()`, `randomSeed()`, `randomGaussian()`
|
|
62
|
+
- **Restored seeded Perlin noise** for `noise()`, `noiseSeed()`
|
|
63
|
+
- Full sync between SDK source and npm package
|
|
64
|
+
|
|
65
|
+
The v1.4.0 npm package had an outdated runtime that used `Math.random()` directly. This release restores determinism.
|
|
66
|
+
|
|
67
|
+
## v1.4.0 (Protocol v1.2.0)
|
|
58
68
|
|
|
59
69
|
**Phase 3 — Pixel & Graphics**
|
|
60
70
|
|
package/dist/engine.d.ts
CHANGED
|
@@ -1,24 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* NexArt Code Mode Runtime SDK
|
|
3
|
-
* Version: 1.4.0 (Protocol v1.2.0)
|
|
2
|
+
* NexArt Code Mode Runtime SDK - Canonical Execution Entry Point
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
4
|
+
* ╔══════════════════════════════════════════════════════════════════════════╗
|
|
5
|
+
* ║ CODE MODE PROTOCOL v1.2.0 (Phase 3) — 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
|
+
* ╚══════════════════════════════════════════════════════════════════════════╝
|
|
13
12
|
*/
|
|
14
|
-
import
|
|
13
|
+
import { ExecuteCodeModeInput, ExecuteCodeModeResult } from './types';
|
|
15
14
|
/**
|
|
16
|
-
*
|
|
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
|
|
17
22
|
*
|
|
18
|
-
* @
|
|
19
|
-
*
|
|
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.2.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
|
|
20
41
|
*/
|
|
21
|
-
export declare function
|
|
22
|
-
|
|
23
|
-
|
|
42
|
+
export declare function validateCodeModeSource(source: string, mode: 'static' | 'loop'): {
|
|
43
|
+
valid: boolean;
|
|
44
|
+
errors: string[];
|
|
45
|
+
};
|
|
24
46
|
//# sourceMappingURL=engine.d.ts.map
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../engine.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../engine.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/engine.js
CHANGED
|
@@ -1,67 +1,268 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* NexArt Code Mode Runtime SDK
|
|
3
|
-
* Version: 1.4.0 (Protocol v1.2.0)
|
|
2
|
+
* NexArt Code Mode Runtime SDK - Canonical Execution Entry Point
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
4
|
+
* ╔══════════════════════════════════════════════════════════════════════════╗
|
|
5
|
+
* ║ CODE MODE PROTOCOL v1.2.0 (Phase 3) — 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
|
+
* ╚══════════════════════════════════════════════════════════════════════════╝
|
|
13
12
|
*/
|
|
14
|
-
import { DEFAULT_CONFIG } from './types';
|
|
15
13
|
import { runStaticMode } from './static-engine';
|
|
16
|
-
import { runLoopMode
|
|
14
|
+
import { runLoopMode } from './loop-engine';
|
|
15
|
+
import { PROTOCOL_IDENTITY, DEFAULT_CONFIG, } from './types';
|
|
17
16
|
/**
|
|
18
|
-
*
|
|
17
|
+
* Validate and normalize VAR array to 10 elements.
|
|
19
18
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
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
|
|
22
26
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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}`);
|
|
35
40
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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');
|
|
47
74
|
}
|
|
48
|
-
|
|
49
|
-
|
|
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}`);
|
|
50
102
|
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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');
|
|
55
108
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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 } : {}),
|
|
60
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.2.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.2.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.2.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.2.0 — Phase 3 — 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
|
+
}
|
|
61
264
|
return {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
getConfig,
|
|
265
|
+
valid: errors.length === 0,
|
|
266
|
+
errors,
|
|
65
267
|
};
|
|
66
268
|
}
|
|
67
|
-
export { DEFAULT_CONFIG } from './types';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NexArt Code Mode Runtime SDK
|
|
3
|
-
* Version: 1.
|
|
3
|
+
* Version: 1.5.0 (Protocol v1.2.0)
|
|
4
4
|
*
|
|
5
5
|
* ╔══════════════════════════════════════════════════════════════════════════╗
|
|
6
6
|
* ║ @nexart/codemode-sdk — Canonical Code Mode Authority ║
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* ║ ║
|
|
11
11
|
* ║ Protocol: nexart ║
|
|
12
12
|
* ║ Engine: codemode ║
|
|
13
|
-
* ║ SDK Version: 1.
|
|
13
|
+
* ║ SDK Version: 1.5.0 ║
|
|
14
14
|
* ║ Protocol Version: 1.2.0 ║
|
|
15
15
|
* ║ Phase: 3 ║
|
|
16
16
|
* ║ Enforcement: HARD ║
|
|
@@ -18,25 +18,26 @@
|
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* ```typescript
|
|
21
|
-
* import {
|
|
21
|
+
* import { executeCodeMode } from '@nexart/codemode-sdk';
|
|
22
22
|
*
|
|
23
|
-
* const
|
|
24
|
-
*
|
|
25
|
-
* engine.run({
|
|
26
|
-
* code: `
|
|
23
|
+
* const result = await executeCodeMode({
|
|
24
|
+
* source: `
|
|
27
25
|
* function setup() {
|
|
28
26
|
* background(255);
|
|
29
27
|
* fill(0);
|
|
30
28
|
* ellipse(width/2, height/2, 100);
|
|
31
29
|
* }
|
|
32
30
|
* `,
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
31
|
+
* mode: 'static',
|
|
32
|
+
* width: 1950,
|
|
33
|
+
* height: 2400,
|
|
34
|
+
* seed: 12345,
|
|
35
|
+
* vars: [50, 50, 50, 50, 50, 50, 50, 50, 50, 50]
|
|
36
36
|
* });
|
|
37
|
+
* console.log('Rendered:', result.blob.size, 'bytes');
|
|
37
38
|
* ```
|
|
38
39
|
*/
|
|
39
|
-
export {
|
|
40
|
-
export type {
|
|
40
|
+
export { executeCodeMode, validateCodeModeSource } from './engine';
|
|
41
|
+
export type { ExecuteCodeModeInput, ExecuteCodeModeResult, ProtocolMetadata, RenderResult, TimeVariables, } from './types';
|
|
41
42
|
export { DEFAULT_CONFIG, PROTOCOL_IDENTITY } from './types';
|
|
42
43
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACnE,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,EACZ,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NexArt Code Mode Runtime SDK
|
|
3
|
-
* Version: 1.
|
|
3
|
+
* Version: 1.5.0 (Protocol v1.2.0)
|
|
4
4
|
*
|
|
5
5
|
* ╔══════════════════════════════════════════════════════════════════════════╗
|
|
6
6
|
* ║ @nexart/codemode-sdk — Canonical Code Mode Authority ║
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* ║ ║
|
|
11
11
|
* ║ Protocol: nexart ║
|
|
12
12
|
* ║ Engine: codemode ║
|
|
13
|
-
* ║ SDK Version: 1.
|
|
13
|
+
* ║ SDK Version: 1.5.0 ║
|
|
14
14
|
* ║ Protocol Version: 1.2.0 ║
|
|
15
15
|
* ║ Phase: 3 ║
|
|
16
16
|
* ║ Enforcement: HARD ║
|
|
@@ -18,23 +18,24 @@
|
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* ```typescript
|
|
21
|
-
* import {
|
|
21
|
+
* import { executeCodeMode } from '@nexart/codemode-sdk';
|
|
22
22
|
*
|
|
23
|
-
* const
|
|
24
|
-
*
|
|
25
|
-
* engine.run({
|
|
26
|
-
* code: `
|
|
23
|
+
* const result = await executeCodeMode({
|
|
24
|
+
* source: `
|
|
27
25
|
* function setup() {
|
|
28
26
|
* background(255);
|
|
29
27
|
* fill(0);
|
|
30
28
|
* ellipse(width/2, height/2, 100);
|
|
31
29
|
* }
|
|
32
30
|
* `,
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
31
|
+
* mode: 'static',
|
|
32
|
+
* width: 1950,
|
|
33
|
+
* height: 2400,
|
|
34
|
+
* seed: 12345,
|
|
35
|
+
* vars: [50, 50, 50, 50, 50, 50, 50, 50, 50, 50]
|
|
36
36
|
* });
|
|
37
|
+
* console.log('Rendered:', result.blob.size, 'bytes');
|
|
37
38
|
* ```
|
|
38
39
|
*/
|
|
39
|
-
export {
|
|
40
|
+
export { executeCodeMode, validateCodeModeSource } from './engine';
|
|
40
41
|
export { DEFAULT_CONFIG, PROTOCOL_IDENTITY } from './types';
|
package/dist/loop-engine.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NexArt Code Mode Runtime SDK - Loop Engine
|
|
3
|
-
*
|
|
3
|
+
* Protocol: v1.2.0 (Phase 3) — HARD ENFORCEMENT
|
|
4
4
|
*
|
|
5
5
|
* Loop mode renderer: frame-authoritative, stateless execution.
|
|
6
6
|
* - Executes setup() once
|
|
7
7
|
* - Executes draw() once per frame
|
|
8
8
|
* - Clears canvas before each frame (transparent)
|
|
9
|
+
* - Resets blend mode to NORMAL before each frame
|
|
9
10
|
* - Injects normalized time variables
|
|
10
11
|
* - No canvas persistence between frames
|
|
12
|
+
*
|
|
13
|
+
* Determinism Guarantee:
|
|
14
|
+
* Same code + same seed + same VARs = identical frame sequence
|
|
11
15
|
*/
|
|
12
16
|
import type { EngineConfig, RunOptions } from './types';
|
|
13
17
|
export declare function cancelLoopMode(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loop-engine.d.ts","sourceRoot":"","sources":["../loop-engine.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"loop-engine.d.ts","sourceRoot":"","sources":["../loop-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAA+B,MAAM,SAAS,CAAC;AAMrF,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CAuMf"}
|
package/dist/loop-engine.js
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NexArt Code Mode Runtime SDK - Loop Engine
|
|
3
|
-
*
|
|
3
|
+
* Protocol: v1.2.0 (Phase 3) — HARD ENFORCEMENT
|
|
4
4
|
*
|
|
5
5
|
* Loop mode renderer: frame-authoritative, stateless execution.
|
|
6
6
|
* - Executes setup() once
|
|
7
7
|
* - Executes draw() once per frame
|
|
8
8
|
* - Clears canvas before each frame (transparent)
|
|
9
|
+
* - Resets blend mode to NORMAL before each frame
|
|
9
10
|
* - Injects normalized time variables
|
|
10
11
|
* - No canvas persistence between frames
|
|
12
|
+
*
|
|
13
|
+
* Determinism Guarantee:
|
|
14
|
+
* Same code + same seed + same VARs = identical frame sequence
|
|
11
15
|
*/
|
|
12
16
|
import { DEFAULT_CONFIG } from './types';
|
|
13
|
-
import { createP5Runtime } from './p5-runtime';
|
|
17
|
+
import { createP5Runtime, injectProtocolVariables } from './p5-runtime';
|
|
14
18
|
let isCancelled = false;
|
|
15
19
|
export function cancelLoopMode() {
|
|
16
20
|
isCancelled = true;
|
|
17
21
|
}
|
|
18
22
|
export async function runLoopMode(config, options) {
|
|
19
|
-
const { code, onPreview, onProgress, onComplete, onError } = options;
|
|
23
|
+
const { code, seed, vars, onPreview, onProgress, onComplete, onError } = options;
|
|
20
24
|
const width = config.width ?? DEFAULT_CONFIG.width;
|
|
21
25
|
const height = config.height ?? DEFAULT_CONFIG.height;
|
|
22
26
|
const duration = Math.max(DEFAULT_CONFIG.minDuration, Math.min(DEFAULT_CONFIG.maxDuration, config.duration ?? DEFAULT_CONFIG.duration));
|
|
@@ -33,8 +37,10 @@ export async function runLoopMode(config, options) {
|
|
|
33
37
|
const canvas = document.createElement('canvas');
|
|
34
38
|
canvas.width = width;
|
|
35
39
|
canvas.height = height;
|
|
36
|
-
// Create p5 runtime
|
|
37
|
-
const p = createP5Runtime(canvas, width, height);
|
|
40
|
+
// Create p5 runtime with optional seed for determinism
|
|
41
|
+
const p = createP5Runtime(canvas, width, height, { seed });
|
|
42
|
+
// Inject protocol variables (VAR[0..9])
|
|
43
|
+
injectProtocolVariables(p, vars);
|
|
38
44
|
// Validate code
|
|
39
45
|
const hasDrawFunction = /function\s+draw\s*\(\s*\)/.test(code);
|
|
40
46
|
if (!hasDrawFunction) {
|
|
@@ -64,16 +70,18 @@ export async function runLoopMode(config, options) {
|
|
|
64
70
|
if (!drawCode) {
|
|
65
71
|
throw new Error('Loop Mode requires a draw() function with content.');
|
|
66
72
|
}
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
// Inject totalFrames into runtime
|
|
74
|
+
p.totalFrames = totalFrames;
|
|
75
|
+
// Create wrapped functions with p5 context, time variables, VAR, and totalFrames
|
|
76
|
+
const wrappedSetup = new Function('p', 'frameCount', 't', 'time', 'tGlobal', 'VAR', 'totalFrames', `with(p) { ${setupCode} }`);
|
|
77
|
+
const wrappedDraw = new Function('p', 'frameCount', 't', 'time', 'tGlobal', 'VAR', 'totalFrames', `with(p) { ${drawCode} }`);
|
|
70
78
|
onProgress?.({
|
|
71
79
|
phase: 'setup',
|
|
72
80
|
percent: 10,
|
|
73
81
|
message: 'Executing setup()...',
|
|
74
82
|
});
|
|
75
|
-
// Execute setup() once with time = 0
|
|
76
|
-
wrappedSetup(p, 0, 0, 0, 0);
|
|
83
|
+
// Execute setup() once with time = 0, VAR, and totalFrames
|
|
84
|
+
wrappedSetup(p, 0, 0, 0, 0, p.VAR, totalFrames);
|
|
77
85
|
// Capture frames
|
|
78
86
|
const frames = [];
|
|
79
87
|
onProgress?.({
|
|
@@ -93,12 +101,15 @@ export async function runLoopMode(config, options) {
|
|
|
93
101
|
const time = t * duration;
|
|
94
102
|
// Update p5 runtime frameCount
|
|
95
103
|
p.frameCount = frame;
|
|
96
|
-
// CRITICAL:
|
|
104
|
+
// CRITICAL: Reset canvas state before each draw() call
|
|
97
105
|
// This enforces stateless, frame-authoritative rendering
|
|
98
|
-
//
|
|
106
|
+
// 1. Clear canvas (transparent)
|
|
99
107
|
p.clear();
|
|
100
|
-
//
|
|
101
|
-
|
|
108
|
+
// 2. Reset blend mode to NORMAL (Protocol v1.1 requirement)
|
|
109
|
+
// Prevents blend mode state from persisting across frames
|
|
110
|
+
p.blendMode('NORMAL');
|
|
111
|
+
// Execute draw() with time variables, VAR, and totalFrames
|
|
112
|
+
wrappedDraw(p, frame, t, time, t, p.VAR, totalFrames);
|
|
102
113
|
// Capture frame as PNG blob
|
|
103
114
|
const blob = await new Promise((resolve, reject) => {
|
|
104
115
|
canvas.toBlob((b) => b ? resolve(b) : reject(new Error(`Failed to capture frame ${frame}`)), 'image/png');
|