@nexart/ui-renderer 0.3.1 → 0.6.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.
@@ -1,407 +0,0 @@
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
- }