@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.
Files changed (38) hide show
  1. package/README.md +78 -4
  2. package/dist/compiler.d.ts +18 -2
  3. package/dist/compiler.d.ts.map +1 -1
  4. package/dist/compiler.js +25 -11
  5. package/dist/index.d.ts +19 -8
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +18 -7
  8. package/dist/presets/backgrounds.d.ts +14 -0
  9. package/dist/presets/backgrounds.d.ts.map +1 -0
  10. package/dist/presets/backgrounds.js +222 -0
  11. package/dist/presets/index.d.ts +7 -0
  12. package/dist/presets/index.d.ts.map +1 -0
  13. package/dist/presets/index.js +6 -0
  14. package/dist/presets/primitives.d.ts +16 -0
  15. package/dist/presets/primitives.d.ts.map +1 -0
  16. package/dist/presets/primitives.js +282 -0
  17. package/dist/presets/sketch-wrapper.d.ts +14 -0
  18. package/dist/presets/sketch-wrapper.d.ts.map +1 -0
  19. package/dist/presets/sketch-wrapper.js +70 -0
  20. package/dist/preview/code-renderer.d.ts +25 -0
  21. package/dist/preview/code-renderer.d.ts.map +1 -0
  22. package/dist/preview/code-renderer.js +651 -0
  23. package/dist/preview/primitives/sketch.d.ts +14 -0
  24. package/dist/preview/primitives/sketch.d.ts.map +1 -0
  25. package/dist/preview/primitives/sketch.js +407 -0
  26. package/dist/preview/renderer.d.ts +1 -1
  27. package/dist/preview/renderer.d.ts.map +1 -1
  28. package/dist/preview/renderer.js +23 -13
  29. package/dist/preview/unified-renderer.d.ts +16 -0
  30. package/dist/preview/unified-renderer.d.ts.map +1 -0
  31. package/dist/preview/unified-renderer.js +270 -0
  32. package/dist/system.d.ts +7 -3
  33. package/dist/system.d.ts.map +1 -1
  34. package/dist/system.js +187 -11
  35. package/dist/types.d.ts +125 -5
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/types.js +12 -3
  38. 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,5 +1,5 @@
1
1
  /**
2
- * @nexart/ui-renderer v0.2.0 - Preview Renderer
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.
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/preview/renderer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAsC7D,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,CA0JjB"}
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"}
@@ -1,9 +1,12 @@
1
1
  /**
2
- * @nexart/ui-renderer v0.2.0 - Preview Renderer
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(system.seed);
51
- ctx.fillStyle = parseColor(system.background.color);
60
+ const random = createPRNG(declarativeSystem.seed);
61
+ ctx.fillStyle = parseColor(declarativeSystem.background.color);
52
62
  ctx.fillRect(0, 0, width, height);
53
- if (system.background.gradient) {
54
- const g = system.background.gradient;
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 (system.background.texture === 'noise' || system.background.texture === 'grain') {
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 = system.background.texture === 'noise' ? 30 : 15;
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 system.elements) {
84
- const elRandom = createPRNG(system.seed + system.elements.indexOf(el) * 1000);
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, system.seed, t);
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 = system.motion?.speed ?? 1;
145
+ const speed = declarativeSystem.motion?.speed ?? 1;
136
146
  const loop = () => {
137
147
  const elapsed = (performance.now() - startTime) / 1000;
138
- const t = system.motion?.source === 'time' ? elapsed * speed : 0;
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' && system.motion?.source !== 'none') {
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"}