@nexart/ui-renderer 0.2.1 → 0.3.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/README.md +78 -4
- package/dist/compiler.d.ts +18 -2
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +25 -11
- package/dist/index.d.ts +19 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -7
- package/dist/presets/backgrounds.d.ts +14 -0
- package/dist/presets/backgrounds.d.ts.map +1 -0
- package/dist/presets/backgrounds.js +222 -0
- package/dist/presets/index.d.ts +7 -0
- package/dist/presets/index.d.ts.map +1 -0
- package/dist/presets/index.js +6 -0
- package/dist/presets/primitives.d.ts +16 -0
- package/dist/presets/primitives.d.ts.map +1 -0
- package/dist/presets/primitives.js +282 -0
- package/dist/presets/sketch-wrapper.d.ts +14 -0
- package/dist/presets/sketch-wrapper.d.ts.map +1 -0
- package/dist/presets/sketch-wrapper.js +70 -0
- package/dist/preview/code-renderer.d.ts +25 -0
- package/dist/preview/code-renderer.d.ts.map +1 -0
- package/dist/preview/code-renderer.js +651 -0
- package/dist/preview/primitives/sketch.d.ts +14 -0
- package/dist/preview/primitives/sketch.d.ts.map +1 -0
- package/dist/preview/primitives/sketch.js +407 -0
- package/dist/preview/renderer.d.ts +1 -1
- package/dist/preview/renderer.d.ts.map +1 -1
- package/dist/preview/renderer.js +23 -13
- package/dist/preview/unified-renderer.d.ts +16 -0
- package/dist/preview/unified-renderer.d.ts.map +1 -0
- package/dist/preview/unified-renderer.js +270 -0
- package/dist/system.d.ts +7 -3
- package/dist/system.d.ts.map +1 -1
- package/dist/system.js +187 -11
- package/dist/types.d.ts +125 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +12 -3
- package/package.json +2 -2
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nexart/ui-renderer v0.2.1 - Sketch Primitive Renderer
|
|
3
|
+
*
|
|
4
|
+
* Executes raw Code Mode p5-like sketches.
|
|
5
|
+
* This is NOT canonical output - for preview/exploration only.
|
|
6
|
+
*/
|
|
7
|
+
function createSeededRNG(seed = 123456) {
|
|
8
|
+
let a = seed >>> 0;
|
|
9
|
+
return () => {
|
|
10
|
+
a += 0x6D2B79F5;
|
|
11
|
+
let t = Math.imul(a ^ (a >>> 15), a | 1);
|
|
12
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
13
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function createSeededNoise(seed = 0) {
|
|
17
|
+
const permutation = [];
|
|
18
|
+
const rng = createSeededRNG(seed);
|
|
19
|
+
for (let i = 0; i < 256; i++) {
|
|
20
|
+
permutation[i] = i;
|
|
21
|
+
}
|
|
22
|
+
for (let i = 255; i > 0; i--) {
|
|
23
|
+
const j = Math.floor(rng() * (i + 1));
|
|
24
|
+
[permutation[i], permutation[j]] = [permutation[j], permutation[i]];
|
|
25
|
+
}
|
|
26
|
+
for (let i = 0; i < 256; i++) {
|
|
27
|
+
permutation[256 + i] = permutation[i];
|
|
28
|
+
}
|
|
29
|
+
const fade = (t) => t * t * t * (t * (t * 6 - 15) + 10);
|
|
30
|
+
const lerp = (a, b, t) => a + t * (b - a);
|
|
31
|
+
const grad = (hash, x, y, z) => {
|
|
32
|
+
const h = hash & 15;
|
|
33
|
+
const u = h < 8 ? x : y;
|
|
34
|
+
const v = h < 4 ? y : h === 12 || h === 14 ? x : z;
|
|
35
|
+
return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
|
|
36
|
+
};
|
|
37
|
+
return (x, y = 0, z = 0) => {
|
|
38
|
+
const X = Math.floor(x) & 255;
|
|
39
|
+
const Y = Math.floor(y) & 255;
|
|
40
|
+
const Z = Math.floor(z) & 255;
|
|
41
|
+
x -= Math.floor(x);
|
|
42
|
+
y -= Math.floor(y);
|
|
43
|
+
z -= Math.floor(z);
|
|
44
|
+
const u = fade(x);
|
|
45
|
+
const v = fade(y);
|
|
46
|
+
const w = fade(z);
|
|
47
|
+
const A = permutation[X] + Y;
|
|
48
|
+
const AA = permutation[A] + Z;
|
|
49
|
+
const AB = permutation[A + 1] + Z;
|
|
50
|
+
const B = permutation[X + 1] + Y;
|
|
51
|
+
const BA = permutation[B] + Z;
|
|
52
|
+
const BB = permutation[B + 1] + Z;
|
|
53
|
+
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;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function createP5Runtime(ctx, width, height, seed) {
|
|
57
|
+
let currentFill = 'rgba(255, 255, 255, 1)';
|
|
58
|
+
let currentStroke = 'rgba(0, 0, 0, 1)';
|
|
59
|
+
let strokeEnabled = true;
|
|
60
|
+
let fillEnabled = true;
|
|
61
|
+
let currentStrokeWeight = 1;
|
|
62
|
+
let colorModeSettings = { mode: 'RGB', maxR: 255, maxG: 255, maxB: 255, maxA: 255 };
|
|
63
|
+
let shapeStarted = false;
|
|
64
|
+
let rng = createSeededRNG(seed);
|
|
65
|
+
let noiseFunc = createSeededNoise(seed);
|
|
66
|
+
let noiseOctaves = 4;
|
|
67
|
+
let noiseFalloff = 0.5;
|
|
68
|
+
const parseColor = (...args) => {
|
|
69
|
+
if (args.length === 0)
|
|
70
|
+
return 'rgba(0, 0, 0, 1)';
|
|
71
|
+
const { mode, maxR, maxG, maxB, maxA } = colorModeSettings;
|
|
72
|
+
if (args.length === 1) {
|
|
73
|
+
const val = args[0];
|
|
74
|
+
if (typeof val === 'string')
|
|
75
|
+
return val;
|
|
76
|
+
if (mode === 'HSB') {
|
|
77
|
+
return `hsla(${val}, 100%, 50%, 1)`;
|
|
78
|
+
}
|
|
79
|
+
const gray = Math.round((val / maxR) * 255);
|
|
80
|
+
return `rgba(${gray}, ${gray}, ${gray}, 1)`;
|
|
81
|
+
}
|
|
82
|
+
if (args.length === 2) {
|
|
83
|
+
const [gray, alpha] = args;
|
|
84
|
+
const g = Math.round((gray / maxR) * 255);
|
|
85
|
+
const a = alpha / maxA;
|
|
86
|
+
return `rgba(${g}, ${g}, ${g}, ${a})`;
|
|
87
|
+
}
|
|
88
|
+
if (args.length === 3) {
|
|
89
|
+
const [r, g, b] = args;
|
|
90
|
+
if (mode === 'HSB') {
|
|
91
|
+
return `hsla(${(r / maxR) * 360}, ${(g / maxG) * 100}%, ${(b / maxB) * 100}%, 1)`;
|
|
92
|
+
}
|
|
93
|
+
return `rgba(${Math.round((r / maxR) * 255)}, ${Math.round((g / maxG) * 255)}, ${Math.round((b / maxB) * 255)}, 1)`;
|
|
94
|
+
}
|
|
95
|
+
if (args.length === 4) {
|
|
96
|
+
const [r, g, b, a] = args;
|
|
97
|
+
if (mode === 'HSB') {
|
|
98
|
+
return `hsla(${(r / maxR) * 360}, ${(g / maxG) * 100}%, ${(b / maxB) * 100}%, ${a / maxA})`;
|
|
99
|
+
}
|
|
100
|
+
return `rgba(${Math.round((r / maxR) * 255)}, ${Math.round((g / maxG) * 255)}, ${Math.round((b / maxB) * 255)}, ${a / maxA})`;
|
|
101
|
+
}
|
|
102
|
+
return 'rgba(0, 0, 0, 1)';
|
|
103
|
+
};
|
|
104
|
+
const p = {
|
|
105
|
+
width,
|
|
106
|
+
height,
|
|
107
|
+
frameCount: 0,
|
|
108
|
+
PI: Math.PI,
|
|
109
|
+
TWO_PI: Math.PI * 2,
|
|
110
|
+
HALF_PI: Math.PI / 2,
|
|
111
|
+
QUARTER_PI: Math.PI / 4,
|
|
112
|
+
CORNER: 'corner',
|
|
113
|
+
CENTER: 'center',
|
|
114
|
+
CORNERS: 'corners',
|
|
115
|
+
RADIUS: 'radius',
|
|
116
|
+
ROUND: 'round',
|
|
117
|
+
SQUARE: 'square',
|
|
118
|
+
PROJECT: 'project',
|
|
119
|
+
MITER: 'miter',
|
|
120
|
+
BEVEL: 'bevel',
|
|
121
|
+
CLOSE: 'close',
|
|
122
|
+
background: (...args) => {
|
|
123
|
+
ctx.save();
|
|
124
|
+
ctx.fillStyle = parseColor(...args);
|
|
125
|
+
ctx.fillRect(0, 0, width, height);
|
|
126
|
+
ctx.restore();
|
|
127
|
+
},
|
|
128
|
+
clear: () => {
|
|
129
|
+
ctx.clearRect(0, 0, width, height);
|
|
130
|
+
},
|
|
131
|
+
fill: (...args) => {
|
|
132
|
+
fillEnabled = true;
|
|
133
|
+
currentFill = parseColor(...args);
|
|
134
|
+
ctx.fillStyle = currentFill;
|
|
135
|
+
},
|
|
136
|
+
noFill: () => {
|
|
137
|
+
fillEnabled = false;
|
|
138
|
+
},
|
|
139
|
+
stroke: (...args) => {
|
|
140
|
+
strokeEnabled = true;
|
|
141
|
+
currentStroke = parseColor(...args);
|
|
142
|
+
ctx.strokeStyle = currentStroke;
|
|
143
|
+
},
|
|
144
|
+
noStroke: () => {
|
|
145
|
+
strokeEnabled = false;
|
|
146
|
+
},
|
|
147
|
+
strokeWeight: (weight) => {
|
|
148
|
+
currentStrokeWeight = weight;
|
|
149
|
+
ctx.lineWidth = weight;
|
|
150
|
+
},
|
|
151
|
+
colorMode: (mode, max1, max2, max3, maxA) => {
|
|
152
|
+
colorModeSettings = {
|
|
153
|
+
mode: mode.toUpperCase(),
|
|
154
|
+
maxR: max1 ?? 255,
|
|
155
|
+
maxG: max2 ?? max1 ?? 255,
|
|
156
|
+
maxB: max3 ?? max1 ?? 255,
|
|
157
|
+
maxA: maxA ?? 255,
|
|
158
|
+
};
|
|
159
|
+
},
|
|
160
|
+
color: (...args) => parseColor(...args),
|
|
161
|
+
lerpColor: (c1, c2, amt) => c1,
|
|
162
|
+
ellipse: (x, y, w, h) => {
|
|
163
|
+
const rw = w / 2;
|
|
164
|
+
const rh = (h ?? w) / 2;
|
|
165
|
+
ctx.beginPath();
|
|
166
|
+
ctx.ellipse(x, y, rw, rh, 0, 0, Math.PI * 2);
|
|
167
|
+
if (fillEnabled)
|
|
168
|
+
ctx.fill();
|
|
169
|
+
if (strokeEnabled)
|
|
170
|
+
ctx.stroke();
|
|
171
|
+
},
|
|
172
|
+
circle: (x, y, d) => {
|
|
173
|
+
p.ellipse(x, y, d, d);
|
|
174
|
+
},
|
|
175
|
+
rect: (x, y, w, h, r) => {
|
|
176
|
+
const height = h ?? w;
|
|
177
|
+
ctx.beginPath();
|
|
178
|
+
if (r && r > 0) {
|
|
179
|
+
ctx.roundRect(x, y, w, height, r);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
ctx.rect(x, y, w, height);
|
|
183
|
+
}
|
|
184
|
+
if (fillEnabled)
|
|
185
|
+
ctx.fill();
|
|
186
|
+
if (strokeEnabled)
|
|
187
|
+
ctx.stroke();
|
|
188
|
+
},
|
|
189
|
+
square: (x, y, s, r) => {
|
|
190
|
+
p.rect(x, y, s, s, r);
|
|
191
|
+
},
|
|
192
|
+
line: (x1, y1, x2, y2) => {
|
|
193
|
+
ctx.beginPath();
|
|
194
|
+
ctx.moveTo(x1, y1);
|
|
195
|
+
ctx.lineTo(x2, y2);
|
|
196
|
+
if (strokeEnabled)
|
|
197
|
+
ctx.stroke();
|
|
198
|
+
},
|
|
199
|
+
point: (x, y) => {
|
|
200
|
+
ctx.beginPath();
|
|
201
|
+
ctx.arc(x, y, currentStrokeWeight / 2, 0, Math.PI * 2);
|
|
202
|
+
ctx.fillStyle = currentStroke;
|
|
203
|
+
ctx.fill();
|
|
204
|
+
},
|
|
205
|
+
triangle: (x1, y1, x2, y2, x3, y3) => {
|
|
206
|
+
ctx.beginPath();
|
|
207
|
+
ctx.moveTo(x1, y1);
|
|
208
|
+
ctx.lineTo(x2, y2);
|
|
209
|
+
ctx.lineTo(x3, y3);
|
|
210
|
+
ctx.closePath();
|
|
211
|
+
if (fillEnabled)
|
|
212
|
+
ctx.fill();
|
|
213
|
+
if (strokeEnabled)
|
|
214
|
+
ctx.stroke();
|
|
215
|
+
},
|
|
216
|
+
quad: (x1, y1, x2, y2, x3, y3, x4, y4) => {
|
|
217
|
+
ctx.beginPath();
|
|
218
|
+
ctx.moveTo(x1, y1);
|
|
219
|
+
ctx.lineTo(x2, y2);
|
|
220
|
+
ctx.lineTo(x3, y3);
|
|
221
|
+
ctx.lineTo(x4, y4);
|
|
222
|
+
ctx.closePath();
|
|
223
|
+
if (fillEnabled)
|
|
224
|
+
ctx.fill();
|
|
225
|
+
if (strokeEnabled)
|
|
226
|
+
ctx.stroke();
|
|
227
|
+
},
|
|
228
|
+
arc: (x, y, w, h, start, stop, mode) => {
|
|
229
|
+
ctx.beginPath();
|
|
230
|
+
ctx.ellipse(x, y, w / 2, h / 2, 0, start, stop);
|
|
231
|
+
if (mode === 'pie' || mode === 'PIE') {
|
|
232
|
+
ctx.lineTo(x, y);
|
|
233
|
+
ctx.closePath();
|
|
234
|
+
}
|
|
235
|
+
else if (mode === 'chord' || mode === 'CHORD') {
|
|
236
|
+
ctx.closePath();
|
|
237
|
+
}
|
|
238
|
+
if (fillEnabled)
|
|
239
|
+
ctx.fill();
|
|
240
|
+
if (strokeEnabled)
|
|
241
|
+
ctx.stroke();
|
|
242
|
+
},
|
|
243
|
+
beginShape: () => {
|
|
244
|
+
ctx.beginPath();
|
|
245
|
+
shapeStarted = false;
|
|
246
|
+
},
|
|
247
|
+
vertex: (x, y) => {
|
|
248
|
+
if (!shapeStarted) {
|
|
249
|
+
ctx.moveTo(x, y);
|
|
250
|
+
shapeStarted = true;
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
ctx.lineTo(x, y);
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
endShape: (mode) => {
|
|
257
|
+
if (mode === 'close' || mode === 'CLOSE') {
|
|
258
|
+
ctx.closePath();
|
|
259
|
+
}
|
|
260
|
+
if (fillEnabled)
|
|
261
|
+
ctx.fill();
|
|
262
|
+
if (strokeEnabled)
|
|
263
|
+
ctx.stroke();
|
|
264
|
+
shapeStarted = false;
|
|
265
|
+
},
|
|
266
|
+
push: () => {
|
|
267
|
+
ctx.save();
|
|
268
|
+
},
|
|
269
|
+
pop: () => {
|
|
270
|
+
ctx.restore();
|
|
271
|
+
ctx.fillStyle = currentFill;
|
|
272
|
+
ctx.strokeStyle = currentStroke;
|
|
273
|
+
ctx.lineWidth = currentStrokeWeight;
|
|
274
|
+
},
|
|
275
|
+
translate: (x, y) => {
|
|
276
|
+
ctx.translate(x, y);
|
|
277
|
+
},
|
|
278
|
+
rotate: (angle) => {
|
|
279
|
+
ctx.rotate(angle);
|
|
280
|
+
},
|
|
281
|
+
scale: (sx, sy) => {
|
|
282
|
+
ctx.scale(sx, sy ?? sx);
|
|
283
|
+
},
|
|
284
|
+
resetMatrix: () => {
|
|
285
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
286
|
+
},
|
|
287
|
+
random: (min, max) => {
|
|
288
|
+
if (Array.isArray(min)) {
|
|
289
|
+
return min[Math.floor(rng() * min.length)];
|
|
290
|
+
}
|
|
291
|
+
if (min === undefined)
|
|
292
|
+
return rng();
|
|
293
|
+
if (max === undefined)
|
|
294
|
+
return rng() * min;
|
|
295
|
+
return min + rng() * (max - min);
|
|
296
|
+
},
|
|
297
|
+
randomSeed: (seed) => {
|
|
298
|
+
rng = createSeededRNG(seed);
|
|
299
|
+
},
|
|
300
|
+
randomGaussian: (mean = 0, sd = 1) => {
|
|
301
|
+
const u1 = rng();
|
|
302
|
+
const u2 = rng();
|
|
303
|
+
const z0 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
|
|
304
|
+
return z0 * sd + mean;
|
|
305
|
+
},
|
|
306
|
+
noise: (x, y, z) => {
|
|
307
|
+
let total = 0;
|
|
308
|
+
let frequency = 1;
|
|
309
|
+
let amplitude = 1;
|
|
310
|
+
let maxValue = 0;
|
|
311
|
+
for (let i = 0; i < noiseOctaves; i++) {
|
|
312
|
+
total += noiseFunc(x * frequency, (y ?? 0) * frequency, (z ?? 0) * frequency) * amplitude;
|
|
313
|
+
maxValue += amplitude;
|
|
314
|
+
amplitude *= noiseFalloff;
|
|
315
|
+
frequency *= 2;
|
|
316
|
+
}
|
|
317
|
+
return total / maxValue;
|
|
318
|
+
},
|
|
319
|
+
noiseSeed: (seed) => {
|
|
320
|
+
noiseFunc = createSeededNoise(seed);
|
|
321
|
+
},
|
|
322
|
+
noiseDetail: (lod, falloff) => {
|
|
323
|
+
noiseOctaves = Math.max(1, Math.min(8, lod));
|
|
324
|
+
if (falloff !== undefined) {
|
|
325
|
+
noiseFalloff = Math.max(0, Math.min(1, falloff));
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
map: (value, start1, stop1, start2, stop2) => {
|
|
329
|
+
return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
|
|
330
|
+
},
|
|
331
|
+
constrain: (n, low, high) => {
|
|
332
|
+
return Math.max(low, Math.min(high, n));
|
|
333
|
+
},
|
|
334
|
+
lerp: (start, stop, amt) => {
|
|
335
|
+
return start + (stop - start) * amt;
|
|
336
|
+
},
|
|
337
|
+
dist: (x1, y1, x2, y2) => {
|
|
338
|
+
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
|
|
339
|
+
},
|
|
340
|
+
mag: (x, y) => {
|
|
341
|
+
return Math.sqrt(x * x + y * y);
|
|
342
|
+
},
|
|
343
|
+
norm: (value, start, stop) => {
|
|
344
|
+
return (value - start) / (stop - start);
|
|
345
|
+
},
|
|
346
|
+
sin: Math.sin,
|
|
347
|
+
cos: Math.cos,
|
|
348
|
+
tan: Math.tan,
|
|
349
|
+
asin: Math.asin,
|
|
350
|
+
acos: Math.acos,
|
|
351
|
+
atan: Math.atan,
|
|
352
|
+
atan2: Math.atan2,
|
|
353
|
+
radians: (degrees) => degrees * (Math.PI / 180),
|
|
354
|
+
degrees: (radians) => radians * (180 / Math.PI),
|
|
355
|
+
abs: Math.abs,
|
|
356
|
+
ceil: Math.ceil,
|
|
357
|
+
floor: Math.floor,
|
|
358
|
+
round: Math.round,
|
|
359
|
+
sqrt: Math.sqrt,
|
|
360
|
+
pow: Math.pow,
|
|
361
|
+
exp: Math.exp,
|
|
362
|
+
log: Math.log,
|
|
363
|
+
min: Math.min,
|
|
364
|
+
max: Math.max,
|
|
365
|
+
noLoop: () => { },
|
|
366
|
+
loop: () => { },
|
|
367
|
+
redraw: () => { },
|
|
368
|
+
frameRate: (fps) => { },
|
|
369
|
+
};
|
|
370
|
+
return p;
|
|
371
|
+
}
|
|
372
|
+
export function createSketchRenderer(element, ctx, width, height, seed) {
|
|
373
|
+
const p5 = createP5Runtime(ctx, width, height, seed);
|
|
374
|
+
let setupFn = null;
|
|
375
|
+
let drawFn = null;
|
|
376
|
+
let setupExecuted = false;
|
|
377
|
+
const runtimeKeys = Object.keys(p5);
|
|
378
|
+
const destructure = runtimeKeys.map(key => `var ${key} = p5.${key};`).join('\n');
|
|
379
|
+
try {
|
|
380
|
+
const wrappedCode = `
|
|
381
|
+
${destructure}
|
|
382
|
+
${element.code}
|
|
383
|
+
return { setup: typeof setup === 'function' ? setup : null, draw: typeof draw === 'function' ? draw : null };
|
|
384
|
+
`;
|
|
385
|
+
const factory = new Function('p5', wrappedCode);
|
|
386
|
+
const result = factory(p5);
|
|
387
|
+
setupFn = result.setup;
|
|
388
|
+
drawFn = result.draw;
|
|
389
|
+
}
|
|
390
|
+
catch (e) {
|
|
391
|
+
console.error('[NexArt SDK] Sketch compilation error:', e);
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
render: (frameCount) => {
|
|
395
|
+
p5.frameCount = frameCount;
|
|
396
|
+
if (!setupExecuted && setupFn) {
|
|
397
|
+
setupFn();
|
|
398
|
+
setupExecuted = true;
|
|
399
|
+
}
|
|
400
|
+
if (drawFn) {
|
|
401
|
+
drawFn();
|
|
402
|
+
}
|
|
403
|
+
},
|
|
404
|
+
hasSetup: setupFn !== null,
|
|
405
|
+
hasDraw: drawFn !== null,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/preview/renderer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/preview/renderer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAoC,cAAc,EAAE,MAAM,UAAU,CAAC;AAyC/F,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,WAAW,EAAE,KAAK,CAAC;IACnB,UAAU,EAAE,KAAK,CAAC;CACnB;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,iBAAiB,EACzB,OAAO,GAAE,cAAmB,GAC3B,eAAe,CAmKjB"}
|
package/dist/preview/renderer.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @nexart/ui-renderer v0.
|
|
2
|
+
* @nexart/ui-renderer v0.4.0 - Preview Renderer
|
|
3
3
|
*
|
|
4
4
|
* Renders visual approximations of NexArt systems.
|
|
5
5
|
* This is NOT canonical output - for preview/exploration only.
|
|
6
6
|
*/
|
|
7
|
+
import { isCodeModeSystem, isUnifiedModeSystem } from '../system';
|
|
8
|
+
import { renderCodeModeSystem } from './code-renderer';
|
|
9
|
+
import { renderUnifiedSystem } from './unified-renderer';
|
|
7
10
|
import { renderDots } from './primitives/dots';
|
|
8
11
|
import { renderLines } from './primitives/lines';
|
|
9
12
|
import { renderWaves } from './primitives/waves';
|
|
@@ -39,6 +42,13 @@ function parseColor(color) {
|
|
|
39
42
|
return colorMap[color.toLowerCase()] || color;
|
|
40
43
|
}
|
|
41
44
|
export function previewSystem(system, canvas, options = {}) {
|
|
45
|
+
if (isCodeModeSystem(system)) {
|
|
46
|
+
return renderCodeModeSystem(system, canvas, options);
|
|
47
|
+
}
|
|
48
|
+
if (isUnifiedModeSystem(system)) {
|
|
49
|
+
return renderUnifiedSystem(system, canvas, options);
|
|
50
|
+
}
|
|
51
|
+
const declarativeSystem = system;
|
|
42
52
|
const { mode = 'static', showBadge = true } = options;
|
|
43
53
|
const width = canvas.width || 800;
|
|
44
54
|
const height = canvas.height || 800;
|
|
@@ -47,11 +57,11 @@ export function previewSystem(system, canvas, options = {}) {
|
|
|
47
57
|
const ctx = canvas.getContext('2d');
|
|
48
58
|
let animationId = null;
|
|
49
59
|
const renderFrame = (t = 0) => {
|
|
50
|
-
const random = createPRNG(
|
|
51
|
-
ctx.fillStyle = parseColor(
|
|
60
|
+
const random = createPRNG(declarativeSystem.seed);
|
|
61
|
+
ctx.fillStyle = parseColor(declarativeSystem.background.color);
|
|
52
62
|
ctx.fillRect(0, 0, width, height);
|
|
53
|
-
if (
|
|
54
|
-
const g =
|
|
63
|
+
if (declarativeSystem.background.gradient) {
|
|
64
|
+
const g = declarativeSystem.background.gradient;
|
|
55
65
|
let gradient;
|
|
56
66
|
if (g.type === 'radial') {
|
|
57
67
|
gradient = ctx.createRadialGradient(width / 2, height / 2, 0, width / 2, height / 2, Math.max(width, height) / 2);
|
|
@@ -68,10 +78,10 @@ export function previewSystem(system, canvas, options = {}) {
|
|
|
68
78
|
ctx.fillStyle = gradient;
|
|
69
79
|
ctx.fillRect(0, 0, width, height);
|
|
70
80
|
}
|
|
71
|
-
if (
|
|
81
|
+
if (declarativeSystem.background.texture === 'noise' || declarativeSystem.background.texture === 'grain') {
|
|
72
82
|
const imageData = ctx.getImageData(0, 0, width, height);
|
|
73
83
|
const data = imageData.data;
|
|
74
|
-
const intensity =
|
|
84
|
+
const intensity = declarativeSystem.background.texture === 'noise' ? 30 : 15;
|
|
75
85
|
for (let i = 0; i < data.length; i += 4) {
|
|
76
86
|
const noise = (random() - 0.5) * intensity;
|
|
77
87
|
data[i] += noise;
|
|
@@ -80,8 +90,8 @@ export function previewSystem(system, canvas, options = {}) {
|
|
|
80
90
|
}
|
|
81
91
|
ctx.putImageData(imageData, 0, 0);
|
|
82
92
|
}
|
|
83
|
-
for (const el of
|
|
84
|
-
const elRandom = createPRNG(
|
|
93
|
+
for (const el of declarativeSystem.elements) {
|
|
94
|
+
const elRandom = createPRNG(declarativeSystem.seed + declarativeSystem.elements.indexOf(el) * 1000);
|
|
85
95
|
switch (el.type) {
|
|
86
96
|
case 'dots':
|
|
87
97
|
renderDots(ctx, el, width, height, elRandom, t);
|
|
@@ -96,7 +106,7 @@ export function previewSystem(system, canvas, options = {}) {
|
|
|
96
106
|
renderGrid(ctx, el, width, height, elRandom, t);
|
|
97
107
|
break;
|
|
98
108
|
case 'flowField':
|
|
99
|
-
renderFlowField(ctx, el, width, height, elRandom,
|
|
109
|
+
renderFlowField(ctx, el, width, height, elRandom, declarativeSystem.seed, t);
|
|
100
110
|
break;
|
|
101
111
|
case 'orbits':
|
|
102
112
|
renderOrbits(ctx, el, width, height, elRandom, t);
|
|
@@ -132,14 +142,14 @@ export function previewSystem(system, canvas, options = {}) {
|
|
|
132
142
|
const start = () => {
|
|
133
143
|
stop();
|
|
134
144
|
const startTime = performance.now();
|
|
135
|
-
const speed =
|
|
145
|
+
const speed = declarativeSystem.motion?.speed ?? 1;
|
|
136
146
|
const loop = () => {
|
|
137
147
|
const elapsed = (performance.now() - startTime) / 1000;
|
|
138
|
-
const t =
|
|
148
|
+
const t = declarativeSystem.motion?.source === 'time' ? elapsed * speed : 0;
|
|
139
149
|
renderFrame(t);
|
|
140
150
|
animationId = requestAnimationFrame(loop);
|
|
141
151
|
};
|
|
142
|
-
if (mode === 'loop' &&
|
|
152
|
+
if (mode === 'loop' && declarativeSystem.motion?.source !== 'none') {
|
|
143
153
|
animationId = requestAnimationFrame(loop);
|
|
144
154
|
}
|
|
145
155
|
else {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Renderer - Handles background, primitive, and sketch elements
|
|
3
|
+
* Dispatches rendering per element type in order: background → primitive → sketch
|
|
4
|
+
* All elements render to the same canvas/context with shared timing
|
|
5
|
+
*/
|
|
6
|
+
import type { UnifiedSystem, PreviewOptions } from '../types';
|
|
7
|
+
export interface UnifiedRenderer {
|
|
8
|
+
render: () => void;
|
|
9
|
+
start: () => void;
|
|
10
|
+
stop: () => void;
|
|
11
|
+
destroy: () => void;
|
|
12
|
+
isCanonical: false;
|
|
13
|
+
isArchival: false;
|
|
14
|
+
}
|
|
15
|
+
export declare function renderUnifiedSystem(system: UnifiedSystem, canvas: HTMLCanvasElement, options?: PreviewOptions): UnifiedRenderer;
|
|
16
|
+
//# sourceMappingURL=unified-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unified-renderer.d.ts","sourceRoot":"","sources":["../../src/preview/unified-renderer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAkB,cAAc,EAAoE,MAAM,UAAU,CAAC;AAgBhJ,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,WAAW,EAAE,KAAK,CAAC;IACnB,UAAU,EAAE,KAAK,CAAC;CACnB;AA6ED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,iBAAiB,EACzB,OAAO,GAAE,cAAmB,GAC3B,eAAe,CAiOjB"}
|