@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
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fractal Noise - Code Mode Sketch
|
|
3
|
+
*
|
|
4
|
+
* This sketch implements Perlin FBM and Cellular noise rendering
|
|
5
|
+
* through the Code Mode p5-runtime. Uses N.* globals for all parameters.
|
|
6
|
+
*
|
|
7
|
+
* Original: client/src/components/noise-canvas-simple.tsx
|
|
8
|
+
*/
|
|
9
|
+
export const FRACTAL_NOISE_SKETCH = `
|
|
10
|
+
// Fractal Noise - Code Mode Sketch
|
|
11
|
+
// Uses N.* noise globals and standard p5-like functions
|
|
12
|
+
|
|
13
|
+
function setup() {
|
|
14
|
+
// Set seeded random for reproducibility
|
|
15
|
+
randomSeed(N.seed);
|
|
16
|
+
noiseSeed(N.seed);
|
|
17
|
+
|
|
18
|
+
// Set background color
|
|
19
|
+
background(N.bgR, N.bgG, N.bgB);
|
|
20
|
+
|
|
21
|
+
// Noise rendering parameters
|
|
22
|
+
const adjustedScale = N.scale * (1 / N.zoom) * 0.05;
|
|
23
|
+
const cellSize = 4; // Fixed for quality
|
|
24
|
+
|
|
25
|
+
// Generate cellular points if needed
|
|
26
|
+
const numPoints = Math.floor(20 + N.cellDensity * 180);
|
|
27
|
+
const cellPoints = [];
|
|
28
|
+
for (let i = 0; i < numPoints; i++) {
|
|
29
|
+
cellPoints.push([random(0, width), random(0, height)]);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Helper: Perlin FBM (Fractional Brownian Motion)
|
|
33
|
+
function perlinFBM(x, y, scale) {
|
|
34
|
+
let value = 0;
|
|
35
|
+
let amplitude = 1;
|
|
36
|
+
let frequency = 1;
|
|
37
|
+
let maxValue = 0;
|
|
38
|
+
|
|
39
|
+
const oct = Math.min(N.octaves, 6); // Cap for performance
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < oct; i++) {
|
|
42
|
+
value += noise(x * scale * frequency, y * scale * frequency) * amplitude;
|
|
43
|
+
maxValue += amplitude;
|
|
44
|
+
amplitude *= N.persistence;
|
|
45
|
+
frequency *= N.lacunarity;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return value / maxValue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Helper: Cellular noise (Worley)
|
|
52
|
+
function cellularNoise(x, y, points) {
|
|
53
|
+
let sampleX = x;
|
|
54
|
+
let sampleY = y;
|
|
55
|
+
|
|
56
|
+
// Warp distortion if using warp mode
|
|
57
|
+
if (N.isWarp && N.cellDistortion > 0) {
|
|
58
|
+
const distortionAmount = N.cellDistortion * 100;
|
|
59
|
+
sampleX += noise(x * 0.01, y * 0.01) * distortionAmount;
|
|
60
|
+
sampleY += noise(y * 0.01, x * 0.01) * distortionAmount;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Find distances to closest points
|
|
64
|
+
let minDist = 999999;
|
|
65
|
+
let secondMinDist = 999999;
|
|
66
|
+
|
|
67
|
+
for (let i = 0; i < points.length; i++) {
|
|
68
|
+
const px = points[i][0];
|
|
69
|
+
const py = points[i][1];
|
|
70
|
+
const dx = sampleX - px;
|
|
71
|
+
const dy = sampleY - py;
|
|
72
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
73
|
+
|
|
74
|
+
if (dist < minDist) {
|
|
75
|
+
secondMinDist = minDist;
|
|
76
|
+
minDist = dist;
|
|
77
|
+
} else if (dist < secondMinDist) {
|
|
78
|
+
secondMinDist = dist;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Normalize distance
|
|
83
|
+
return Math.min(1.0, (secondMinDist - minDist) / 50);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Render the noise grid
|
|
87
|
+
noStroke();
|
|
88
|
+
|
|
89
|
+
for (let y = 0; y < height; y += cellSize) {
|
|
90
|
+
for (let x = 0; x < width; x += cellSize) {
|
|
91
|
+
// Calculate Perlin value
|
|
92
|
+
const perlinValue = perlinFBM(x, y, adjustedScale);
|
|
93
|
+
|
|
94
|
+
// Calculate final value based on blend mode
|
|
95
|
+
let finalValue = perlinValue;
|
|
96
|
+
|
|
97
|
+
if (!N.isPerlinOnly) {
|
|
98
|
+
const cellValue = cellularNoise(x, y, cellPoints);
|
|
99
|
+
|
|
100
|
+
if (N.isBlend) {
|
|
101
|
+
finalValue = perlinValue * cellValue;
|
|
102
|
+
} else if (N.isWarp) {
|
|
103
|
+
finalValue = (perlinValue + cellValue) / 2;
|
|
104
|
+
} else if (N.isInterleave) {
|
|
105
|
+
finalValue = (Math.floor(x / 20) + Math.floor(y / 20)) % 2 === 0
|
|
106
|
+
? perlinValue
|
|
107
|
+
: cellValue;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Set opacity based on noise value
|
|
112
|
+
const alpha = map(finalValue, 0, 1, 0, 255);
|
|
113
|
+
|
|
114
|
+
// Fill with noise color and calculated alpha
|
|
115
|
+
fill(N.noiseR, N.noiseG, N.noiseB, alpha);
|
|
116
|
+
rect(x, y, cellSize, cellSize);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
`;
|
|
121
|
+
export default FRACTAL_NOISE_SKETCH;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Noise Sketches Index
|
|
3
|
+
*
|
|
4
|
+
* Exports all available noise sketch generators for the Code Mode runtime.
|
|
5
|
+
*/
|
|
6
|
+
import FRACTAL_NOISE_SKETCH from './fractalNoise';
|
|
7
|
+
export type NoiseSketchName = 'fractalNoise';
|
|
8
|
+
/**
|
|
9
|
+
* Get a noise sketch by name
|
|
10
|
+
*/
|
|
11
|
+
export declare function getNoiseSketch(name: NoiseSketchName): string;
|
|
12
|
+
/**
|
|
13
|
+
* Check if a sketch name is valid
|
|
14
|
+
*/
|
|
15
|
+
export declare function isValidNoiseSketch(name: string): name is NoiseSketchName;
|
|
16
|
+
/**
|
|
17
|
+
* Get list of all available noise sketch names
|
|
18
|
+
*/
|
|
19
|
+
export declare function getAvailableNoiseSketchNames(): NoiseSketchName[];
|
|
20
|
+
export { FRACTAL_NOISE_SKETCH };
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../noise-sketches/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,oBAAoB,MAAM,gBAAgB,CAAC;AAElD,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC;AAM7C;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAE5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,eAAe,CAExE;AAED;;GAEG;AACH,wBAAgB,4BAA4B,IAAI,eAAe,EAAE,CAEhE;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Noise Sketches Index
|
|
3
|
+
*
|
|
4
|
+
* Exports all available noise sketch generators for the Code Mode runtime.
|
|
5
|
+
*/
|
|
6
|
+
import FRACTAL_NOISE_SKETCH from './fractalNoise';
|
|
7
|
+
const NOISE_SKETCHES = {
|
|
8
|
+
fractalNoise: FRACTAL_NOISE_SKETCH,
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Get a noise sketch by name
|
|
12
|
+
*/
|
|
13
|
+
export function getNoiseSketch(name) {
|
|
14
|
+
return NOISE_SKETCHES[name];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Check if a sketch name is valid
|
|
18
|
+
*/
|
|
19
|
+
export function isValidNoiseSketch(name) {
|
|
20
|
+
return name in NOISE_SKETCHES;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get list of all available noise sketch names
|
|
24
|
+
*/
|
|
25
|
+
export function getAvailableNoiseSketchNames() {
|
|
26
|
+
return Object.keys(NOISE_SKETCHES);
|
|
27
|
+
}
|
|
28
|
+
export { FRACTAL_NOISE_SKETCH };
|
package/dist/p5-runtime.d.ts
CHANGED
|
@@ -1,11 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NexArt Code Mode Runtime SDK - p5-like Runtime
|
|
3
|
-
* Version: 0.1.1
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* ╔══════════════════════════════════════════════════════════════════════════╗
|
|
5
|
+
* ║ CODE MODE PROTOCOL v1.0.0 (Phase 1) — LOCKED ║
|
|
6
|
+
* ║ ║
|
|
7
|
+
* ║ Status: HARD PROTOCOL ENFORCEMENT ║
|
|
8
|
+
* ║ This is the stable, canonical execution surface. ║
|
|
9
|
+
* ║ SDKs, ByX, and external builders can depend on this API. ║
|
|
10
|
+
* ║ ║
|
|
11
|
+
* ║ Phase 1 Surface: ║
|
|
12
|
+
* ║ - VAR[0..9]: 10 read-only protocol variables (0-100 range) ║
|
|
13
|
+
* ║ - Drawing: line, rect, ellipse, circle, triangle, quad, arc, etc. ║
|
|
14
|
+
* ║ - Style: fill, stroke, colorMode, strokeWeight ║
|
|
15
|
+
* ║ - Transform: push, pop, translate, rotate, scale ║
|
|
16
|
+
* ║ - Random: random(), randomSeed(), randomGaussian() (seeded) ║
|
|
17
|
+
* ║ - Noise: noise(), noiseSeed(), noiseDetail() (seeded) ║
|
|
18
|
+
* ║ - Math: map, constrain, lerp, lerpColor, dist, mag, norm ║
|
|
19
|
+
* ║ - Color: Full CSS format support, color extraction functions ║
|
|
20
|
+
* ║ - Time: frameCount, t, time, tGlobal ║
|
|
21
|
+
* ║ ║
|
|
22
|
+
* ║ Determinism Guarantees: ║
|
|
23
|
+
* ║ - Same code + same seed + same VARs = identical output ║
|
|
24
|
+
* ║ - No external state, no browser entropy, no time-based drift ║
|
|
25
|
+
* ║ - Randomness ONLY from: random(), noise() (both seeded) ║
|
|
26
|
+
* ║ ║
|
|
27
|
+
* ║ ⚠️ Future changes require Phase 2+ ║
|
|
28
|
+
* ╚══════════════════════════════════════════════════════════════════════════╝
|
|
7
29
|
*/
|
|
8
30
|
import type { TimeVariables } from './types';
|
|
31
|
+
/**
|
|
32
|
+
* Code Mode Protocol Version
|
|
33
|
+
* This constant defines the locked protocol version.
|
|
34
|
+
* Changes to the execution surface require a version bump.
|
|
35
|
+
*/
|
|
36
|
+
export declare const CODE_MODE_PROTOCOL_VERSION = "1.0.0";
|
|
37
|
+
export declare const CODE_MODE_PROTOCOL_PHASE = 1;
|
|
38
|
+
export declare const CODE_MODE_ENFORCEMENT: "HARD";
|
|
9
39
|
export interface P5Runtime {
|
|
10
40
|
[key: string]: any;
|
|
11
41
|
width: number;
|
|
@@ -16,6 +46,28 @@ export interface P5Runtime {
|
|
|
16
46
|
HALF_PI: number;
|
|
17
47
|
QUARTER_PI: number;
|
|
18
48
|
}
|
|
19
|
-
export
|
|
49
|
+
export interface P5RuntimeConfig {
|
|
50
|
+
seed?: number;
|
|
51
|
+
}
|
|
52
|
+
export declare function createP5Runtime(canvas: HTMLCanvasElement, width: number, height: number, config?: P5RuntimeConfig): P5Runtime;
|
|
20
53
|
export declare function injectTimeVariables(p: P5Runtime, time: TimeVariables): void;
|
|
54
|
+
/**
|
|
55
|
+
* VAR Protocol Constants (Phase 1 — Protocol v1.0.0)
|
|
56
|
+
* SDK v1.0.2: VAR input is optional (0-10 elements), but runtime always has 10
|
|
57
|
+
*/
|
|
58
|
+
export declare const VAR_COUNT = 10;
|
|
59
|
+
export declare const VAR_MIN = 0;
|
|
60
|
+
export declare const VAR_MAX = 100;
|
|
61
|
+
/**
|
|
62
|
+
* Create a protected, read-only VAR array for protocol execution.
|
|
63
|
+
*
|
|
64
|
+
* SDK v1.0.2 Rules (Protocol v1.0.0):
|
|
65
|
+
* - Input accepts 0-10 elements
|
|
66
|
+
* - Runtime VAR is ALWAYS 10 elements (padded with zeros)
|
|
67
|
+
* - Values are numeric, must be in 0-100 range (validated upstream)
|
|
68
|
+
* - Read-only: writes throw descriptive errors
|
|
69
|
+
* - Available in both setup() and draw()
|
|
70
|
+
*/
|
|
71
|
+
export declare function createProtocolVAR(vars?: number[]): readonly number[];
|
|
72
|
+
export declare function injectProtocolVariables(p: P5Runtime, vars?: number[]): void;
|
|
21
73
|
//# sourceMappingURL=p5-runtime.d.ts.map
|
package/dist/p5-runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"p5-runtime.d.ts","sourceRoot":"","sources":["../p5-runtime.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"p5-runtime.d.ts","sourceRoot":"","sources":["../p5-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,UAAU,CAAC;AAClD,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAC1C,eAAO,MAAM,qBAAqB,EAAG,MAAe,CAAC;AAErD,MAAM,WAAW,SAAS;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAmED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,eAAe,GACvB,SAAS,CA0hBX;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAE3E;AAED;;;GAGG;AACH,eAAO,MAAM,SAAS,KAAK,CAAC;AAC5B,eAAO,MAAM,OAAO,IAAI,CAAC;AACzB,eAAO,MAAM,OAAO,MAAM,CAAC;AAE3B;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,CAmCpE;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAE3E"}
|
package/dist/p5-runtime.js
CHANGED
|
@@ -1,11 +1,97 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NexArt Code Mode Runtime SDK - p5-like Runtime
|
|
3
|
-
* Version: 0.1.1
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* ╔══════════════════════════════════════════════════════════════════════════╗
|
|
5
|
+
* ║ CODE MODE PROTOCOL v1.0.0 (Phase 1) — LOCKED ║
|
|
6
|
+
* ║ ║
|
|
7
|
+
* ║ Status: HARD PROTOCOL ENFORCEMENT ║
|
|
8
|
+
* ║ This is the stable, canonical execution surface. ║
|
|
9
|
+
* ║ SDKs, ByX, and external builders can depend on this API. ║
|
|
10
|
+
* ║ ║
|
|
11
|
+
* ║ Phase 1 Surface: ║
|
|
12
|
+
* ║ - VAR[0..9]: 10 read-only protocol variables (0-100 range) ║
|
|
13
|
+
* ║ - Drawing: line, rect, ellipse, circle, triangle, quad, arc, etc. ║
|
|
14
|
+
* ║ - Style: fill, stroke, colorMode, strokeWeight ║
|
|
15
|
+
* ║ - Transform: push, pop, translate, rotate, scale ║
|
|
16
|
+
* ║ - Random: random(), randomSeed(), randomGaussian() (seeded) ║
|
|
17
|
+
* ║ - Noise: noise(), noiseSeed(), noiseDetail() (seeded) ║
|
|
18
|
+
* ║ - Math: map, constrain, lerp, lerpColor, dist, mag, norm ║
|
|
19
|
+
* ║ - Color: Full CSS format support, color extraction functions ║
|
|
20
|
+
* ║ - Time: frameCount, t, time, tGlobal ║
|
|
21
|
+
* ║ ║
|
|
22
|
+
* ║ Determinism Guarantees: ║
|
|
23
|
+
* ║ - Same code + same seed + same VARs = identical output ║
|
|
24
|
+
* ║ - No external state, no browser entropy, no time-based drift ║
|
|
25
|
+
* ║ - Randomness ONLY from: random(), noise() (both seeded) ║
|
|
26
|
+
* ║ ║
|
|
27
|
+
* ║ ⚠️ Future changes require Phase 2+ ║
|
|
28
|
+
* ╚══════════════════════════════════════════════════════════════════════════╝
|
|
7
29
|
*/
|
|
8
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Code Mode Protocol Version
|
|
32
|
+
* This constant defines the locked protocol version.
|
|
33
|
+
* Changes to the execution surface require a version bump.
|
|
34
|
+
*/
|
|
35
|
+
export const CODE_MODE_PROTOCOL_VERSION = '1.0.0';
|
|
36
|
+
export const CODE_MODE_PROTOCOL_PHASE = 1;
|
|
37
|
+
export const CODE_MODE_ENFORCEMENT = 'HARD';
|
|
38
|
+
/**
|
|
39
|
+
* Create a seeded random number generator (Mulberry32)
|
|
40
|
+
* Same algorithm used in SoundArt for consistency
|
|
41
|
+
*/
|
|
42
|
+
function createSeededRNG(seed = 123456) {
|
|
43
|
+
let a = seed >>> 0;
|
|
44
|
+
return () => {
|
|
45
|
+
a += 0x6D2B79F5;
|
|
46
|
+
let t = Math.imul(a ^ (a >>> 15), a | 1);
|
|
47
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
48
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create improved Perlin-like noise with seeding support
|
|
53
|
+
*/
|
|
54
|
+
function createSeededNoise(seed = 0) {
|
|
55
|
+
const permutation = [];
|
|
56
|
+
const rng = createSeededRNG(seed);
|
|
57
|
+
for (let i = 0; i < 256; i++) {
|
|
58
|
+
permutation[i] = i;
|
|
59
|
+
}
|
|
60
|
+
for (let i = 255; i > 0; i--) {
|
|
61
|
+
const j = Math.floor(rng() * (i + 1));
|
|
62
|
+
[permutation[i], permutation[j]] = [permutation[j], permutation[i]];
|
|
63
|
+
}
|
|
64
|
+
for (let i = 0; i < 256; i++) {
|
|
65
|
+
permutation[256 + i] = permutation[i];
|
|
66
|
+
}
|
|
67
|
+
const fade = (t) => t * t * t * (t * (t * 6 - 15) + 10);
|
|
68
|
+
const lerp = (a, b, t) => a + t * (b - a);
|
|
69
|
+
const grad = (hash, x, y, z) => {
|
|
70
|
+
const h = hash & 15;
|
|
71
|
+
const u = h < 8 ? x : y;
|
|
72
|
+
const v = h < 4 ? y : h === 12 || h === 14 ? x : z;
|
|
73
|
+
return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
|
|
74
|
+
};
|
|
75
|
+
return (x, y = 0, z = 0) => {
|
|
76
|
+
const X = Math.floor(x) & 255;
|
|
77
|
+
const Y = Math.floor(y) & 255;
|
|
78
|
+
const Z = Math.floor(z) & 255;
|
|
79
|
+
x -= Math.floor(x);
|
|
80
|
+
y -= Math.floor(y);
|
|
81
|
+
z -= Math.floor(z);
|
|
82
|
+
const u = fade(x);
|
|
83
|
+
const v = fade(y);
|
|
84
|
+
const w = fade(z);
|
|
85
|
+
const A = permutation[X] + Y;
|
|
86
|
+
const AA = permutation[A] + Z;
|
|
87
|
+
const AB = permutation[A + 1] + Z;
|
|
88
|
+
const B = permutation[X + 1] + Y;
|
|
89
|
+
const BA = permutation[B] + Z;
|
|
90
|
+
const BB = permutation[B + 1] + Z;
|
|
91
|
+
return (lerp(lerp(lerp(grad(permutation[AA], x, y, z), grad(permutation[BA], x - 1, y, z), u), lerp(grad(permutation[AB], x, y - 1, z), grad(permutation[BB], x - 1, y - 1, z), u), v), lerp(lerp(grad(permutation[AA + 1], x, y, z - 1), grad(permutation[BA + 1], x - 1, y, z - 1), u), lerp(grad(permutation[AB + 1], x, y - 1, z - 1), grad(permutation[BB + 1], x - 1, y - 1, z - 1), u), v), w) + 1) / 2;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export function createP5Runtime(canvas, width, height, config) {
|
|
9
95
|
const ctx = canvas.getContext('2d', { willReadFrequently: true });
|
|
10
96
|
let currentFill = 'rgba(255, 255, 255, 1)';
|
|
11
97
|
let currentStroke = 'rgba(0, 0, 0, 1)';
|
|
@@ -14,14 +100,119 @@ export function createP5Runtime(canvas, width, height) {
|
|
|
14
100
|
let currentStrokeWeight = 1;
|
|
15
101
|
let colorModeSettings = { mode: 'RGB', maxR: 255, maxG: 255, maxB: 255, maxA: 255 };
|
|
16
102
|
let shapeStarted = false;
|
|
103
|
+
// Seeded random state
|
|
104
|
+
let randomSeedValue = config?.seed ?? Math.floor(Math.random() * 2147483647);
|
|
105
|
+
let rng = createSeededRNG(randomSeedValue);
|
|
106
|
+
// Seeded noise state
|
|
107
|
+
let noiseSeedValue = config?.seed ?? 0;
|
|
108
|
+
let noiseFunc = createSeededNoise(noiseSeedValue);
|
|
109
|
+
let noiseOctaves = 4;
|
|
110
|
+
let noiseFalloff = 0.5;
|
|
111
|
+
/**
|
|
112
|
+
* Parse CSS color string to normalized RGBA values
|
|
113
|
+
* Supports: hex (#RGB, #RRGGBB, #RRGGBBAA), rgb(), rgba(), hsl(), hsla()
|
|
114
|
+
*/
|
|
115
|
+
const parseCssColor = (str) => {
|
|
116
|
+
const s = str.trim();
|
|
117
|
+
// Hex format: #RGB, #RRGGBB, #RRGGBBAA
|
|
118
|
+
if (s.startsWith('#')) {
|
|
119
|
+
const hex = s.slice(1);
|
|
120
|
+
if (hex.length === 3) {
|
|
121
|
+
const r = parseInt(hex[0] + hex[0], 16);
|
|
122
|
+
const g = parseInt(hex[1] + hex[1], 16);
|
|
123
|
+
const b = parseInt(hex[2] + hex[2], 16);
|
|
124
|
+
return { r, g, b, a: 1 };
|
|
125
|
+
}
|
|
126
|
+
else if (hex.length === 6) {
|
|
127
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
128
|
+
const g = parseInt(hex.slice(2, 4), 16);
|
|
129
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
130
|
+
return { r, g, b, a: 1 };
|
|
131
|
+
}
|
|
132
|
+
else if (hex.length === 8) {
|
|
133
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
134
|
+
const g = parseInt(hex.slice(2, 4), 16);
|
|
135
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
136
|
+
const a = parseInt(hex.slice(6, 8), 16) / 255;
|
|
137
|
+
return { r, g, b, a };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// rgb(r, g, b) or rgb(r g b)
|
|
141
|
+
const rgbMatch = s.match(/^rgb\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*\)$/i);
|
|
142
|
+
if (rgbMatch) {
|
|
143
|
+
return {
|
|
144
|
+
r: parseInt(rgbMatch[1]),
|
|
145
|
+
g: parseInt(rgbMatch[2]),
|
|
146
|
+
b: parseInt(rgbMatch[3]),
|
|
147
|
+
a: 1
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
// rgba(r, g, b, a) or rgba(r g b / a)
|
|
151
|
+
const rgbaMatch = s.match(/^rgba\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\/\s]\s*([\d.]+)\s*\)$/i);
|
|
152
|
+
if (rgbaMatch) {
|
|
153
|
+
return {
|
|
154
|
+
r: parseInt(rgbaMatch[1]),
|
|
155
|
+
g: parseInt(rgbaMatch[2]),
|
|
156
|
+
b: parseInt(rgbaMatch[3]),
|
|
157
|
+
a: parseFloat(rgbaMatch[4])
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// hsl(h, s%, l%) or hsla(h, s%, l%, a)
|
|
161
|
+
const hslMatch = s.match(/^hsla?\s*\(\s*([\d.]+)\s*[,\s]\s*([\d.]+)%?\s*[,\s]\s*([\d.]+)%?\s*(?:[,\/\s]\s*([\d.]+))?\s*\)$/i);
|
|
162
|
+
if (hslMatch) {
|
|
163
|
+
const h = parseFloat(hslMatch[1]) / 360;
|
|
164
|
+
const sat = parseFloat(hslMatch[2]) / 100;
|
|
165
|
+
const l = parseFloat(hslMatch[3]) / 100;
|
|
166
|
+
const a = hslMatch[4] ? parseFloat(hslMatch[4]) : 1;
|
|
167
|
+
// HSL to RGB conversion
|
|
168
|
+
let r, g, b;
|
|
169
|
+
if (sat === 0) {
|
|
170
|
+
r = g = b = l;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
const hue2rgb = (p, q, t) => {
|
|
174
|
+
if (t < 0)
|
|
175
|
+
t += 1;
|
|
176
|
+
if (t > 1)
|
|
177
|
+
t -= 1;
|
|
178
|
+
if (t < 1 / 6)
|
|
179
|
+
return p + (q - p) * 6 * t;
|
|
180
|
+
if (t < 1 / 2)
|
|
181
|
+
return q;
|
|
182
|
+
if (t < 2 / 3)
|
|
183
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
184
|
+
return p;
|
|
185
|
+
};
|
|
186
|
+
const q = l < 0.5 ? l * (1 + sat) : l + sat - l * sat;
|
|
187
|
+
const p = 2 * l - q;
|
|
188
|
+
r = hue2rgb(p, q, h + 1 / 3);
|
|
189
|
+
g = hue2rgb(p, q, h);
|
|
190
|
+
b = hue2rgb(p, q, h - 1 / 3);
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
r: Math.round(r * 255),
|
|
194
|
+
g: Math.round(g * 255),
|
|
195
|
+
b: Math.round(b * 255),
|
|
196
|
+
a
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
return null;
|
|
200
|
+
};
|
|
17
201
|
const parseColor = (...args) => {
|
|
18
202
|
if (args.length === 0)
|
|
19
203
|
return 'rgba(0, 0, 0, 1)';
|
|
20
204
|
const { mode, maxR, maxG, maxB, maxA } = colorModeSettings;
|
|
21
205
|
if (args.length === 1) {
|
|
22
206
|
const val = args[0];
|
|
23
|
-
if (typeof val === 'string')
|
|
207
|
+
if (typeof val === 'string') {
|
|
208
|
+
// Try to parse CSS color formats
|
|
209
|
+
const parsed = parseCssColor(val);
|
|
210
|
+
if (parsed) {
|
|
211
|
+
return `rgba(${parsed.r}, ${parsed.g}, ${parsed.b}, ${parsed.a})`;
|
|
212
|
+
}
|
|
213
|
+
// Return as-is for named colors (canvas handles them)
|
|
24
214
|
return val;
|
|
215
|
+
}
|
|
25
216
|
if (mode === 'HSB') {
|
|
26
217
|
return `hsla(${val}, 100%, 50%, 1)`;
|
|
27
218
|
}
|
|
@@ -112,7 +303,71 @@ export function createP5Runtime(canvas, width, height) {
|
|
|
112
303
|
},
|
|
113
304
|
color: (...args) => parseColor(...args),
|
|
114
305
|
lerpColor: (c1, c2, amt) => {
|
|
115
|
-
|
|
306
|
+
// Parse both colors
|
|
307
|
+
const color1 = parseCssColor(c1) || { r: 0, g: 0, b: 0, a: 1 };
|
|
308
|
+
const color2 = parseCssColor(c2) || { r: 255, g: 255, b: 255, a: 1 };
|
|
309
|
+
// Linearly interpolate each channel
|
|
310
|
+
const r = Math.round(color1.r + (color2.r - color1.r) * amt);
|
|
311
|
+
const g = Math.round(color1.g + (color2.g - color1.g) * amt);
|
|
312
|
+
const b = Math.round(color1.b + (color2.b - color1.b) * amt);
|
|
313
|
+
const a = color1.a + (color2.a - color1.a) * amt;
|
|
314
|
+
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
315
|
+
},
|
|
316
|
+
red: (color) => {
|
|
317
|
+
const parsed = parseCssColor(color);
|
|
318
|
+
return parsed ? parsed.r : 0;
|
|
319
|
+
},
|
|
320
|
+
green: (color) => {
|
|
321
|
+
const parsed = parseCssColor(color);
|
|
322
|
+
return parsed ? parsed.g : 0;
|
|
323
|
+
},
|
|
324
|
+
blue: (color) => {
|
|
325
|
+
const parsed = parseCssColor(color);
|
|
326
|
+
return parsed ? parsed.b : 0;
|
|
327
|
+
},
|
|
328
|
+
alpha: (color) => {
|
|
329
|
+
const parsed = parseCssColor(color);
|
|
330
|
+
return parsed ? parsed.a * 255 : 255;
|
|
331
|
+
},
|
|
332
|
+
brightness: (color) => {
|
|
333
|
+
const parsed = parseCssColor(color);
|
|
334
|
+
if (!parsed)
|
|
335
|
+
return 0;
|
|
336
|
+
return Math.max(parsed.r, parsed.g, parsed.b) / 255 * 100;
|
|
337
|
+
},
|
|
338
|
+
saturation: (color) => {
|
|
339
|
+
const parsed = parseCssColor(color);
|
|
340
|
+
if (!parsed)
|
|
341
|
+
return 0;
|
|
342
|
+
const max = Math.max(parsed.r, parsed.g, parsed.b);
|
|
343
|
+
const min = Math.min(parsed.r, parsed.g, parsed.b);
|
|
344
|
+
if (max === 0)
|
|
345
|
+
return 0;
|
|
346
|
+
return ((max - min) / max) * 100;
|
|
347
|
+
},
|
|
348
|
+
hue: (color) => {
|
|
349
|
+
const parsed = parseCssColor(color);
|
|
350
|
+
if (!parsed)
|
|
351
|
+
return 0;
|
|
352
|
+
const { r, g, b } = parsed;
|
|
353
|
+
const max = Math.max(r, g, b);
|
|
354
|
+
const min = Math.min(r, g, b);
|
|
355
|
+
if (max === min)
|
|
356
|
+
return 0;
|
|
357
|
+
let h = 0;
|
|
358
|
+
const d = max - min;
|
|
359
|
+
switch (max) {
|
|
360
|
+
case r:
|
|
361
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
362
|
+
break;
|
|
363
|
+
case g:
|
|
364
|
+
h = ((b - r) / d + 2) / 6;
|
|
365
|
+
break;
|
|
366
|
+
case b:
|
|
367
|
+
h = ((r - g) / d + 4) / 6;
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
return h * 360;
|
|
116
371
|
},
|
|
117
372
|
// Shape functions
|
|
118
373
|
ellipse: (x, y, w, h) => {
|
|
@@ -242,30 +497,53 @@ export function createP5Runtime(canvas, width, height) {
|
|
|
242
497
|
resetMatrix: () => {
|
|
243
498
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
244
499
|
},
|
|
245
|
-
// Math functions
|
|
500
|
+
// Math functions - SEEDED for determinism
|
|
246
501
|
random: (min, max) => {
|
|
502
|
+
// Support random() with arrays
|
|
503
|
+
if (Array.isArray(min)) {
|
|
504
|
+
return min[Math.floor(rng() * min.length)];
|
|
505
|
+
}
|
|
247
506
|
if (min === undefined)
|
|
248
|
-
return
|
|
507
|
+
return rng();
|
|
249
508
|
if (max === undefined)
|
|
250
|
-
return
|
|
251
|
-
return min +
|
|
509
|
+
return rng() * min;
|
|
510
|
+
return min + rng() * (max - min);
|
|
252
511
|
},
|
|
253
512
|
randomSeed: (seed) => {
|
|
254
|
-
|
|
513
|
+
randomSeedValue = seed;
|
|
514
|
+
rng = createSeededRNG(seed);
|
|
515
|
+
},
|
|
516
|
+
randomGaussian: (mean = 0, sd = 1) => {
|
|
517
|
+
// Box-Muller transform for Gaussian distribution
|
|
518
|
+
const u1 = rng();
|
|
519
|
+
const u2 = rng();
|
|
520
|
+
const z0 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
|
|
521
|
+
return z0 * sd + mean;
|
|
255
522
|
},
|
|
256
523
|
noise: (x, y, z) => {
|
|
257
|
-
//
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
524
|
+
// Use seeded Perlin noise with octaves
|
|
525
|
+
let total = 0;
|
|
526
|
+
let frequency = 1;
|
|
527
|
+
let amplitude = 1;
|
|
528
|
+
let maxValue = 0;
|
|
529
|
+
for (let i = 0; i < noiseOctaves; i++) {
|
|
530
|
+
total += noiseFunc(x * frequency, (y ?? 0) * frequency, (z ?? 0) * frequency) * amplitude;
|
|
531
|
+
maxValue += amplitude;
|
|
532
|
+
amplitude *= noiseFalloff;
|
|
533
|
+
frequency *= 2;
|
|
534
|
+
}
|
|
535
|
+
return total / maxValue;
|
|
536
|
+
},
|
|
537
|
+
noiseSeed: (seed) => {
|
|
538
|
+
noiseSeedValue = seed;
|
|
539
|
+
noiseFunc = createSeededNoise(seed);
|
|
540
|
+
},
|
|
541
|
+
noiseDetail: (lod, falloff) => {
|
|
542
|
+
noiseOctaves = Math.max(1, Math.min(8, lod));
|
|
543
|
+
if (falloff !== undefined) {
|
|
544
|
+
noiseFalloff = Math.max(0, Math.min(1, falloff));
|
|
545
|
+
}
|
|
266
546
|
},
|
|
267
|
-
noiseSeed: (seed) => { },
|
|
268
|
-
noiseDetail: (lod, falloff) => { },
|
|
269
547
|
map: (value, start1, stop1, start2, stop2) => {
|
|
270
548
|
return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
|
|
271
549
|
},
|
|
@@ -316,3 +594,51 @@ export function createP5Runtime(canvas, width, height) {
|
|
|
316
594
|
export function injectTimeVariables(p, time) {
|
|
317
595
|
p.frameCount = time.frameCount;
|
|
318
596
|
}
|
|
597
|
+
/**
|
|
598
|
+
* VAR Protocol Constants (Phase 1 — Protocol v1.0.0)
|
|
599
|
+
* SDK v1.0.2: VAR input is optional (0-10 elements), but runtime always has 10
|
|
600
|
+
*/
|
|
601
|
+
export const VAR_COUNT = 10; // Exactly 10 protocol variables: VAR[0..9]
|
|
602
|
+
export const VAR_MIN = 0; // Minimum value
|
|
603
|
+
export const VAR_MAX = 100; // Maximum value (normalized range)
|
|
604
|
+
/**
|
|
605
|
+
* Create a protected, read-only VAR array for protocol execution.
|
|
606
|
+
*
|
|
607
|
+
* SDK v1.0.2 Rules (Protocol v1.0.0):
|
|
608
|
+
* - Input accepts 0-10 elements
|
|
609
|
+
* - Runtime VAR is ALWAYS 10 elements (padded with zeros)
|
|
610
|
+
* - Values are numeric, must be in 0-100 range (validated upstream)
|
|
611
|
+
* - Read-only: writes throw descriptive errors
|
|
612
|
+
* - Available in both setup() and draw()
|
|
613
|
+
*/
|
|
614
|
+
export function createProtocolVAR(vars) {
|
|
615
|
+
// Create frozen 10-element array (upstream normalizeVars ensures this)
|
|
616
|
+
const normalizedVars = [];
|
|
617
|
+
for (let i = 0; i < VAR_COUNT; i++) {
|
|
618
|
+
normalizedVars[i] = vars?.[i] ?? 0;
|
|
619
|
+
}
|
|
620
|
+
// Freeze the array to prevent modifications
|
|
621
|
+
const frozenVars = Object.freeze(normalizedVars);
|
|
622
|
+
// Wrap in Proxy for descriptive error messages on write attempts
|
|
623
|
+
return new Proxy(frozenVars, {
|
|
624
|
+
set(_target, prop, _value) {
|
|
625
|
+
const propName = typeof prop === 'symbol' ? prop.toString() : prop;
|
|
626
|
+
throw new Error(`[Code Mode Protocol Error] VAR is read-only. ` +
|
|
627
|
+
`Cannot write to VAR[${propName}]. ` +
|
|
628
|
+
`VAR[0..9] are protocol inputs, not sketch state.`);
|
|
629
|
+
},
|
|
630
|
+
deleteProperty(_target, prop) {
|
|
631
|
+
const propName = typeof prop === 'symbol' ? prop.toString() : prop;
|
|
632
|
+
throw new Error(`[Code Mode Protocol Error] VAR is read-only. ` +
|
|
633
|
+
`Cannot delete VAR[${propName}].`);
|
|
634
|
+
},
|
|
635
|
+
defineProperty(_target, prop) {
|
|
636
|
+
const propName = typeof prop === 'symbol' ? prop.toString() : prop;
|
|
637
|
+
throw new Error(`[Code Mode Protocol Error] Cannot define new VAR properties. ` +
|
|
638
|
+
`VAR is fixed at 10 elements (VAR[0..9]). Attempted: ${propName}`);
|
|
639
|
+
},
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
export function injectProtocolVariables(p, vars) {
|
|
643
|
+
p.VAR = createProtocolVAR(vars);
|
|
644
|
+
}
|