@nexart/ui-renderer 0.1.0 → 0.2.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.
Files changed (41) hide show
  1. package/README.md +204 -95
  2. package/dist/capabilities.d.ts +54 -0
  3. package/dist/capabilities.d.ts.map +1 -0
  4. package/dist/capabilities.js +338 -0
  5. package/dist/compiler.d.ts +34 -0
  6. package/dist/compiler.d.ts.map +1 -0
  7. package/dist/compiler.js +80 -0
  8. package/dist/index.d.ts +21 -6
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +19 -5
  11. package/dist/preview/primitives/dots.d.ts +6 -0
  12. package/dist/preview/primitives/dots.d.ts.map +1 -0
  13. package/dist/preview/primitives/dots.js +53 -0
  14. package/dist/preview/primitives/flow.d.ts +6 -0
  15. package/dist/preview/primitives/flow.d.ts.map +1 -0
  16. package/dist/preview/primitives/flow.js +32 -0
  17. package/dist/preview/primitives/grid.d.ts +6 -0
  18. package/dist/preview/primitives/grid.d.ts.map +1 -0
  19. package/dist/preview/primitives/grid.js +38 -0
  20. package/dist/preview/primitives/lines.d.ts +6 -0
  21. package/dist/preview/primitives/lines.d.ts.map +1 -0
  22. package/dist/preview/primitives/lines.js +47 -0
  23. package/dist/preview/primitives/orbits.d.ts +6 -0
  24. package/dist/preview/primitives/orbits.d.ts.map +1 -0
  25. package/dist/preview/primitives/orbits.js +27 -0
  26. package/dist/preview/primitives/waves.d.ts +6 -0
  27. package/dist/preview/primitives/waves.d.ts.map +1 -0
  28. package/dist/preview/primitives/waves.js +44 -0
  29. package/dist/preview/renderer.d.ts +17 -0
  30. package/dist/preview/renderer.d.ts.map +1 -0
  31. package/dist/preview/renderer.js +167 -0
  32. package/dist/system.d.ts +9 -0
  33. package/dist/system.d.ts.map +1 -0
  34. package/dist/system.js +165 -0
  35. package/dist/types.d.ts +99 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +7 -0
  38. package/package.json +7 -5
  39. package/dist/renderer.d.ts +0 -31
  40. package/dist/renderer.d.ts.map +0 -1
  41. package/dist/renderer.js +0 -210
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Grid Primitive Renderer
3
+ */
4
+ export function renderGrid(ctx, el, width, height, random, t) {
5
+ const color = el.color || 'white';
6
+ const opacity = el.opacity ?? 1;
7
+ ctx.fillStyle = color;
8
+ ctx.globalAlpha = opacity;
9
+ const cellW = width / el.cols;
10
+ const cellH = height / el.rows;
11
+ const baseSize = el.cellSize || Math.min(cellW, cellH) * 0.4;
12
+ for (let row = 0; row < el.rows; row++) {
13
+ for (let col = 0; col < el.cols; col++) {
14
+ const x = cellW * (col + 0.5);
15
+ const y = cellH * (row + 0.5);
16
+ const pulse = 1 + Math.sin((row + col) * 0.5 + t * 3) * 0.2;
17
+ const size = baseSize * pulse;
18
+ ctx.beginPath();
19
+ switch (el.shape) {
20
+ case 'circle':
21
+ ctx.arc(x, y, size / 2, 0, Math.PI * 2);
22
+ break;
23
+ case 'square':
24
+ ctx.rect(x - size / 2, y - size / 2, size, size);
25
+ break;
26
+ case 'diamond':
27
+ ctx.moveTo(x, y - size / 2);
28
+ ctx.lineTo(x + size / 2, y);
29
+ ctx.lineTo(x, y + size / 2);
30
+ ctx.lineTo(x - size / 2, y);
31
+ ctx.closePath();
32
+ break;
33
+ }
34
+ ctx.fill();
35
+ }
36
+ }
37
+ ctx.globalAlpha = 1;
38
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Lines Primitive Renderer
3
+ */
4
+ import type { LinesElement } from '../../types';
5
+ export declare function renderLines(ctx: CanvasRenderingContext2D, el: LinesElement, width: number, height: number, random: () => number, t: number): void;
6
+ //# sourceMappingURL=lines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../../src/preview/primitives/lines.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,wBAAgB,WAAW,CACzB,GAAG,EAAE,wBAAwB,EAC7B,EAAE,EAAE,YAAY,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,MAAM,EACpB,CAAC,EAAE,MAAM,GACR,IAAI,CAqDN"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Lines Primitive Renderer
3
+ */
4
+ export function renderLines(ctx, el, width, height, random, t) {
5
+ const color = el.color || 'white';
6
+ const opacity = el.opacity ?? 1;
7
+ ctx.strokeStyle = color;
8
+ ctx.globalAlpha = opacity;
9
+ const cx = width / 2;
10
+ const cy = height / 2;
11
+ for (let i = 0; i < el.count; i++) {
12
+ const thickness = el.thickness[0] + random() * (el.thickness[1] - el.thickness[0]);
13
+ ctx.lineWidth = thickness;
14
+ ctx.beginPath();
15
+ switch (el.direction) {
16
+ case 'horizontal': {
17
+ const y = (i / el.count) * height;
18
+ const wobble = Math.sin(i * 0.5 + t * 2) * 10;
19
+ ctx.moveTo(0, y + wobble);
20
+ ctx.lineTo(width, y + wobble);
21
+ break;
22
+ }
23
+ case 'vertical': {
24
+ const x = (i / el.count) * width;
25
+ const wobble = Math.sin(i * 0.5 + t * 2) * 10;
26
+ ctx.moveTo(x + wobble, 0);
27
+ ctx.lineTo(x + wobble, height);
28
+ break;
29
+ }
30
+ case 'diagonal': {
31
+ const offset = (i / el.count) * (width + height) - height;
32
+ ctx.moveTo(offset, 0);
33
+ ctx.lineTo(offset + height, height);
34
+ break;
35
+ }
36
+ case 'radial': {
37
+ const angle = (i / el.count) * Math.PI * 2 + t * 0.2;
38
+ const len = Math.min(width, height) * 0.4;
39
+ ctx.moveTo(cx, cy);
40
+ ctx.lineTo(cx + Math.cos(angle) * len, cy + Math.sin(angle) * len);
41
+ break;
42
+ }
43
+ }
44
+ ctx.stroke();
45
+ }
46
+ ctx.globalAlpha = 1;
47
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Orbits Primitive Renderer
3
+ */
4
+ import type { OrbitsElement } from '../../types';
5
+ export declare function renderOrbits(ctx: CanvasRenderingContext2D, el: OrbitsElement, width: number, height: number, random: () => number, t: number): void;
6
+ //# sourceMappingURL=orbits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orbits.d.ts","sourceRoot":"","sources":["../../../src/preview/primitives/orbits.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,wBAAgB,YAAY,CAC1B,GAAG,EAAE,wBAAwB,EAC7B,EAAE,EAAE,aAAa,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,MAAM,EACpB,CAAC,EAAE,MAAM,GACR,IAAI,CAgCN"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Orbits Primitive Renderer
3
+ */
4
+ export function renderOrbits(ctx, el, width, height, random, t) {
5
+ const color = el.color || 'white';
6
+ const opacity = el.opacity ?? 1;
7
+ const speed = el.speed ?? 1;
8
+ ctx.fillStyle = color;
9
+ ctx.globalAlpha = opacity;
10
+ const cx = width / 2;
11
+ const cy = height / 2;
12
+ for (let o = 0; o < el.count; o++) {
13
+ const orbitRadius = el.radius[0] + (random() * (el.radius[1] - el.radius[0]));
14
+ const orbitPhase = random() * Math.PI * 2;
15
+ for (let d = 0; d < el.dotCount; d++) {
16
+ const angle = (d / el.dotCount) * Math.PI * 2 + t * speed + orbitPhase;
17
+ const wobble = Math.sin(angle * 3 + t * 2) * 10;
18
+ const x = cx + Math.cos(angle) * (orbitRadius + wobble);
19
+ const y = cy + Math.sin(angle) * (orbitRadius + wobble);
20
+ const size = 2 + random() * 3;
21
+ ctx.beginPath();
22
+ ctx.arc(x, y, size, 0, Math.PI * 2);
23
+ ctx.fill();
24
+ }
25
+ }
26
+ ctx.globalAlpha = 1;
27
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Waves Primitive Renderer
3
+ */
4
+ import type { WavesElement } from '../../types';
5
+ export declare function renderWaves(ctx: CanvasRenderingContext2D, el: WavesElement, width: number, height: number, random: () => number, t: number): void;
6
+ //# sourceMappingURL=waves.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waves.d.ts","sourceRoot":"","sources":["../../../src/preview/primitives/waves.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,wBAAgB,WAAW,CACzB,GAAG,EAAE,wBAAwB,EAC7B,EAAE,EAAE,YAAY,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,MAAM,EACpB,CAAC,EAAE,MAAM,GACR,IAAI,CA2CN"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Waves Primitive Renderer
3
+ */
4
+ export function renderWaves(ctx, el, width, height, random, t) {
5
+ const color = el.color || 'white';
6
+ const opacity = el.opacity ?? 1;
7
+ const count = el.count || 8;
8
+ ctx.strokeStyle = color;
9
+ ctx.globalAlpha = opacity;
10
+ ctx.lineWidth = 2;
11
+ const maxAmp = Math.min(width, height) * 0.3 * el.amplitude;
12
+ for (let w = 0; w < count; w++) {
13
+ const waveOffset = w / count;
14
+ ctx.beginPath();
15
+ if (el.axis === 'x') {
16
+ const baseY = height * (0.2 + waveOffset * 0.6);
17
+ for (let x = 0; x <= width; x += 5) {
18
+ const phase = (x / width) * Math.PI * 2 * el.frequency + t * 2 + w;
19
+ const y = baseY + Math.sin(phase) * maxAmp;
20
+ if (x === 0) {
21
+ ctx.moveTo(x, y);
22
+ }
23
+ else {
24
+ ctx.lineTo(x, y);
25
+ }
26
+ }
27
+ }
28
+ else {
29
+ const baseX = width * (0.2 + waveOffset * 0.6);
30
+ for (let y = 0; y <= height; y += 5) {
31
+ const phase = (y / height) * Math.PI * 2 * el.frequency + t * 2 + w;
32
+ const x = baseX + Math.sin(phase) * maxAmp;
33
+ if (y === 0) {
34
+ ctx.moveTo(x, y);
35
+ }
36
+ else {
37
+ ctx.lineTo(x, y);
38
+ }
39
+ }
40
+ }
41
+ ctx.stroke();
42
+ }
43
+ ctx.globalAlpha = 1;
44
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @nexart/ui-renderer v0.2.0 - Preview Renderer
3
+ *
4
+ * Renders visual approximations of NexArt systems.
5
+ * This is NOT canonical output - for preview/exploration only.
6
+ */
7
+ import type { NexArtSystem, PreviewOptions } from '../types';
8
+ export interface PreviewRenderer {
9
+ render: () => void;
10
+ start: () => void;
11
+ stop: () => void;
12
+ destroy: () => void;
13
+ isCanonical: false;
14
+ isArchival: false;
15
+ }
16
+ export declare function previewSystem(system: NexArtSystem, canvas: HTMLCanvasElement, options?: PreviewOptions): PreviewRenderer;
17
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * @nexart/ui-renderer v0.2.0 - Preview Renderer
3
+ *
4
+ * Renders visual approximations of NexArt systems.
5
+ * This is NOT canonical output - for preview/exploration only.
6
+ */
7
+ import { renderDots } from './primitives/dots';
8
+ import { renderLines } from './primitives/lines';
9
+ import { renderWaves } from './primitives/waves';
10
+ import { renderGrid } from './primitives/grid';
11
+ import { renderFlowField } from './primitives/flow';
12
+ import { renderOrbits } from './primitives/orbits';
13
+ function createPRNG(seed) {
14
+ let state = seed;
15
+ return () => {
16
+ state |= 0;
17
+ state = (state + 0x6d2b79f5) | 0;
18
+ let t = Math.imul(state ^ (state >>> 15), 1 | state);
19
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
20
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
21
+ };
22
+ }
23
+ function parseColor(color) {
24
+ const colorMap = {
25
+ red: '#ff0000',
26
+ green: '#00ff00',
27
+ blue: '#0000ff',
28
+ black: '#000000',
29
+ white: '#ffffff',
30
+ yellow: '#ffff00',
31
+ cyan: '#00ffff',
32
+ magenta: '#ff00ff',
33
+ orange: '#ff8000',
34
+ purple: '#8000ff',
35
+ pink: '#ff0080',
36
+ gray: '#808080',
37
+ grey: '#808080',
38
+ };
39
+ return colorMap[color.toLowerCase()] || color;
40
+ }
41
+ export function previewSystem(system, canvas, options = {}) {
42
+ const { mode = 'static', showBadge = true } = options;
43
+ const width = canvas.width || 800;
44
+ const height = canvas.height || 800;
45
+ canvas.width = width;
46
+ canvas.height = height;
47
+ const ctx = canvas.getContext('2d');
48
+ let animationId = null;
49
+ const renderFrame = (t = 0) => {
50
+ const random = createPRNG(system.seed);
51
+ ctx.fillStyle = parseColor(system.background.color);
52
+ ctx.fillRect(0, 0, width, height);
53
+ if (system.background.gradient) {
54
+ const g = system.background.gradient;
55
+ let gradient;
56
+ if (g.type === 'radial') {
57
+ gradient = ctx.createRadialGradient(width / 2, height / 2, 0, width / 2, height / 2, Math.max(width, height) / 2);
58
+ }
59
+ else {
60
+ const angle = (g.angle || 0) * (Math.PI / 180);
61
+ const dx = Math.cos(angle) * width;
62
+ const dy = Math.sin(angle) * height;
63
+ gradient = ctx.createLinearGradient(width / 2 - dx / 2, height / 2 - dy / 2, width / 2 + dx / 2, height / 2 + dy / 2);
64
+ }
65
+ g.colors.forEach((c, i) => {
66
+ gradient.addColorStop(i / (g.colors.length - 1), parseColor(c));
67
+ });
68
+ ctx.fillStyle = gradient;
69
+ ctx.fillRect(0, 0, width, height);
70
+ }
71
+ if (system.background.texture === 'noise' || system.background.texture === 'grain') {
72
+ const imageData = ctx.getImageData(0, 0, width, height);
73
+ const data = imageData.data;
74
+ const intensity = system.background.texture === 'noise' ? 30 : 15;
75
+ for (let i = 0; i < data.length; i += 4) {
76
+ const noise = (random() - 0.5) * intensity;
77
+ data[i] += noise;
78
+ data[i + 1] += noise;
79
+ data[i + 2] += noise;
80
+ }
81
+ ctx.putImageData(imageData, 0, 0);
82
+ }
83
+ for (const el of system.elements) {
84
+ const elRandom = createPRNG(system.seed + system.elements.indexOf(el) * 1000);
85
+ switch (el.type) {
86
+ case 'dots':
87
+ renderDots(ctx, el, width, height, elRandom, t);
88
+ break;
89
+ case 'lines':
90
+ renderLines(ctx, el, width, height, elRandom, t);
91
+ break;
92
+ case 'waves':
93
+ renderWaves(ctx, el, width, height, elRandom, t);
94
+ break;
95
+ case 'grid':
96
+ renderGrid(ctx, el, width, height, elRandom, t);
97
+ break;
98
+ case 'flowField':
99
+ renderFlowField(ctx, el, width, height, elRandom, system.seed, t);
100
+ break;
101
+ case 'orbits':
102
+ renderOrbits(ctx, el, width, height, elRandom, t);
103
+ break;
104
+ }
105
+ }
106
+ if (showBadge) {
107
+ drawBadge(ctx, width);
108
+ }
109
+ };
110
+ const drawBadge = (ctx, width) => {
111
+ const text = '⚠️ Preview Renderer (Non-Canonical)';
112
+ ctx.font = '12px -apple-system, sans-serif';
113
+ const metrics = ctx.measureText(text);
114
+ const padding = 8;
115
+ const badgeWidth = metrics.width + padding * 2;
116
+ const badgeHeight = 24;
117
+ const x = width - badgeWidth - 10;
118
+ const y = 10;
119
+ ctx.fillStyle = 'rgba(255, 100, 100, 0.15)';
120
+ ctx.strokeStyle = 'rgba(255, 100, 100, 0.4)';
121
+ ctx.lineWidth = 1;
122
+ ctx.beginPath();
123
+ ctx.roundRect(x, y, badgeWidth, badgeHeight, 4);
124
+ ctx.fill();
125
+ ctx.stroke();
126
+ ctx.fillStyle = '#ff9999';
127
+ ctx.fillText(text, x + padding, y + 16);
128
+ };
129
+ const render = () => {
130
+ renderFrame(0);
131
+ };
132
+ const start = () => {
133
+ stop();
134
+ const startTime = performance.now();
135
+ const speed = system.motion?.speed ?? 1;
136
+ const loop = () => {
137
+ const elapsed = (performance.now() - startTime) / 1000;
138
+ const t = system.motion?.source === 'time' ? elapsed * speed : 0;
139
+ renderFrame(t);
140
+ animationId = requestAnimationFrame(loop);
141
+ };
142
+ if (mode === 'loop' && system.motion?.source !== 'none') {
143
+ animationId = requestAnimationFrame(loop);
144
+ }
145
+ else {
146
+ render();
147
+ }
148
+ };
149
+ const stop = () => {
150
+ if (animationId !== null) {
151
+ cancelAnimationFrame(animationId);
152
+ animationId = null;
153
+ }
154
+ };
155
+ const destroy = () => {
156
+ stop();
157
+ ctx.clearRect(0, 0, width, height);
158
+ };
159
+ return {
160
+ render,
161
+ start,
162
+ stop,
163
+ destroy,
164
+ isCanonical: false,
165
+ isArchival: false,
166
+ };
167
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @nexart/ui-renderer v0.2.0 - System Creation & Validation
3
+ *
4
+ * Declarative system authoring for NexArt Protocol.
5
+ */
6
+ import type { NexArtSystemInput, NexArtSystem, ValidationResult } from './types';
7
+ export declare function validateSystem(input: NexArtSystemInput): ValidationResult;
8
+ export declare function createSystem(input: NexArtSystemInput): NexArtSystem;
9
+ //# sourceMappingURL=system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../src/system.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EAEZ,gBAAgB,EAGjB,MAAM,SAAS,CAAC;AAoIjB,wBAAgB,cAAc,CAAC,KAAK,EAAE,iBAAiB,GAAG,gBAAgB,CA6BzE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CA0BnE"}
package/dist/system.js ADDED
@@ -0,0 +1,165 @@
1
+ /**
2
+ * @nexart/ui-renderer v0.2.0 - System Creation & Validation
3
+ *
4
+ * Declarative system authoring for NexArt Protocol.
5
+ */
6
+ const CURRENT_VERSION = '0.2';
7
+ const VALID_ELEMENT_TYPES = ['dots', 'lines', 'waves', 'grid', 'flowField', 'orbits'];
8
+ const VALID_MOTION_SOURCES = ['none', 'time', 'seed'];
9
+ const VALID_TEXTURES = ['none', 'noise', 'grain'];
10
+ function validateBackground(bg) {
11
+ const errors = [];
12
+ if (!bg.color || typeof bg.color !== 'string') {
13
+ errors.push('Background color is required and must be a string');
14
+ }
15
+ if (bg.texture && !VALID_TEXTURES.includes(bg.texture)) {
16
+ errors.push(`Invalid texture: ${bg.texture}. Must be one of: ${VALID_TEXTURES.join(', ')}`);
17
+ }
18
+ if (bg.gradient) {
19
+ if (!['linear', 'radial'].includes(bg.gradient.type)) {
20
+ errors.push('Gradient type must be "linear" or "radial"');
21
+ }
22
+ if (!Array.isArray(bg.gradient.colors) || bg.gradient.colors.length < 2) {
23
+ errors.push('Gradient requires at least 2 colors');
24
+ }
25
+ }
26
+ return errors;
27
+ }
28
+ function validateElement(el, index) {
29
+ const errors = [];
30
+ const prefix = `Element[${index}]`;
31
+ if (!el.type || !VALID_ELEMENT_TYPES.includes(el.type)) {
32
+ errors.push(`${prefix}: Invalid type. Must be one of: ${VALID_ELEMENT_TYPES.join(', ')}`);
33
+ return errors;
34
+ }
35
+ switch (el.type) {
36
+ case 'dots':
37
+ if (!['random', 'radial', 'grid', 'spiral'].includes(el.distribution)) {
38
+ errors.push(`${prefix}: Invalid distribution for dots`);
39
+ }
40
+ if (typeof el.count !== 'number' || el.count < 1 || el.count > 10000) {
41
+ errors.push(`${prefix}: count must be between 1 and 10000`);
42
+ }
43
+ if (!Array.isArray(el.size) || el.size.length !== 2) {
44
+ errors.push(`${prefix}: size must be [min, max] array`);
45
+ }
46
+ break;
47
+ case 'lines':
48
+ if (!['horizontal', 'vertical', 'diagonal', 'radial'].includes(el.direction)) {
49
+ errors.push(`${prefix}: Invalid direction for lines`);
50
+ }
51
+ if (typeof el.count !== 'number' || el.count < 1 || el.count > 500) {
52
+ errors.push(`${prefix}: count must be between 1 and 500`);
53
+ }
54
+ break;
55
+ case 'waves':
56
+ if (!['x', 'y'].includes(el.axis)) {
57
+ errors.push(`${prefix}: axis must be "x" or "y"`);
58
+ }
59
+ if (typeof el.amplitude !== 'number' || el.amplitude < 0 || el.amplitude > 1) {
60
+ errors.push(`${prefix}: amplitude must be between 0 and 1`);
61
+ }
62
+ if (typeof el.frequency !== 'number' || el.frequency < 0.1 || el.frequency > 10) {
63
+ errors.push(`${prefix}: frequency must be between 0.1 and 10`);
64
+ }
65
+ break;
66
+ case 'grid':
67
+ if (typeof el.rows !== 'number' || el.rows < 1 || el.rows > 100) {
68
+ errors.push(`${prefix}: rows must be between 1 and 100`);
69
+ }
70
+ if (typeof el.cols !== 'number' || el.cols < 1 || el.cols > 100) {
71
+ errors.push(`${prefix}: cols must be between 1 and 100`);
72
+ }
73
+ if (!['square', 'circle', 'diamond'].includes(el.shape)) {
74
+ errors.push(`${prefix}: shape must be "square", "circle", or "diamond"`);
75
+ }
76
+ break;
77
+ case 'flowField':
78
+ if (typeof el.resolution !== 'number' || el.resolution < 5 || el.resolution > 100) {
79
+ errors.push(`${prefix}: resolution must be between 5 and 100`);
80
+ }
81
+ if (typeof el.strength !== 'number' || el.strength < 0 || el.strength > 1) {
82
+ errors.push(`${prefix}: strength must be between 0 and 1`);
83
+ }
84
+ if (typeof el.particles !== 'number' || el.particles < 10 || el.particles > 5000) {
85
+ errors.push(`${prefix}: particles must be between 10 and 5000`);
86
+ }
87
+ break;
88
+ case 'orbits':
89
+ if (typeof el.count !== 'number' || el.count < 1 || el.count > 20) {
90
+ errors.push(`${prefix}: count must be between 1 and 20`);
91
+ }
92
+ if (!Array.isArray(el.radius) || el.radius.length !== 2) {
93
+ errors.push(`${prefix}: radius must be [min, max] array`);
94
+ }
95
+ if (typeof el.dotCount !== 'number' || el.dotCount < 1 || el.dotCount > 200) {
96
+ errors.push(`${prefix}: dotCount must be between 1 and 200`);
97
+ }
98
+ break;
99
+ }
100
+ if (el.opacity !== undefined && (el.opacity < 0 || el.opacity > 1)) {
101
+ errors.push(`${prefix}: opacity must be between 0 and 1`);
102
+ }
103
+ return errors;
104
+ }
105
+ function validateMotion(motion) {
106
+ const errors = [];
107
+ if (!VALID_MOTION_SOURCES.includes(motion.source)) {
108
+ errors.push(`Invalid motion source. Must be one of: ${VALID_MOTION_SOURCES.join(', ')}`);
109
+ }
110
+ if (motion.speed !== undefined && (motion.speed < 0 || motion.speed > 5)) {
111
+ errors.push('Motion speed must be between 0 and 5');
112
+ }
113
+ return errors;
114
+ }
115
+ export function validateSystem(input) {
116
+ const errors = [];
117
+ if (typeof input.seed !== 'number') {
118
+ errors.push('seed is required and must be a number');
119
+ }
120
+ if (!input.background) {
121
+ errors.push('background is required');
122
+ }
123
+ else {
124
+ errors.push(...validateBackground(input.background));
125
+ }
126
+ if (!Array.isArray(input.elements) || input.elements.length === 0) {
127
+ errors.push('elements array is required and must not be empty');
128
+ }
129
+ else {
130
+ input.elements.forEach((el, i) => {
131
+ errors.push(...validateElement(el, i));
132
+ });
133
+ }
134
+ if (input.motion) {
135
+ errors.push(...validateMotion(input.motion));
136
+ }
137
+ return {
138
+ valid: errors.length === 0,
139
+ errors,
140
+ };
141
+ }
142
+ export function createSystem(input) {
143
+ const validation = validateSystem(input);
144
+ if (!validation.valid) {
145
+ throw new Error(`Invalid system: ${validation.errors.join('; ')}`);
146
+ }
147
+ const system = {
148
+ protocol: 'nexart',
149
+ systemVersion: input.version || CURRENT_VERSION,
150
+ seed: input.seed,
151
+ background: {
152
+ color: input.background.color,
153
+ texture: input.background.texture || 'none',
154
+ ...(input.background.gradient && { gradient: input.background.gradient }),
155
+ },
156
+ elements: input.elements.map((el) => ({
157
+ ...el,
158
+ opacity: el.opacity ?? 1,
159
+ })),
160
+ motion: input.motion || { source: 'none' },
161
+ deterministic: true,
162
+ createdAt: new Date().toISOString(),
163
+ };
164
+ return system;
165
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @nexart/ui-renderer v0.2.0 - Type Definitions
3
+ *
4
+ * Declarative system authoring types for NexArt Protocol.
5
+ * This SDK is non-canonical and for authoring/preview only.
6
+ */
7
+ export type BackgroundTexture = 'none' | 'noise' | 'grain';
8
+ export interface BackgroundConfig {
9
+ color: string;
10
+ gradient?: {
11
+ type: 'linear' | 'radial';
12
+ colors: string[];
13
+ angle?: number;
14
+ };
15
+ texture?: BackgroundTexture;
16
+ }
17
+ export interface DotsElement {
18
+ type: 'dots';
19
+ distribution: 'random' | 'radial' | 'grid' | 'spiral';
20
+ count: number;
21
+ size: [number, number];
22
+ color?: string;
23
+ opacity?: number;
24
+ }
25
+ export interface LinesElement {
26
+ type: 'lines';
27
+ direction: 'horizontal' | 'vertical' | 'diagonal' | 'radial';
28
+ count: number;
29
+ thickness: [number, number];
30
+ color?: string;
31
+ opacity?: number;
32
+ }
33
+ export interface WavesElement {
34
+ type: 'waves';
35
+ axis: 'x' | 'y';
36
+ amplitude: number;
37
+ frequency: number;
38
+ count?: number;
39
+ color?: string;
40
+ opacity?: number;
41
+ }
42
+ export interface GridElement {
43
+ type: 'grid';
44
+ rows: number;
45
+ cols: number;
46
+ cellSize?: number;
47
+ shape: 'square' | 'circle' | 'diamond';
48
+ color?: string;
49
+ opacity?: number;
50
+ }
51
+ export interface FlowFieldElement {
52
+ type: 'flowField';
53
+ resolution: number;
54
+ strength: number;
55
+ particles: number;
56
+ color?: string;
57
+ opacity?: number;
58
+ }
59
+ export interface OrbitsElement {
60
+ type: 'orbits';
61
+ count: number;
62
+ radius: [number, number];
63
+ dotCount: number;
64
+ speed?: number;
65
+ color?: string;
66
+ opacity?: number;
67
+ }
68
+ export type SystemElement = DotsElement | LinesElement | WavesElement | GridElement | FlowFieldElement | OrbitsElement;
69
+ export type MotionSource = 'none' | 'time' | 'seed';
70
+ export interface MotionConfig {
71
+ source: MotionSource;
72
+ speed?: number;
73
+ }
74
+ export interface NexArtSystemInput {
75
+ version?: string;
76
+ seed: number;
77
+ background: BackgroundConfig;
78
+ elements: SystemElement[];
79
+ motion?: MotionConfig;
80
+ }
81
+ export interface NexArtSystem {
82
+ protocol: 'nexart';
83
+ systemVersion: string;
84
+ seed: number;
85
+ background: BackgroundConfig;
86
+ elements: SystemElement[];
87
+ motion: MotionConfig;
88
+ deterministic: boolean;
89
+ createdAt: string;
90
+ }
91
+ export interface PreviewOptions {
92
+ mode?: 'static' | 'loop';
93
+ showBadge?: boolean;
94
+ }
95
+ export interface ValidationResult {
96
+ valid: boolean;
97
+ errors: string[];
98
+ }
99
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @nexart/ui-renderer v0.2.0 - Type Definitions
3
+ *
4
+ * Declarative system authoring types for NexArt Protocol.
5
+ * This SDK is non-canonical and for authoring/preview only.
6
+ */
7
+ export {};