@nexart/ui-renderer 0.8.7 → 0.9.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.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @nexart/ui-renderer
3
- * Version: 0.8.6
3
+ * Version: 0.9.0
4
4
  *
5
5
  * Lightweight Preview Runtime for NexArt Protocol
6
6
  *
@@ -11,21 +11,15 @@
11
11
  * ║ It does not guarantee determinism or protocol compliance. ║
12
12
  * ║ ║
13
13
  * ║ Performance Limits: ║
14
- * ║ - Max frames: 30
15
- * ║ - Max total time: 500ms ║
14
+ * ║ - FPS: Native RAF (~60 FPS)
16
15
  * ║ - Max canvas dimension: 900px ║
17
- * ║ - Frame stride: render every 3rd frame
16
+ * ║ - Budget: 1800 frames / 5 minutes (configurable)
18
17
  * ║ ║
19
- * ║ Use Cases:
20
- * ║ - Editor live preview
21
- * ║ - Builder dashboards
22
- * ║ - Background generative art
23
- * ║ - Static or loop previews
24
- * ║ ║
25
- * ║ NOT For: ║
26
- * ║ - Minting / export ║
27
- * ║ - ByX ║
28
- * ║ - Protocol validation ║
18
+ * ║ v0.9.0 Features:
19
+ * ║ - Budget exceed callbacks + overlay
20
+ * ║ - getPreviewStats() for observability
21
+ * ║ - createPreviewRuntime() as recommended entrypoint
22
+ * ║ - toCanonicalRequest() for handoff to @nexart/codemode-sdk
29
23
  * ║ ║
30
24
  * ║ For canonical output: use @nexart/codemode-sdk ║
31
25
  * ╚══════════════════════════════════════════════════════════════════════════╝
@@ -39,16 +33,40 @@ export { compileBackgroundPreset, getPaletteColors } from './presets/backgrounds
39
33
  export { compilePrimitive } from './presets/primitives';
40
34
  export { wrapSketch, validateSketchSafety } from './presets/sketch-wrapper';
41
35
  export { getCapabilities, getPrimitiveTypes, getPrimitivesByCategory, getPrimitiveInfo, isPrimitiveValid, getMotionSources, getBackgroundTextures, } from './capabilities';
42
- export { createPreviewEngine, renderStaticPreview, stopActivePreview, } from './preview/preview-engine';
43
- export { PREVIEW_FPS, CANVAS_LIMITS, type RuntimeProfile, type PreviewMode, type PreviewEngineConfig, type PreviewRenderResult, type PreviewRenderer, type FpsThrottleState, } from './preview/preview-types';
36
+ export { createPreviewEngine, renderStaticPreview, stopActivePreview, toCanonicalRequest, } from './preview/preview-engine';
37
+ export { PREVIEW_FPS, PREVIEW_BUDGET, CANVAS_LIMITS, type RuntimeProfile, type PreviewMode, type PreviewEngineConfig, type PreviewRenderResult, type PreviewRenderer, type PreviewStats, type BudgetExceededInfo, type BudgetExceedReason, type BudgetBehavior, type CanonicalRequest, type FpsThrottleState, } from './preview/preview-types';
44
38
  export { type FrameBudgetState } from './preview/frame-budget';
45
39
  export { createFpsThrottle, shouldRenderFrame, recordFrame, resetThrottle, createFrameBudget, canRenderFrame, resetBudget, shouldSkipFrame, getElapsedMs, } from './preview/frame-budget';
46
40
  export { calculateScaledDimensions, applyScaledDimensions, type ScaledDimensions, } from './preview/canvas-scaler';
47
41
  export type { NexArtSystemInput, NexArtSystem, DeclarativeSystemInput, DeclarativeSystem, CodeSystem, NexArtCodeSystem, UnifiedSystemInput, UnifiedSystem, UnifiedElement, BackgroundElement, PrimitiveElement, SketchElement, BackgroundPreset, PrimitiveName, ColorPalette, MotionSpeed, StrokeWeightAuto, LoopConfig, DeclarativeElement, SystemElement, DotsElement, LinesElement, WavesElement, GridElement, FlowFieldElement, OrbitsElement, BackgroundConfig, MotionConfig, PreviewOptions, ValidationResult, } from './types';
48
42
  export { AESTHETIC_DEFAULTS, SDK_VERSION as TYPE_SDK_VERSION } from './types';
49
43
  export type { Capabilities, PrimitiveCapability, ParameterSpec, } from './capabilities';
50
- export declare const SDK_VERSION = "0.8.6";
51
- export declare const PROTOCOL_VERSION = "0.8";
44
+ /**
45
+ * createPreviewRuntime - Recommended entrypoint for AI coding agents.
46
+ *
47
+ * This is an alias for createPreviewEngine with sensible defaults.
48
+ * Use this as the primary way to create previews.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * import { createPreviewRuntime } from '@nexart/ui-renderer';
53
+ *
54
+ * const runtime = createPreviewRuntime({
55
+ * canvas: document.getElementById('canvas'),
56
+ * source: 'function draw() { circle(width/2, height/2, 100); }',
57
+ * mode: 'loop',
58
+ * width: 1950,
59
+ * height: 2400,
60
+ * onBudgetExceeded: (info) => console.log('Budget exceeded:', info),
61
+ * });
62
+ *
63
+ * runtime.startLoop();
64
+ * console.log(runtime.getPreviewStats());
65
+ * ```
66
+ */
67
+ export { createPreviewEngine as createPreviewRuntime } from './preview/preview-engine';
68
+ export declare const SDK_VERSION = "0.9.0";
69
+ export declare const PROTOCOL_VERSION = "0.9";
52
70
  export declare const IS_CANONICAL = false;
53
71
  export declare const IS_ARCHIVAL = false;
54
72
  export declare const RENDERER = "@nexart/ui-renderer";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AACpH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,WAAW,EACX,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,aAAa,EAEb,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,eAAe,EACf,YAAY,GACb,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,KAAK,gBAAgB,GACtB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,sBAAsB,EACtB,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,kBAAkB,EAAE,WAAW,IAAI,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE9E,YAAY,EACV,YAAY,EACZ,mBAAmB,EACnB,aAAa,GACd,MAAM,gBAAgB,CAAC;AAExB,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AACtC,eAAO,MAAM,YAAY,QAAQ,CAAC;AAClC,eAAO,MAAM,WAAW,QAAQ,CAAC;AACjC,eAAO,MAAM,QAAQ,wBAAwB,CAAC;AAC9C,eAAO,MAAM,wBAAwB,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AACpH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,WAAW,EACX,cAAc,EACd,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,GACtB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,eAAe,EACf,YAAY,GACb,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,KAAK,gBAAgB,GACtB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,sBAAsB,EACtB,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,kBAAkB,EAAE,WAAW,IAAI,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE9E,YAAY,EACV,YAAY,EACZ,mBAAmB,EACnB,aAAa,GACd,MAAM,gBAAgB,CAAC;AAMxB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,mBAAmB,IAAI,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEvF,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AACtC,eAAO,MAAM,YAAY,QAAQ,CAAC;AAClC,eAAO,MAAM,WAAW,QAAQ,CAAC;AACjC,eAAO,MAAM,QAAQ,wBAAwB,CAAC;AAC9C,eAAO,MAAM,wBAAwB,QAAQ,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @nexart/ui-renderer
3
- * Version: 0.8.6
3
+ * Version: 0.9.0
4
4
  *
5
5
  * Lightweight Preview Runtime for NexArt Protocol
6
6
  *
@@ -11,21 +11,15 @@
11
11
  * ║ It does not guarantee determinism or protocol compliance. ║
12
12
  * ║ ║
13
13
  * ║ Performance Limits: ║
14
- * ║ - Max frames: 30
15
- * ║ - Max total time: 500ms ║
14
+ * ║ - FPS: Native RAF (~60 FPS)
16
15
  * ║ - Max canvas dimension: 900px ║
17
- * ║ - Frame stride: render every 3rd frame
16
+ * ║ - Budget: 1800 frames / 5 minutes (configurable)
18
17
  * ║ ║
19
- * ║ Use Cases:
20
- * ║ - Editor live preview
21
- * ║ - Builder dashboards
22
- * ║ - Background generative art
23
- * ║ - Static or loop previews
24
- * ║ ║
25
- * ║ NOT For: ║
26
- * ║ - Minting / export ║
27
- * ║ - ByX ║
28
- * ║ - Protocol validation ║
18
+ * ║ v0.9.0 Features:
19
+ * ║ - Budget exceed callbacks + overlay
20
+ * ║ - getPreviewStats() for observability
21
+ * ║ - createPreviewRuntime() as recommended entrypoint
22
+ * ║ - toCanonicalRequest() for handoff to @nexart/codemode-sdk
29
23
  * ║ ║
30
24
  * ║ For canonical output: use @nexart/codemode-sdk ║
31
25
  * ╚══════════════════════════════════════════════════════════════════════════╝
@@ -39,15 +33,40 @@ export { compileBackgroundPreset, getPaletteColors } from './presets/backgrounds
39
33
  export { compilePrimitive } from './presets/primitives';
40
34
  export { wrapSketch, validateSketchSafety } from './presets/sketch-wrapper';
41
35
  export { getCapabilities, getPrimitiveTypes, getPrimitivesByCategory, getPrimitiveInfo, isPrimitiveValid, getMotionSources, getBackgroundTextures, } from './capabilities';
42
- export { createPreviewEngine, renderStaticPreview, stopActivePreview, } from './preview/preview-engine';
43
- export { PREVIEW_FPS, CANVAS_LIMITS, } from './preview/preview-types';
44
- export { createFpsThrottle, shouldRenderFrame, recordFrame, resetThrottle,
45
- // Deprecated exports for backward compatibility (will be removed in v0.9.0)
46
- createFrameBudget, canRenderFrame, resetBudget, shouldSkipFrame, getElapsedMs, } from './preview/frame-budget';
36
+ export { createPreviewEngine, renderStaticPreview, stopActivePreview, toCanonicalRequest, } from './preview/preview-engine';
37
+ export { PREVIEW_FPS, PREVIEW_BUDGET, CANVAS_LIMITS, } from './preview/preview-types';
38
+ export { createFpsThrottle, shouldRenderFrame, recordFrame, resetThrottle, createFrameBudget, canRenderFrame, resetBudget, shouldSkipFrame, getElapsedMs, } from './preview/frame-budget';
47
39
  export { calculateScaledDimensions, applyScaledDimensions, } from './preview/canvas-scaler';
48
40
  export { AESTHETIC_DEFAULTS, SDK_VERSION as TYPE_SDK_VERSION } from './types';
49
- export const SDK_VERSION = '0.8.6';
50
- export const PROTOCOL_VERSION = '0.8';
41
+ // ============================================================================
42
+ // v0.9.0 RECOMMENDED ENTRYPOINT
43
+ // ============================================================================
44
+ /**
45
+ * createPreviewRuntime - Recommended entrypoint for AI coding agents.
46
+ *
47
+ * This is an alias for createPreviewEngine with sensible defaults.
48
+ * Use this as the primary way to create previews.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * import { createPreviewRuntime } from '@nexart/ui-renderer';
53
+ *
54
+ * const runtime = createPreviewRuntime({
55
+ * canvas: document.getElementById('canvas'),
56
+ * source: 'function draw() { circle(width/2, height/2, 100); }',
57
+ * mode: 'loop',
58
+ * width: 1950,
59
+ * height: 2400,
60
+ * onBudgetExceeded: (info) => console.log('Budget exceeded:', info),
61
+ * });
62
+ *
63
+ * runtime.startLoop();
64
+ * console.log(runtime.getPreviewStats());
65
+ * ```
66
+ */
67
+ export { createPreviewEngine as createPreviewRuntime } from './preview/preview-engine';
68
+ export const SDK_VERSION = '0.9.0';
69
+ export const PROTOCOL_VERSION = '0.9';
51
70
  export const IS_CANONICAL = false;
52
71
  export const IS_ARCHIVAL = false;
53
72
  export const RENDERER = '@nexart/ui-renderer';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @nexart/ui-renderer v0.8.7 - Code Mode Renderer
2
+ * @nexart/ui-renderer v0.8.8 - Code Mode Renderer
3
3
  *
4
4
  * ╔══════════════════════════════════════════════════════════════════════════╗
5
5
  * ║ PREVIEW RENDERER — LIGHTWEIGHT, NON-AUTHORITATIVE ║
@@ -7,7 +7,7 @@
7
7
  * ║ This renderer is a preview-only runtime. ║
8
8
  * ║ It does not guarantee determinism or protocol compliance. ║
9
9
  * ║ ║
10
- * ║ Performance: FPS-capped at 8 FPS, canvas max 900px
10
+ * ║ Performance: Native requestAnimationFrame (~60 FPS), canvas max 900px
11
11
  * ║ Animation: Runs continuously until stop() is called ║
12
12
  * ║ ║
13
13
  * ║ For minting, export, or validation: use @nexart/codemode-sdk ║
@@ -1 +1 @@
1
- {"version":3,"file":"code-renderer.d.ts","sourceRoot":"","sources":["../../src/preview/code-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAwBjE,MAAM,WAAW,YAAY;IAC3B,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;AAwBD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,iBAAiB,EACzB,OAAO,GAAE,cAAmB,GAC3B,YAAY,CAoTd"}
1
+ {"version":3,"file":"code-renderer.d.ts","sourceRoot":"","sources":["../../src/preview/code-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAiBjE,MAAM,WAAW,YAAY;IAC3B,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;AAwBD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,iBAAiB,EACzB,OAAO,GAAE,cAAmB,GAC3B,YAAY,CA4Sd"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @nexart/ui-renderer v0.8.7 - Code Mode Renderer
2
+ * @nexart/ui-renderer v0.8.8 - Code Mode Renderer
3
3
  *
4
4
  * ╔══════════════════════════════════════════════════════════════════════════╗
5
5
  * ║ PREVIEW RENDERER — LIGHTWEIGHT, NON-AUTHORITATIVE ║
@@ -7,14 +7,13 @@
7
7
  * ║ This renderer is a preview-only runtime. ║
8
8
  * ║ It does not guarantee determinism or protocol compliance. ║
9
9
  * ║ ║
10
- * ║ Performance: FPS-capped at 8 FPS, canvas max 900px
10
+ * ║ Performance: Native requestAnimationFrame (~60 FPS), canvas max 900px
11
11
  * ║ Animation: Runs continuously until stop() is called ║
12
12
  * ║ ║
13
13
  * ║ For minting, export, or validation: use @nexart/codemode-sdk ║
14
14
  * ╚══════════════════════════════════════════════════════════════════════════╝
15
15
  */
16
- import { PREVIEW_FPS, CANVAS_LIMITS, } from './preview-types';
17
- import { createFpsThrottle, shouldRenderFrame, recordFrame, resetThrottle, } from './frame-budget';
16
+ import { CANVAS_LIMITS, } from './preview-types';
18
17
  import { calculateScaledDimensions, applyScaledDimensions, reapplyContextScale, clearCanvasIgnoringTransform, } from './canvas-scaler';
19
18
  import { createPreviewRuntime } from './preview-runtime';
20
19
  const PROTOCOL_VERSION = '1.2.0';
@@ -42,8 +41,8 @@ function normalizeVars(vars) {
42
41
  return result;
43
42
  }
44
43
  export function renderCodeModeSystem(system, canvas, options = {}) {
45
- console.log('[UIRenderer] Preview mode → FPS-capped continuous animation');
46
- console.log(`[UIRenderer] Target: ${PREVIEW_FPS.TARGET_FPS} FPS, canvas max ${CANVAS_LIMITS.MAX_DIMENSION}px`);
44
+ console.log('[UIRenderer] Preview mode → native requestAnimationFrame (~60 FPS)');
45
+ console.log(`[UIRenderer] Canvas max ${CANVAS_LIMITS.MAX_DIMENSION}px`);
47
46
  if (activeRendererInstance) {
48
47
  activeRendererInstance.destroy();
49
48
  activeRendererInstance = null;
@@ -61,7 +60,6 @@ export function renderCodeModeSystem(system, canvas, options = {}) {
61
60
  let animationId = null;
62
61
  let isRunning = false;
63
62
  let isDestroyed = false;
64
- const throttle = createFpsThrottle();
65
63
  const normalizedVars = normalizeVars(system.vars);
66
64
  let runtime = null;
67
65
  let setupFn = null;
@@ -217,15 +215,14 @@ export function renderCodeModeSystem(system, canvas, options = {}) {
217
215
  if (setupFn) {
218
216
  setupFn();
219
217
  }
220
- resetThrottle(throttle);
221
218
  isRunning = true;
222
219
  // ╔═══════════════════════════════════════════════════════════════════════╗
223
- // ║ ANIMATION LOOP — CONTINUOUS FPS-CAPPED RENDERING
220
+ // ║ ANIMATION LOOP — NATIVE requestAnimationFrame (~60 FPS)
224
221
  // ║ ║
225
- // ║ requestAnimationFrame runs continuously until stop() is called.
226
- // ║ FPS throttle (8 FPS) prevents excessive CPU usage.
222
+ // ║ v0.8.8: Removed FPS throttle for smooth rendering matching NexArt.
223
+ // ║ Browser handles frame pacing naturally via requestAnimationFrame.
227
224
  // ║ Looping uses modulo math: t = (frame % total) / total ║
228
- // ║ Canvas cleared before each draw; skipped frames preserve pixels.
225
+ // ║ Canvas cleared before each draw() call.
229
226
  // ╚═══════════════════════════════════════════════════════════════════════╝
230
227
  const loop = () => {
231
228
  // Schedule next frame first — loop runs until stop()
@@ -233,10 +230,6 @@ export function renderCodeModeSystem(system, canvas, options = {}) {
233
230
  // Exit if stopped or destroyed
234
231
  if (!isRunning || isDestroyed)
235
232
  return;
236
- // FPS throttle — skip if not enough time has passed
237
- if (!shouldRenderFrame(throttle)) {
238
- return; // Preserve current canvas
239
- }
240
233
  frameCount++;
241
234
  // Update runtime timing using modulo for natural looping
242
235
  if (runtime) {
@@ -251,7 +244,6 @@ export function renderCodeModeSystem(system, canvas, options = {}) {
251
244
  if (drawFn)
252
245
  drawFn();
253
246
  drawBadge();
254
- recordFrame(throttle);
255
247
  }
256
248
  catch (error) {
257
249
  console.warn('[UIRenderer] Draw error:', error);
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * @nexart/ui-renderer - Preview Engine
3
+ * Version: 0.9.0
3
4
  *
4
5
  * Lightweight, non-authoritative preview executor.
5
6
  * Safe, interruptible, and performant.
@@ -10,21 +11,18 @@
10
11
  * ║ This engine is a preview-only runtime. ║
11
12
  * ║ It does not guarantee determinism or protocol compliance. ║
12
13
  * ║ ║
13
- * ║ Usage:
14
- * ║ - Editor live preview
15
- * ║ - Builder dashboards
16
- * ║ - Background generative art
17
- * ║ - Static or loop previews ║
14
+ * ║ v0.9.0 Features:
15
+ * ║ - Budget exceed callbacks + overlay
16
+ * ║ - getPreviewStats() for observability
17
+ * ║ - toCanonicalRequest() for handoff to @nexart/codemode-sdk
18
18
  * ║ ║
19
- * ║ NOT for:
20
- * ║ - Minting / export
21
- * ║ - ByX ║
22
- * ║ - Protocol validation ║
19
+ * ║ Animation runs at native RAF cadence (~60 FPS) per v0.8.8.
20
+ * ║ Budget system uses frame count + time limits (not FPS throttling).
23
21
  * ║ ║
24
22
  * ║ For canonical output: use @nexart/codemode-sdk ║
25
23
  * ╚══════════════════════════════════════════════════════════════════════════╝
26
24
  */
27
- import { type PreviewEngineConfig, type PreviewRenderResult, type PreviewRenderer } from './preview-types';
25
+ import { type PreviewEngineConfig, type PreviewRenderResult, type PreviewRenderer, type CanonicalRequest } from './preview-types';
28
26
  /**
29
27
  * Create a preview renderer for the given configuration.
30
28
  *
@@ -39,4 +37,9 @@ export declare function renderStaticPreview(config: PreviewEngineConfig): Previe
39
37
  * Stop any active preview renderer.
40
38
  */
41
39
  export declare function stopActivePreview(): void;
40
+ /**
41
+ * Create a canonical request from preview config.
42
+ * For handoff to @nexart/codemode-sdk.
43
+ */
44
+ export declare function toCanonicalRequest(config: PreviewEngineConfig): CanonicalRequest;
42
45
  //# sourceMappingURL=preview-engine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"preview-engine.d.ts","sourceRoot":"","sources":["../../src/preview/preview-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EAErB,MAAM,iBAAiB,CAAC;AAiNzB;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,eAAe,CAEhF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB,CAKpF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAKxC"}
1
+ {"version":3,"file":"preview-engine.d.ts","sourceRoot":"","sources":["../../src/preview/preview-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EAIpB,KAAK,gBAAgB,EAEtB,MAAM,iBAAiB,CAAC;AAyVzB;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,eAAe,CAEhF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB,CAKpF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAKxC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,GAAG,gBAAgB,CAchF"}
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * @nexart/ui-renderer - Preview Engine
3
+ * Version: 0.9.0
3
4
  *
4
5
  * Lightweight, non-authoritative preview executor.
5
6
  * Safe, interruptible, and performant.
@@ -10,33 +11,38 @@
10
11
  * ║ This engine is a preview-only runtime. ║
11
12
  * ║ It does not guarantee determinism or protocol compliance. ║
12
13
  * ║ ║
13
- * ║ Usage:
14
- * ║ - Editor live preview
15
- * ║ - Builder dashboards
16
- * ║ - Background generative art
17
- * ║ - Static or loop previews ║
14
+ * ║ v0.9.0 Features:
15
+ * ║ - Budget exceed callbacks + overlay
16
+ * ║ - getPreviewStats() for observability
17
+ * ║ - toCanonicalRequest() for handoff to @nexart/codemode-sdk
18
18
  * ║ ║
19
- * ║ NOT for:
20
- * ║ - Minting / export
21
- * ║ - ByX ║
22
- * ║ - Protocol validation ║
19
+ * ║ Animation runs at native RAF cadence (~60 FPS) per v0.8.8.
20
+ * ║ Budget system uses frame count + time limits (not FPS throttling).
23
21
  * ║ ║
24
22
  * ║ For canonical output: use @nexart/codemode-sdk ║
25
23
  * ╚══════════════════════════════════════════════════════════════════════════╝
26
24
  */
27
- import { createFpsThrottle, shouldRenderFrame, recordFrame, resetThrottle, } from './frame-budget';
25
+ import { PREVIEW_BUDGET, } from './preview-types';
28
26
  import { calculateScaledDimensions, applyScaledDimensions, reapplyContextScale, } from './canvas-scaler';
29
27
  import { createPreviewRuntime } from './preview-runtime';
28
+ const SDK_VERSION = '0.9.0';
30
29
  let activePreviewRenderer = null;
31
30
  class PreviewEngine {
31
+ get previewScale() {
32
+ return this.scaled?.scaleFactor ?? 1;
33
+ }
32
34
  constructor(config) {
33
35
  this.runtime = null;
34
36
  this.setupFn = null;
35
37
  this.drawFn = null;
36
38
  this.animationFrameId = null;
37
- this.throttle = createFpsThrottle();
38
39
  this.running = false;
39
40
  this.internalFrameCount = 0;
41
+ this.startTimeMs = 0;
42
+ this.scaled = null;
43
+ this.currentStride = 1;
44
+ this.budgetExceededReason = null;
45
+ this.overlayElement = null;
40
46
  this.isCanonical = false;
41
47
  this.isArchival = false;
42
48
  this.config = config;
@@ -44,20 +50,10 @@ class PreviewEngine {
44
50
  this.initialize();
45
51
  }
46
52
  initialize() {
47
- const scaled = calculateScaledDimensions(this.config.width, this.config.height);
48
- applyScaledDimensions(this.canvas, scaled);
49
- // NOTE: Canvas resizing resets the 2D context transform.
50
- // Reapply scale factor once after resize for correct rendering.
51
- reapplyContextScale(this.canvas, scaled);
52
- // ╔═══════════════════════════════════════════════════════════════════════╗
53
- // ║ ARCHITECTURAL INVARIANT — DO NOT CHANGE ║
54
- // ║ Runtime width/height MUST equal protocol dimensions. ║
55
- // ║ DO NOT pass renderWidth/renderHeight — breaks loop animations. ║
56
- // ║ Scaling is handled by ctx.scale(), not by changing width/height. ║
57
- // ╚═══════════════════════════════════════════════════════════════════════╝
58
- this.runtime = createPreviewRuntime(this.canvas, scaled.originalWidth, // ← Protocol dimension
59
- scaled.originalHeight, // ← Protocol dimension
60
- this.config.seed ?? 12345, this.config.vars ?? []);
53
+ this.scaled = calculateScaledDimensions(this.config.width, this.config.height);
54
+ applyScaledDimensions(this.canvas, this.scaled);
55
+ reapplyContextScale(this.canvas, this.scaled);
56
+ this.runtime = createPreviewRuntime(this.canvas, this.scaled.originalWidth, this.scaled.originalHeight, this.config.seed ?? 12345, this.config.vars ?? []);
61
57
  const totalFrames = this.config.totalFrames ?? 120;
62
58
  this.runtime.totalFrames = totalFrames;
63
59
  try {
@@ -86,8 +82,123 @@ class PreviewEngine {
86
82
  const fn = new Function(...globalVars, wrappedSource);
87
83
  return () => fn(...globalValues);
88
84
  }
85
+ getPreviewStats() {
86
+ const elapsed = this.startTimeMs > 0 ? performance.now() - this.startTimeMs : 0;
87
+ return {
88
+ mode: 'preview',
89
+ scale: this.previewScale,
90
+ semanticWidth: this.scaled?.originalWidth ?? this.config.width,
91
+ semanticHeight: this.scaled?.originalHeight ?? this.config.height,
92
+ bufferWidth: this.scaled?.renderWidth ?? this.config.width,
93
+ bufferHeight: this.scaled?.renderHeight ?? this.config.height,
94
+ frames: this.internalFrameCount,
95
+ stride: this.currentStride,
96
+ totalTimeMs: elapsed,
97
+ ...(this.budgetExceededReason ? { budgetExceeded: { reason: this.budgetExceededReason } } : {}),
98
+ };
99
+ }
100
+ toCanonicalRequest() {
101
+ return {
102
+ seed: this.config.seed ?? 12345,
103
+ vars: this.config.vars ?? [],
104
+ code: this.config.source,
105
+ settings: {
106
+ width: this.config.width,
107
+ height: this.config.height,
108
+ mode: this.config.mode,
109
+ totalFrames: this.config.totalFrames,
110
+ },
111
+ renderer: 'preview',
112
+ uiRendererVersion: SDK_VERSION,
113
+ };
114
+ }
115
+ showBudgetOverlay(reason) {
116
+ if (this.overlayElement)
117
+ return;
118
+ const showOverlay = this.config.showOverlay ?? (this.config.budgetBehavior === 'stop');
119
+ if (!showOverlay)
120
+ return;
121
+ const overlay = document.createElement('div');
122
+ overlay.style.cssText = `
123
+ position: absolute;
124
+ top: 0;
125
+ left: 0;
126
+ right: 0;
127
+ bottom: 0;
128
+ background: rgba(0, 0, 0, 0.85);
129
+ display: flex;
130
+ flex-direction: column;
131
+ align-items: center;
132
+ justify-content: center;
133
+ color: white;
134
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
135
+ z-index: 1000;
136
+ pointer-events: none;
137
+ `;
138
+ const reasonText = reason === 'frame_limit'
139
+ ? `Frame limit reached (${this.internalFrameCount} frames)`
140
+ : `Time limit reached (${Math.round((performance.now() - this.startTimeMs) / 1000)}s)`;
141
+ overlay.innerHTML = `
142
+ <div style="font-size: 24px; margin-bottom: 8px;">⚠️ Preview Budget Exceeded</div>
143
+ <div style="font-size: 14px; opacity: 0.8; margin-bottom: 16px;">${reasonText}</div>
144
+ <div style="font-size: 12px; opacity: 0.6; max-width: 280px; text-align: center;">
145
+ Reduce sketch complexity or use @nexart/codemode-sdk for canonical execution.
146
+ </div>
147
+ `;
148
+ const parent = this.canvas.parentElement;
149
+ if (parent) {
150
+ parent.style.position = 'relative';
151
+ parent.appendChild(overlay);
152
+ this.overlayElement = overlay;
153
+ }
154
+ }
155
+ removeOverlay() {
156
+ if (this.overlayElement && this.overlayElement.parentElement) {
157
+ this.overlayElement.parentElement.removeChild(this.overlayElement);
158
+ this.overlayElement = null;
159
+ }
160
+ }
161
+ handleBudgetExceeded(reason) {
162
+ if (this.budgetExceededReason)
163
+ return; // Already exceeded — fire callback only once
164
+ this.budgetExceededReason = reason;
165
+ const behavior = this.config.budgetBehavior ?? 'stop';
166
+ const info = {
167
+ reason,
168
+ framesRendered: this.internalFrameCount,
169
+ totalTimeMs: performance.now() - this.startTimeMs,
170
+ stride: this.currentStride,
171
+ scale: this.previewScale,
172
+ };
173
+ console.warn(`[PreviewEngine] Budget exceeded: ${reason}`, info);
174
+ if (this.config.onBudgetExceeded) {
175
+ this.config.onBudgetExceeded(info);
176
+ }
177
+ if (behavior === 'stop') {
178
+ this.showBudgetOverlay(reason);
179
+ this.stopLoop();
180
+ }
181
+ else if (behavior === 'degrade') {
182
+ this.currentStride = PREVIEW_BUDGET.DEGRADE_STRIDE;
183
+ }
184
+ }
185
+ checkBudget() {
186
+ const maxFrames = this.config.maxFrames ?? PREVIEW_BUDGET.MAX_FRAMES;
187
+ const maxTimeMs = this.config.maxTimeMs ?? PREVIEW_BUDGET.MAX_TOTAL_TIME_MS;
188
+ const elapsed = performance.now() - this.startTimeMs;
189
+ if (this.internalFrameCount >= maxFrames) {
190
+ this.handleBudgetExceeded('frame_limit');
191
+ return false;
192
+ }
193
+ if (elapsed >= maxTimeMs) {
194
+ this.handleBudgetExceeded('time_limit');
195
+ return false;
196
+ }
197
+ return true;
198
+ }
89
199
  renderStatic() {
90
200
  const startTime = performance.now();
201
+ this.startTimeMs = startTime;
91
202
  try {
92
203
  if (this.setupFn) {
93
204
  this.setupFn();
@@ -119,8 +230,11 @@ class PreviewEngine {
119
230
  }
120
231
  activePreviewRenderer = this;
121
232
  this.running = true;
122
- resetThrottle(this.throttle);
233
+ this.startTimeMs = performance.now();
123
234
  this.internalFrameCount = 0;
235
+ this.currentStride = 1;
236
+ this.budgetExceededReason = null;
237
+ this.removeOverlay();
124
238
  try {
125
239
  if (this.setupFn) {
126
240
  this.setupFn();
@@ -131,25 +245,31 @@ class PreviewEngine {
131
245
  }
132
246
  this.scheduleNextFrame();
133
247
  }
134
- // ╔═══════════════════════════════════════════════════════════════════════╗
135
- // ║ ANIMATION LOOPCONTINUOUS FPS-CAPPED RENDERING ║
136
- // ║ ║
137
- // ║ requestAnimationFrame runs continuously until stop() is called.
138
- // ║ FPS throttle (8 FPS) prevents excessive CPU usage. ║
139
- // ║ Looping uses modulo math: t = (frame % total) / total ║
140
- // ╚═══════════════════════════════════════════════════════════════════════╝
248
+ /**
249
+ * Animation loopruns at native RAF cadence (~60 FPS).
250
+ * No FPS throttle per v0.8.8 decision.
251
+ * Budget system uses frame count and time limits only.
252
+ */
141
253
  scheduleNextFrame() {
142
- // Schedule next frame — loop runs until stopLoop()
143
254
  this.animationFrameId = requestAnimationFrame(() => {
255
+ // Always schedule next frame first (RAF continues until stop)
144
256
  this.scheduleNextFrame();
145
257
  // Exit if stopped
146
258
  if (!this.running)
147
259
  return;
148
- // FPS throttle — skip if not enough time has passed
149
- if (!shouldRenderFrame(this.throttle)) {
150
- return; // Preserve current canvas
151
- }
152
260
  this.internalFrameCount++;
261
+ // Check budget — fires callback once when exceeded
262
+ if (!this.checkBudget()) {
263
+ // If behavior is 'stop', loop already halted by handleBudgetExceeded
264
+ // If behavior is 'degrade', continue with stride skipping below
265
+ if (this.config.budgetBehavior !== 'degrade') {
266
+ return;
267
+ }
268
+ }
269
+ // Stride skip in degrade mode (render every Nth frame)
270
+ if (this.currentStride > 1 && this.internalFrameCount % this.currentStride !== 0) {
271
+ return;
272
+ }
153
273
  // Update runtime timing using modulo for natural looping
154
274
  try {
155
275
  if (this.runtime) {
@@ -162,7 +282,6 @@ class PreviewEngine {
162
282
  if (this.drawFn) {
163
283
  this.drawFn();
164
284
  }
165
- recordFrame(this.throttle);
166
285
  }
167
286
  catch (error) {
168
287
  console.warn('[PreviewEngine] Draw error:', error);
@@ -184,6 +303,7 @@ class PreviewEngine {
184
303
  }
185
304
  destroy() {
186
305
  this.stopLoop();
306
+ this.removeOverlay();
187
307
  this.runtime = null;
188
308
  this.setupFn = null;
189
309
  this.drawFn = null;
@@ -215,3 +335,22 @@ export function stopActivePreview() {
215
335
  activePreviewRenderer = null;
216
336
  }
217
337
  }
338
+ /**
339
+ * Create a canonical request from preview config.
340
+ * For handoff to @nexart/codemode-sdk.
341
+ */
342
+ export function toCanonicalRequest(config) {
343
+ return {
344
+ seed: config.seed ?? 12345,
345
+ vars: config.vars ?? [],
346
+ code: config.source,
347
+ settings: {
348
+ width: config.width,
349
+ height: config.height,
350
+ mode: config.mode,
351
+ totalFrames: config.totalFrames,
352
+ },
353
+ renderer: 'preview',
354
+ uiRendererVersion: SDK_VERSION,
355
+ };
356
+ }