@hypertools/sdk 0.2.0 → 0.2.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 (64) hide show
  1. package/LICENSE +1 -1
  2. package/dist/capture/index.js +13 -1
  3. package/dist/capture/index.js.map +2 -2
  4. package/dist/controls/index.js +13 -1
  5. package/dist/controls/index.js.map +2 -2
  6. package/dist/core/index.js +13 -1
  7. package/dist/core/index.js.map +2 -2
  8. package/dist/index.js +14 -1
  9. package/dist/index.js.map +2 -2
  10. package/dist/react/index.js +13 -1
  11. package/dist/react/index.js.map +2 -2
  12. package/dist/recording/index.js +13 -1
  13. package/dist/recording/index.js.map +2 -2
  14. package/package.json +31 -10
  15. package/dist/codegen/index.d.ts +0 -6
  16. package/dist/codegen/index.d.ts.map +0 -1
  17. package/dist/codegen/index.js +0 -800
  18. package/dist/codegen/index.js.map +0 -13
  19. package/dist/export/bundler.d.ts +0 -55
  20. package/dist/export/bundler.d.ts.map +0 -1
  21. package/dist/export/generators/index.d.ts +0 -6
  22. package/dist/export/generators/index.d.ts.map +0 -1
  23. package/dist/export/generators/webComponent.d.ts +0 -29
  24. package/dist/export/generators/webComponent.d.ts.map +0 -1
  25. package/dist/export/index.d.ts +0 -19
  26. package/dist/export/index.d.ts.map +0 -1
  27. package/dist/export/index.js +0 -800
  28. package/dist/export/index.js.map +0 -13
  29. package/dist/export/runtime.d.ts +0 -46
  30. package/dist/export/runtime.d.ts.map +0 -1
  31. package/dist/frame/cssBridge.d.ts +0 -34
  32. package/dist/frame/cssBridge.d.ts.map +0 -1
  33. package/dist/frame/index.d.ts +0 -9
  34. package/dist/frame/index.d.ts.map +0 -1
  35. package/dist/frame/index.js +0 -3
  36. package/dist/frame/index.js.map +0 -24
  37. package/dist/frame/runtime.d.ts +0 -39
  38. package/dist/frame/runtime.d.ts.map +0 -1
  39. package/dist/frame/types.d.ts +0 -119
  40. package/dist/frame/types.d.ts.map +0 -1
  41. package/dist/frame/utils/dom.d.ts +0 -11
  42. package/dist/frame/utils/dom.d.ts.map +0 -1
  43. package/dist/frame/wrapper-app/WrapperApp.d.ts +0 -16
  44. package/dist/frame/wrapper-app/WrapperApp.d.ts.map +0 -1
  45. package/dist/frame/wrapper-app/components/CanvasSizeWidget.d.ts +0 -17
  46. package/dist/frame/wrapper-app/components/CanvasSizeWidget.d.ts.map +0 -1
  47. package/dist/frame/wrapper-app/components/ControlsPanel.d.ts +0 -11
  48. package/dist/frame/wrapper-app/components/ControlsPanel.d.ts.map +0 -1
  49. package/dist/frame/wrapper-app/components/ExportWidget.d.ts +0 -16
  50. package/dist/frame/wrapper-app/components/ExportWidget.d.ts.map +0 -1
  51. package/dist/frame/wrapper-app/components/ResizeHandles.d.ts +0 -19
  52. package/dist/frame/wrapper-app/components/ResizeHandles.d.ts.map +0 -1
  53. package/dist/frame/wrapper-app/components/SandboxContainer.d.ts +0 -16
  54. package/dist/frame/wrapper-app/components/SandboxContainer.d.ts.map +0 -1
  55. package/dist/frame/wrapper-app/components/index.d.ts +0 -5
  56. package/dist/frame/wrapper-app/components/index.d.ts.map +0 -1
  57. package/dist/frame/wrapper-app/context/CanvasContext.d.ts +0 -37
  58. package/dist/frame/wrapper-app/context/CanvasContext.d.ts.map +0 -1
  59. package/dist/frame/wrapper-app/context/index.d.ts +0 -2
  60. package/dist/frame/wrapper-app/context/index.d.ts.map +0 -1
  61. package/dist/frame/wrapper-app/index.d.ts +0 -9
  62. package/dist/frame/wrapper-app/index.d.ts.map +0 -1
  63. package/dist/frame/wrapper-app/types.d.ts +0 -38
  64. package/dist/frame/wrapper-app/types.d.ts.map +0 -1
@@ -1,24 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/frame/runtime.ts", "../../src/frame/cssBridge.ts", "../../src/core/EventEmitter.ts", "../../src/core/ParamStore.ts", "../../src/core/ObjectRegistry.ts", "../../src/core/Experience.ts", "../../src/frame/utils/dom.ts", "../../src/frame/wrapper-app/WrapperApp.tsx", "../../src/frame/wrapper-app/components/ControlsPanel.tsx", "../../src/frame/wrapper-app/components/ExportWidget.tsx", "../../src/frame/wrapper-app/context/CanvasContext.tsx", "../../src/frame/wrapper-app/components/SandboxContainer.tsx", "../../src/frame/wrapper-app/components/ResizeHandles.tsx", "../../src/frame/wrapper-app/components/CanvasSizeWidget.tsx", "../../src/frame/index.ts"],
4
- "sourcesContent": [
5
- "/**\n * Frame Adapter - Thin wiring layer for editor iframe (WebContainer)\n *\n * This adapter:\n * - Uses Core Experience for ALL logic\n * - Optionally attaches Controls UI (Tweakpane)\n * - Wires postMessage for param sync with parent\n * - Wires postMessage for capture requests\n * - Handles CSS mirroring from parent\n *\n * THIN LAYER - no business logic here, just wiring!\n */\n\nimport React from 'react';\nimport { createRoot, type Root } from 'react-dom/client';\nimport { CssBridge } from './cssBridge';\nimport { Experience, type ExperienceContext, type SetupFunction } from '../core/Experience';\nimport type { ParamDefinitions } from '../core/ParamStore';\n\nimport {\n HyperFrameRuntimeApi,\n HyperFrameRuntimeConfig,\n HyperFrameSandboxHandle,\n HyperFrameSandboxOptions,\n SandboxContext,\n SandboxControlsHandle,\n SandboxEnvironment,\n} from './types';\nimport { resolveContainer } from './utils/dom';\nimport { WrapperApp } from './wrapper-app/WrapperApp';\n\n// ============================================================================\n// Frame Adapter\n// ============================================================================\n\nexport class HyperFrameRuntime implements HyperFrameRuntimeApi {\n private cssBridge: CssBridge | null = null;\n private config: HyperFrameRuntimeConfig;\n private currentExperience: Experience | null = null;\n\n constructor(config: HyperFrameRuntimeConfig = {}) {\n this.config = config;\n this.setupMessageHandlers();\n }\n\n // ===== Message Handlers (wiring to parent) =====\n\n private setupMessageHandlers(): void {\n if (typeof window === 'undefined') return;\n\n window.addEventListener('message', (event) => {\n const { type, data } = event.data || {};\n\n switch (type) {\n case 'CAPTURE_SCREENSHOT':\n this.handleCaptureScreenshot(event.data?.requestId);\n break;\n case 'HYPERTOOL_SET_PARAMS':\n this.handleSetParams(data?.params);\n break;\n case 'HYPERTOOL_GET_PARAMS':\n this.handleGetParams();\n break;\n }\n });\n }\n\n private handleCaptureScreenshot(requestId: string): void {\n // Try multiple strategies to find a capturable canvas:\n // 1. Canvas in current experience mount\n // 2. Any canvas in document body\n // 3. Fallback: signal no canvas available\n\n let canvas: HTMLCanvasElement | null = null;\n\n // Strategy 1: Canvas in mount (preferred - most specific)\n if (this.currentExperience) {\n canvas = this.currentExperience.mount.querySelector('canvas');\n }\n\n // Strategy 2: Search entire document for any canvas (handles edge cases)\n if (!canvas) {\n const allCanvases = document.querySelectorAll('canvas');\n if (allCanvases.length > 0) {\n // Find the largest canvas (likely the main rendering canvas)\n let largest = allCanvases[0] as HTMLCanvasElement;\n let largestArea = largest.width * largest.height;\n\n allCanvases.forEach((c) => {\n const canvas = c as HTMLCanvasElement;\n const area = canvas.width * canvas.height;\n if (area > largestArea) {\n largest = canvas;\n largestArea = area;\n }\n });\n\n canvas = largest;\n }\n }\n\n // No canvas found anywhere - signal to parent\n if (!canvas) {\n this.sendToParent('SCREENSHOT_RESULT', {\n requestId,\n noCanvas: true,\n error: 'No canvas found'\n });\n return;\n }\n\n try {\n const dataUrl = this.createOptimizedThumbnail(canvas, 400, 0.8);\n this.sendToParent('SCREENSHOT_RESULT', { requestId, dataUrl });\n } catch (error) {\n this.sendToParent('SCREENSHOT_RESULT', {\n requestId,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n }\n }\n\n private handleSetParams(params: Record<string, unknown> | undefined): void {\n if (!params || !this.currentExperience) return;\n this.currentExperience.setParams(params);\n }\n\n private handleGetParams(): void {\n const params = this.currentExperience?.getParams() ?? {};\n this.sendToParent('HYPERTOOL_PARAMS_RESPONSE', { params });\n }\n\n private sendToParent(type: string, data: Record<string, unknown>): void {\n window.parent.postMessage({ type, ...data }, '*');\n }\n\n private notifyParamChange(params: Record<string, unknown>): void {\n // Clean params for serialization\n const cleanParams: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(params)) {\n if (value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n cleanParams[key] = value;\n } else if (typeof value === 'object') {\n try {\n cleanParams[key] = JSON.parse(JSON.stringify(value));\n } catch {\n // Skip non-serializable\n }\n }\n }\n\n window.parent.postMessage({\n type: 'HYPERTOOL_PARAMS_CHANGED',\n source: 'hypertool-iframe',\n data: { params: cleanParams },\n }, '*');\n }\n\n // ===== Thumbnail Capture =====\n\n private createOptimizedThumbnail(\n sourceCanvas: HTMLCanvasElement,\n maxWidth: number,\n quality: number\n ): string {\n const { width: srcWidth, height: srcHeight } = sourceCanvas;\n\n let targetWidth = srcWidth;\n let targetHeight = srcHeight;\n\n if (srcWidth > maxWidth) {\n const ratio = maxWidth / srcWidth;\n targetWidth = maxWidth;\n targetHeight = Math.round(srcHeight * ratio);\n }\n\n const offscreenCanvas = document.createElement('canvas');\n offscreenCanvas.width = targetWidth;\n offscreenCanvas.height = targetHeight;\n\n const ctx = offscreenCanvas.getContext('2d');\n if (!ctx) {\n return sourceCanvas.toDataURL('image/jpeg', quality);\n }\n\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = 'high';\n ctx.drawImage(sourceCanvas, 0, 0, targetWidth, targetHeight);\n\n return offscreenCanvas.toDataURL('image/jpeg', quality);\n }\n\n // ===== CSS Mirror =====\n\n mirrorCss(): void {\n if (this.cssBridge) return;\n this.cssBridge = new CssBridge({ mirror: this.config.mirrorCss !== false });\n this.cssBridge.start();\n }\n\n // ===== Create Sandbox (main entry point) =====\n\n async createSandbox(options: HyperFrameSandboxOptions): Promise<HyperFrameSandboxHandle> {\n // Setup CSS mirroring\n if (this.config.mirrorCss !== false && options.mirrorCss !== false) {\n this.mirrorCss();\n }\n\n // Create React mount with optional controls UI\n const mount = await this.createReactMount(options);\n\n // Create Core Experience\n // Cast ControlDefinitions to ParamDefinitions (they're structurally compatible)\n const experience = new Experience({\n mount: mount.sandboxContainer,\n paramDefs: options.controls?.definitions as ParamDefinitions | undefined,\n autoplay: true,\n setup: (context) => this.wrapUserSetup(options.setup, context, options),\n });\n\n this.currentExperience = experience;\n\n // Wire param changes to parent\n experience.on('paramChange', () => {\n this.notifyParamChange(experience.getParams());\n });\n\n // Wire to controls if present\n if (options.controls?.definitions) {\n this.wireControlsToExperience(experience, mount);\n }\n\n // Register globally for capture handlers\n if (typeof (globalThis as any).__hypertool_registerParams === 'function') {\n (globalThis as any).__hypertool_registerParams(experience.params);\n }\n\n // Send initial params to parent\n this.notifyParamChange(experience.getParams());\n\n // Return handle\n const handle: HyperFrameSandboxHandle = {\n container: mount.sandboxContainer,\n controls: null, // Will be set by controls callback\n params: experience.params as Record<string, unknown>,\n destroy: () => {\n experience.destroy();\n mount.destroy();\n },\n };\n\n return handle;\n }\n\n /**\n * Wrap user's setup to adapt from our context to theirs\n * This is the THIN adapter part - just mapping\n */\n private wrapUserSetup(\n userSetup: HyperFrameSandboxOptions['setup'],\n context: ExperienceContext,\n options: HyperFrameSandboxOptions\n ): ReturnType<SetupFunction> {\n // Create legacy SandboxContext for backward compatibility\n const sandboxContext: SandboxContext = {\n mount: context.mount,\n params: context.params as Record<string, unknown>,\n controls: null, // Will be set later if controls are used\n exports: {\n registerImageCapture: () => {},\n registerVideoCapture: () => {},\n setFilename: context.exports.setFilename,\n setVisible: () => {},\n useDefaultCanvasCapture: () => {},\n destroy: () => {},\n },\n runtime: this,\n environment: {\n window: context.environment.window,\n document: context.environment.document,\n addCleanup: context.environment.addCleanup,\n onResize: (handler, opts) => {\n context.environment.window.addEventListener('resize', handler, opts);\n const dispose = () => context.environment.window.removeEventListener('resize', handler, opts);\n context.environment.addCleanup(dispose);\n return dispose;\n },\n },\n };\n\n // Call user's setup with legacy context\n return userSetup(sandboxContext);\n }\n\n /**\n * Wire controls UI to Experience params\n */\n private wireControlsToExperience(experience: Experience, mount: any): void {\n // Controls are rendered by WrapperApp\n // When controls change, they update their params object\n // We need to sync that with Experience\n\n // The WrapperApp's onReady callback gives us the controls instance\n // This happens via the mount.controlsCallback mechanism\n }\n\n // ===== React Mount =====\n\n private async createReactMount(options: HyperFrameSandboxOptions & { controls?: any }): Promise<{\n sandboxContainer: HTMLElement;\n destroy(): void;\n }> {\n const baseOptions = options.mount as any;\n const resolved = resolveContainer({\n target: baseOptions?.target,\n containerClassName: baseOptions?.containerClassName,\n });\n\n const root = createRoot(resolved.element);\n\n const controlsConfig = options.controls?.definitions\n ? {\n definitions: options.controls.definitions,\n options: options.controls.options,\n onChange: (change: { key: string; value: unknown; event?: unknown }) => {\n // CRITICAL: Sync control change to Experience's ParamStore\n // ControlsPanel transforms (params, context) → { key, value, event }\n if (this.currentExperience && change?.key !== undefined) {\n this.currentExperience.setParam(change.key, change.value);\n }\n // Also call user's onChange if provided\n options.controls?.onChange?.(change, {} as any);\n },\n onReady: (controls: any) => {\n // Sync initial control params with Experience\n if (this.currentExperience) {\n const controlParams = controls.params;\n this.currentExperience.setParams(controlParams);\n }\n\n // Register controls globally\n if (typeof (globalThis as any).__hypertool_registerControls === 'function') {\n (globalThis as any).__hypertool_registerControls(controls);\n }\n },\n }\n : null;\n\n const containerPromise = new Promise<HTMLElement>((resolve) => {\n root.render(\n React.createElement(WrapperApp, {\n onContainerReady: resolve,\n controls: controlsConfig,\n exportWidget: {\n enabled: options.exportWidget?.enabled !== false,\n filename: options.exportWidget?.filename,\n position: options.exportWidget?.position,\n useCanvasCapture: options.exportWidget?.useCanvasCapture !== false,\n },\n })\n );\n });\n\n const sandboxContainer = await containerPromise;\n\n if (typeof baseOptions?.onReady === 'function') {\n baseOptions.onReady({ container: sandboxContainer });\n }\n\n return {\n sandboxContainer,\n destroy: () => {\n root.unmount();\n if (resolved.createdInternally) {\n resolved.element.remove();\n }\n },\n };\n }\n}\n",
6
- "const CLONE_ATTRIBUTE = 'data-hyper-frame-clone';\nconst SUPPORTED_NODE_NAMES = new Set(['STYLE', 'LINK']);\n\n// Export for use by parent window CSS sync senders\nexport const CSS_SYNC_MESSAGE_TYPE = 'hyper-frame:css-sync';\n\ninterface CssBridgeOptions {\n sourceDocument?: Document | null;\n targetDocument?: Document | null;\n mirror?: boolean;\n}\n\ninterface CssSyncMessage {\n type: typeof CSS_SYNC_MESSAGE_TYPE;\n action: 'init' | 'add' | 'remove' | 'update';\n id?: string;\n tagName?: string;\n attributes?: Record<string, string>;\n textContent?: string;\n}\n\ntype NodeMapping = WeakMap<Node, Node>;\n\nexport class CssBridge {\n private source: Document | null;\n private target: Document | null;\n private observer: MutationObserver | null = null;\n private nodeMap: NodeMapping = new WeakMap();\n private active = false;\n private messageListener: ((event: MessageEvent) => void) | null = null;\n private usePostMessage = false;\n private cssNodesById = new Map<string, HTMLElement>();\n\n constructor(options: CssBridgeOptions = {}) {\n // Try to access parent document, but handle cross-origin errors gracefully\n\n let sourceDoc: Document | null = null;\n if (options.sourceDocument) {\n sourceDoc = options.sourceDocument;\n } else if (typeof window !== 'undefined') {\n try {\n // This will throw SecurityError if cross-origin\n sourceDoc = window.parent?.document ?? null;\n } catch (error) {\n // Cross-origin access blocked - use postMessage instead\n console.debug('[hyper-frame] Using postMessage for CSS sync (cross-origin)');\n this.usePostMessage = true;\n sourceDoc = null;\n }\n }\n\n this.source = sourceDoc;\n this.target = options.targetDocument ?? (typeof document !== 'undefined' ? document : null);\n this.active = Boolean(options.mirror ?? true);\n }\n\n start() {\n if (!this.active) return;\n\n\n\n if (this.usePostMessage) {\n // Use postMessage for cross-origin CSS sync\n this.startPostMessageMode();\n } else if (this.source && this.target) {\n // Use direct DOM access for same-origin\n this.cleanupPreviousClones();\n this.syncAll();\n this.attachObserver();\n } else {\n console.warn('[hyper-frame] Unable to mirror CSS – missing source or target document.');\n }\n }\n\n stop() {\n this.observer?.disconnect();\n this.observer = null;\n this.nodeMap = new WeakMap();\n this.cleanupPreviousClones();\n\n if (this.messageListener && typeof window !== 'undefined') {\n window.removeEventListener('message', this.messageListener);\n this.messageListener = null;\n }\n\n this.cssNodesById.clear();\n }\n\n private startPostMessageMode() {\n if (!this.target || typeof window === 'undefined') return;\n\n this.cleanupPreviousClones();\n\n this.messageListener = (event: MessageEvent) => {\n if (!event.data || event.data.type !== CSS_SYNC_MESSAGE_TYPE) return;\n this.handleCssMessage(event.data as CssSyncMessage);\n };\n\n window.addEventListener('message', this.messageListener);\n console.debug('[hyper-frame] CSS postMessage receiver ready');\n }\n\n private handleCssMessage(message: CssSyncMessage) {\n if (!this.target) return;\n\n switch (message.action) {\n case 'init':\n // Initial CSS sync - clear and prepare\n this.cleanupPreviousClones();\n this.cssNodesById.clear();\n break;\n\n case 'add':\n if (message.id && message.tagName) {\n this.addCssNode(message.id, message.tagName, message.attributes, message.textContent);\n }\n break;\n\n case 'remove':\n if (message.id) {\n this.removeCssNode(message.id);\n }\n break;\n\n case 'update':\n if (message.id) {\n this.updateCssNode(message.id, message.attributes, message.textContent);\n }\n break;\n }\n }\n\n private addCssNode(id: string, tagName: string, attributes?: Record<string, string>, textContent?: string) {\n if (!this.target) return;\n if (this.cssNodesById.has(id)) return; // Already exists\n\n const element = document.createElement(tagName);\n element.setAttribute(CLONE_ATTRIBUTE, 'true');\n element.setAttribute('data-css-id', id);\n\n if (attributes) {\n for (const [key, value] of Object.entries(attributes)) {\n element.setAttribute(key, value);\n }\n }\n\n if (textContent) {\n element.textContent = textContent;\n }\n\n this.target.head.appendChild(element);\n this.cssNodesById.set(id, element);\n }\n\n private removeCssNode(id: string) {\n const element = this.cssNodesById.get(id);\n if (element && element.parentNode) {\n element.parentNode.removeChild(element);\n this.cssNodesById.delete(id);\n }\n }\n\n private updateCssNode(id: string, attributes?: Record<string, string>, textContent?: string) {\n const element = this.cssNodesById.get(id);\n if (!element) return;\n\n if (attributes) {\n // Remove old attributes except special ones\n for (const attr of Array.from(element.attributes)) {\n if (!attr.name.startsWith('data-')) {\n element.removeAttribute(attr.name);\n }\n }\n\n // Set new attributes\n for (const [key, value] of Object.entries(attributes)) {\n element.setAttribute(key, value);\n }\n }\n\n if (textContent !== undefined) {\n element.textContent = textContent;\n }\n }\n\n private cleanupPreviousClones() {\n if (!this.target) return;\n this.target\n .querySelectorAll(`[${CLONE_ATTRIBUTE}=\"true\"]`)\n .forEach((node) => node.parentNode?.removeChild(node));\n }\n\n private async syncAll() {\n if (!this.source || !this.target) return;\n const head = this.source.head;\n const nodes = Array.from(head.children).filter((node) => SUPPORTED_NODE_NAMES.has(node.nodeName));\n\n for (const node of nodes) {\n const clone = await this.cloneNode(node);\n if (!clone) continue;\n this.target?.head.appendChild(clone);\n this.nodeMap.set(node, clone);\n }\n }\n\n private attachObserver() {\n if (!this.source || !this.target) return;\n if (this.observer) return;\n\n this.observer = new MutationObserver((mutations) => {\n mutations.forEach((mutation) => {\n switch (mutation.type) {\n case 'childList':\n this.handleChildListMutation(mutation);\n break;\n case 'characterData':\n this.handleCharacterDataMutation(mutation);\n break;\n case 'attributes':\n this.handleAttributeMutation(mutation);\n break;\n }\n });\n });\n\n this.observer.observe(this.source.head, {\n childList: true,\n subtree: true,\n characterData: true,\n attributes: true,\n });\n }\n\n private handleChildListMutation(mutation: MutationRecord) {\n if (!this.target) return;\n\n mutation.removedNodes.forEach((node) => {\n const mapped = this.nodeMap.get(node);\n if (mapped && mapped.parentNode) {\n mapped.parentNode.removeChild(mapped);\n this.nodeMap.delete(node);\n }\n });\n\n mutation.addedNodes.forEach(async (node) => {\n if (!(node instanceof HTMLElement)) return;\n if (!SUPPORTED_NODE_NAMES.has(node.nodeName)) return;\n\n try {\n const clone = await this.cloneNode(node);\n if (!clone) return;\n\n const reference = mutation.nextSibling ? this.nodeMap.get(mutation.nextSibling) : null;\n if (reference && reference.parentNode) {\n reference.parentNode.insertBefore(clone, reference);\n } else {\n this.target?.head.appendChild(clone);\n }\n\n this.nodeMap.set(node, clone);\n } catch (error) {\n console.error('[CssBridge] Failed to clone node:', error);\n }\n });\n }\n\n private handleCharacterDataMutation(mutation: MutationRecord) {\n const targetNode = mutation.target;\n const parent = targetNode.parentNode;\n if (!parent) return;\n const mappedParent = this.nodeMap.get(parent);\n if (!mappedParent) return;\n\n mappedParent.textContent = parent.textContent;\n }\n\n private handleAttributeMutation(mutation: MutationRecord) {\n const target = mutation.target as Element;\n const mapped = this.nodeMap.get(target);\n if (!mapped || !(mapped instanceof Element)) return;\n\n if (mutation.attributeName) {\n const value = target.getAttribute(mutation.attributeName);\n if (value === null) {\n mapped.removeAttribute(mutation.attributeName);\n } else {\n mapped.setAttribute(mutation.attributeName, value);\n }\n }\n }\n\n private async cloneNode(node: Node): Promise<HTMLElement | null> {\n if (!(node instanceof HTMLElement)) return null;\n if (!SUPPORTED_NODE_NAMES.has(node.nodeName)) return null;\n\n // For LINK tags, handle differently based on rel type\n if (node.nodeName === 'LINK' && node instanceof HTMLLinkElement) {\n const href = node.getAttribute('href');\n const rel = node.getAttribute('rel');\n\n if (href) {\n // For stylesheet links, fetch and inline the CSS\n if (rel === 'stylesheet') {\n try {\n const cssContent = await this.fetchCssContent(href);\n const styleElement = document.createElement('STYLE');\n styleElement.textContent = cssContent;\n styleElement.setAttribute(CLONE_ATTRIBUTE, 'true');\n return styleElement;\n } catch (error) {\n console.error(`[CssBridge] Failed to fetch CSS from ${href}:`, error);\n // Fall through to clone with absolute URL\n }\n }\n\n // For non-stylesheet links (preload, etc.), convert href to absolute URL\n const clone = node.cloneNode(true) as HTMLElement;\n try {\n const baseUrl = this.source ? new URL(this.source.location.href) : new URL(window.location.href);\n const absoluteUrl = new URL(href, baseUrl).href;\n clone.setAttribute('href', absoluteUrl);\n } catch (error) {\n console.error(`[CssBridge] Failed to convert URL to absolute: ${href}`, error);\n }\n clone.setAttribute(CLONE_ATTRIBUTE, 'true');\n return clone;\n }\n }\n\n const clone = node.cloneNode(true) as HTMLElement;\n clone.setAttribute(CLONE_ATTRIBUTE, 'true');\n return clone;\n }\n\n private async fetchCssContent(href: string): Promise<string> {\n // Convert relative URLs to absolute using parent window's location\n const baseUrl = this.source ? new URL(this.source.location.href) : new URL(window.location.href);\n const absoluteUrl = new URL(href, baseUrl).href;\n\n const response = await fetch(absoluteUrl);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return await response.text();\n }\n}\n",
7
- "/**\n * Typed event system for Experience\n */\n\nexport type ExperienceEventType =\n | 'ready'\n | 'error'\n | 'frame'\n | 'resize'\n | 'paramChange'\n | 'play'\n | 'pause'\n | 'objectRegistered'\n | 'objectUnregistered'\n | string; // Allow custom events\n\nexport interface ExperienceEvent {\n type: ExperienceEventType;\n timestamp: number;\n}\n\nexport interface ReadyEvent extends ExperienceEvent {\n type: 'ready';\n}\n\nexport interface ErrorEvent extends ExperienceEvent {\n type: 'error';\n error: Error;\n}\n\nexport interface FrameEvent extends ExperienceEvent {\n type: 'frame';\n frame: number;\n deltaTime: number;\n}\n\nexport interface ResizeEvent extends ExperienceEvent {\n type: 'resize';\n width: number;\n height: number;\n}\n\nexport interface ParamChangeEvent extends ExperienceEvent {\n type: 'paramChange';\n key: string;\n value: unknown;\n previousValue: unknown;\n}\n\nexport interface PlayEvent extends ExperienceEvent {\n type: 'play';\n}\n\nexport interface PauseEvent extends ExperienceEvent {\n type: 'pause';\n}\n\nexport interface ObjectRegisteredEvent extends ExperienceEvent {\n type: 'objectRegistered';\n name: string;\n id: string;\n}\n\nexport interface ObjectUnregisteredEvent extends ExperienceEvent {\n type: 'objectUnregistered';\n name: string;\n}\n\nexport type EventHandler<T extends ExperienceEvent = ExperienceEvent> = (\n event: T\n) => void;\n\nexport class EventEmitter {\n private _handlers = new Map<ExperienceEventType, Set<EventHandler>>();\n\n /**\n * Subscribe to event\n * @returns Unsubscribe function\n */\n on<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): () => void {\n if (!this._handlers.has(type)) {\n this._handlers.set(type, new Set());\n }\n this._handlers.get(type)!.add(handler as EventHandler);\n\n // Return unsubscribe function\n return () => this.off(type, handler);\n }\n\n /**\n * Subscribe once - auto-unsubscribes after first call\n */\n once<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): () => void {\n const wrapper: EventHandler<T> = (event) => {\n this.off(type, wrapper);\n handler(event);\n };\n return this.on(type, wrapper);\n }\n\n /**\n * Unsubscribe from event\n */\n off<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): void {\n const handlers = this._handlers.get(type);\n if (handlers) {\n handlers.delete(handler as EventHandler);\n }\n }\n\n /**\n * Emit event to all handlers\n */\n emit<T extends ExperienceEvent>(event: T): void {\n const handlers = this._handlers.get(event.type);\n if (!handlers) return;\n\n for (const handler of handlers) {\n try {\n handler(event);\n } catch (error) {\n console.error(`[EventEmitter] Handler error for ${event.type}:`, error);\n }\n }\n }\n\n /**\n * Remove all listeners for a type (or all if no type specified)\n */\n removeAllListeners(type?: ExperienceEventType): void {\n if (type) {\n this._handlers.delete(type);\n } else {\n this._handlers.clear();\n }\n }\n\n /**\n * Get listener count for a type\n */\n listenerCount(type: ExperienceEventType): number {\n return this._handlers.get(type)?.size ?? 0;\n }\n}\n",
8
- "/**\n * Reactive parameter store with Proxy-based reactivity\n */\n\nexport type ParamType =\n | 'number'\n | 'color'\n | 'boolean'\n | 'string'\n | 'select'\n | 'file'\n | 'point2d'\n | 'point3d';\n\nexport interface SelectOption {\n label: string;\n value: string;\n}\n\nexport interface ParamDefinition {\n type: ParamType;\n value: unknown;\n label?: string;\n\n // Number constraints\n min?: number;\n max?: number;\n step?: number;\n\n // Select options\n options?: (string | SelectOption)[];\n\n // File constraints\n accept?: string;\n maxSize?: number;\n}\n\nexport type ParamDefinitions = Record<string, ParamDefinition>;\nexport type ParamValues = Record<string, unknown>;\n\nexport type ParamChangeCallback = (\n key: string,\n value: unknown,\n previousValue: unknown\n) => void;\n\nexport class ParamStore {\n private _definitions: ParamDefinitions;\n private _values: ParamValues;\n private _listeners: Set<ParamChangeCallback>;\n private _proxy: ParamValues;\n\n constructor(definitions: ParamDefinitions, initialOverrides?: ParamValues) {\n this._definitions = definitions;\n this._listeners = new Set();\n\n // Initialize from definitions\n this._values = {};\n for (const [key, def] of Object.entries(definitions)) {\n this._values[key] = def.value;\n }\n\n // Apply overrides\n if (initialOverrides) {\n for (const [key, value] of Object.entries(initialOverrides)) {\n if (key in this._definitions) {\n this._values[key] = this._validate(key, value);\n }\n }\n }\n\n // Create reactive proxy\n this._proxy = this._createProxy();\n }\n\n private _createProxy(): ParamValues {\n const self = this;\n return new Proxy(this._values, {\n get(target, prop: string) {\n return target[prop];\n },\n set(target, prop: string, value: unknown) {\n if (!(prop in self._definitions)) {\n console.warn(`[ParamStore] Unknown parameter: ${prop}`);\n return false;\n }\n\n const validated = self._validate(prop, value);\n const previous = target[prop];\n\n if (validated !== previous) {\n target[prop] = validated;\n self._notify(prop, validated, previous);\n }\n\n return true;\n },\n has(target, prop: string) {\n return prop in target;\n },\n ownKeys(target) {\n return Object.keys(target);\n },\n getOwnPropertyDescriptor(target, prop: string) {\n if (prop in target) {\n return {\n enumerable: true,\n configurable: true,\n value: target[prop],\n };\n }\n return undefined;\n },\n });\n }\n\n private _validate(key: string, value: unknown): unknown {\n const def = this._definitions[key];\n if (!def) return value;\n\n switch (def.type) {\n case 'number': {\n let num = typeof value === 'number' ? value : parseFloat(String(value));\n if (isNaN(num)) num = def.value as number;\n if (def.min !== undefined) num = Math.max(def.min, num);\n if (def.max !== undefined) num = Math.min(def.max, num);\n if (def.step !== undefined) {\n num = Math.round(num / def.step) * def.step;\n }\n return num;\n }\n\n case 'color': {\n const str = String(value);\n // Accept various color formats\n if (/^#[0-9A-Fa-f]{6}$/.test(str)) return str;\n if (/^#[0-9A-Fa-f]{3}$/.test(str)) return str;\n if (/^#[0-9A-Fa-f]{8}$/.test(str)) return str; // RGBA\n if (/^rgb\\(/.test(str)) return str;\n if (/^rgba\\(/.test(str)) return str;\n if (/^hsl\\(/.test(str)) return str;\n if (/^hsla\\(/.test(str)) return str;\n return def.value;\n }\n\n case 'boolean':\n if (typeof value === 'boolean') return value;\n if (value === 'true' || value === '1') return true;\n if (value === 'false' || value === '0') return false;\n return Boolean(value);\n\n case 'string':\n return String(value);\n\n case 'select': {\n const str = String(value);\n const options = def.options || [];\n const valid = options.some((opt) =>\n typeof opt === 'object' ? opt.value === str : opt === str\n );\n return valid ? str : def.value;\n }\n\n case 'point2d': {\n if (\n typeof value === 'object' &&\n value !== null &&\n 'x' in value &&\n 'y' in value\n ) {\n return { x: Number((value as any).x), y: Number((value as any).y) };\n }\n return def.value;\n }\n\n case 'point3d': {\n if (\n typeof value === 'object' &&\n value !== null &&\n 'x' in value &&\n 'y' in value &&\n 'z' in value\n ) {\n return {\n x: Number((value as any).x),\n y: Number((value as any).y),\n z: Number((value as any).z),\n };\n }\n return def.value;\n }\n\n default:\n return value;\n }\n }\n\n private _notify(key: string, value: unknown, previous: unknown): void {\n for (const listener of this._listeners) {\n try {\n listener(key, value, previous);\n } catch (error) {\n console.error('[ParamStore] Listener error:', error);\n }\n }\n }\n\n /**\n * Get reactive params proxy\n */\n getProxy(): ParamValues {\n return this._proxy;\n }\n\n /**\n * Get snapshot of current values (non-reactive copy)\n */\n getSnapshot(): ParamValues {\n return { ...this._values };\n }\n\n /**\n * Get definitions\n */\n getDefinitions(): ParamDefinitions {\n return { ...this._definitions };\n }\n\n /**\n * Set single value\n */\n set(key: string, value: unknown): void {\n this._proxy[key] = value;\n }\n\n /**\n * Set multiple values\n */\n setMultiple(params: ParamValues): void {\n for (const [key, value] of Object.entries(params)) {\n this._proxy[key] = value;\n }\n }\n\n /**\n * Reset to defaults\n */\n reset(): void {\n for (const [key, def] of Object.entries(this._definitions)) {\n this._proxy[key] = def.value;\n }\n }\n\n /**\n * Subscribe to changes\n * @returns Unsubscribe function\n */\n subscribe(callback: ParamChangeCallback): () => void {\n this._listeners.add(callback);\n return () => this._listeners.delete(callback);\n }\n\n /**\n * Add a new param definition dynamically\n */\n addDefinition(key: string, definition: ParamDefinition): void {\n this._definitions[key] = definition;\n this._values[key] = definition.value;\n }\n}\n",
9
- "/**\n * Spline-like object registry for querying objects by name/id\n */\n\nexport interface RegisteredObject<T = unknown> {\n name: string;\n id: string;\n object: T;\n metadata?: Record<string, unknown>;\n}\n\nexport type ObjectRegisteredCallback = (name: string, id: string, object: unknown) => void;\nexport type ObjectUnregisteredCallback = (name: string) => void;\n\nexport class ObjectRegistry {\n private _byName = new Map<string, RegisteredObject>();\n private _byId = new Map<string, RegisteredObject>();\n private _onRegister: Set<ObjectRegisteredCallback> = new Set();\n private _onUnregister: Set<ObjectUnregisteredCallback> = new Set();\n\n /**\n * Register an object for external access\n * @returns Generated ID for the object\n */\n register<T>(\n name: string,\n object: T,\n metadata?: Record<string, unknown>\n ): string {\n // If name already exists, unregister first\n if (this._byName.has(name)) {\n this.unregister(name);\n }\n\n const id = this._generateId();\n\n const registered: RegisteredObject<T> = {\n name,\n id,\n object,\n metadata,\n };\n\n this._byName.set(name, registered);\n this._byId.set(id, registered);\n\n // Notify listeners\n for (const callback of this._onRegister) {\n try {\n callback(name, id, object);\n } catch (e) {\n console.error('[ObjectRegistry] onRegister callback error:', e);\n }\n }\n\n return id;\n }\n\n /**\n * Unregister an object by name\n */\n unregister(name: string): boolean {\n const obj = this._byName.get(name);\n if (!obj) return false;\n\n this._byName.delete(name);\n this._byId.delete(obj.id);\n\n // Notify listeners\n for (const callback of this._onUnregister) {\n try {\n callback(name);\n } catch (e) {\n console.error('[ObjectRegistry] onUnregister callback error:', e);\n }\n }\n\n return true;\n }\n\n /**\n * Find object by name (Spline-like API)\n */\n findByName<T = unknown>(name: string): T | undefined {\n return this._byName.get(name)?.object as T | undefined;\n }\n\n /**\n * Find object by ID\n */\n findById<T = unknown>(id: string): T | undefined {\n return this._byId.get(id)?.object as T | undefined;\n }\n\n /**\n * Get registered object info by name\n */\n getInfo(name: string): RegisteredObject | undefined {\n return this._byName.get(name);\n }\n\n /**\n * Check if an object exists\n */\n has(name: string): boolean {\n return this._byName.has(name);\n }\n\n /**\n * Get all registered object names\n */\n getNames(): string[] {\n return Array.from(this._byName.keys());\n }\n\n /**\n * Get all registered objects as a Map\n */\n getAll(): Map<string, unknown> {\n const result = new Map<string, unknown>();\n for (const [name, registered] of this._byName) {\n result.set(name, registered.object);\n }\n return result;\n }\n\n /**\n * Query objects by metadata\n */\n query(predicate: (obj: RegisteredObject) => boolean): RegisteredObject[] {\n const results: RegisteredObject[] = [];\n for (const obj of this._byName.values()) {\n if (predicate(obj)) {\n results.push(obj);\n }\n }\n return results;\n }\n\n /**\n * Query objects by type (requires metadata.type to be set)\n */\n findByType<T = unknown>(type: string): T[] {\n return this.query((obj) => obj.metadata?.type === type).map(\n (obj) => obj.object as T\n );\n }\n\n /**\n * Clear all registered objects\n */\n clear(): void {\n const names = Array.from(this._byName.keys());\n for (const name of names) {\n this.unregister(name);\n }\n }\n\n /**\n * Subscribe to object registration events\n */\n onRegister(callback: ObjectRegisteredCallback): () => void {\n this._onRegister.add(callback);\n return () => this._onRegister.delete(callback);\n }\n\n /**\n * Subscribe to object unregistration events\n */\n onUnregister(callback: ObjectUnregisteredCallback): () => void {\n this._onUnregister.add(callback);\n return () => this._onUnregister.delete(callback);\n }\n\n /**\n * Get the number of registered objects\n */\n get size(): number {\n return this._byName.size;\n }\n\n private _generateId(): string {\n return `obj_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;\n }\n}\n",
10
- "/**\n * Core Experience class - THE shared logic for all runtimes\n *\n * This is the brain. All adapters (Frame, Export, HostedPreview) use this.\n * Adapters are thin wiring layers - Experience contains ALL the logic.\n */\n\nimport {\n EventEmitter,\n type ExperienceEvent,\n type EventHandler,\n type ParamChangeEvent,\n type FrameEvent,\n type ResizeEvent,\n type ErrorEvent,\n} from './EventEmitter';\nimport { ParamStore, type ParamDefinitions, type ParamValues } from './ParamStore';\nimport { ObjectRegistry } from './ObjectRegistry';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ExperienceConfig {\n /** Mount element where content is rendered */\n mount: HTMLElement;\n\n /** Parameter definitions schema */\n paramDefs?: ParamDefinitions;\n\n /** Initial parameter values (overrides defaults from paramDefs) */\n initialParams?: Record<string, unknown>;\n\n /** User's setup function */\n setup: SetupFunction;\n\n /** Auto-start on init (default: true) */\n autoplay?: boolean;\n\n /** Target frame rate for frame events (default: 60) */\n frameRate?: number;\n\n /** Background color/style */\n background?: string;\n}\n\n/**\n * Context passed to user's setup function\n * This is the API users interact with in their code\n */\nexport interface ExperienceContext {\n /** DOM element to render into */\n mount: HTMLElement;\n\n /** Reactive params object (Proxy) - changes trigger events */\n params: ParamValues;\n\n /** Export/capture utilities */\n exports: ExportsApi;\n\n /** Environment utilities (window, document, resize) */\n environment: EnvironmentApi;\n\n /** Register an object for Spline-like queries */\n registerObject: <T = unknown>(\n name: string,\n object: T,\n metadata?: Record<string, unknown>\n ) => string;\n\n /** Find registered object by name */\n findObjectByName: <T = unknown>(name: string) => T | undefined;\n\n /** Experience instance (for advanced use) */\n experience: Experience;\n}\n\nexport interface ExportsApi {\n /** Capture canvas as image */\n captureImage: (format?: 'png' | 'jpeg' | 'webp') => Promise<Blob | null>;\n\n /** Set filename for exports */\n setFilename: (filename: string) => void;\n\n /** Register custom capture handler */\n registerCaptureHandler: (handler: CaptureHandler) => void;\n}\n\nexport type CaptureHandler = (format: string) => Promise<Blob | null>;\n\nexport interface EnvironmentApi {\n /** Window reference */\n window: Window;\n\n /** Document reference */\n document: Document;\n\n /** Subscribe to resize events, returns cleanup */\n onResize: (callback: (width: number, height: number) => void) => () => void;\n\n /** Add cleanup function to be called on destroy */\n addCleanup: (cleanup: () => void) => void;\n}\n\nexport type SetupFunction = (\n context: ExperienceContext\n) => CleanupFunction | void | Promise<CleanupFunction | void>;\n\nexport type CleanupFunction = () => void;\n\n// ============================================================================\n// Experience Class\n// ============================================================================\n\nexport class Experience {\n // State\n private _isReady = false;\n private _isPlaying = false;\n private _isDestroyed = false;\n private _currentFrame = 0;\n\n // Core systems\n private _paramStore: ParamStore;\n private _events: EventEmitter;\n private _objects: ObjectRegistry;\n\n // Config\n private _mount: HTMLElement;\n private _frameRate: number;\n private _filename = 'capture';\n\n // Lifecycle\n private _cleanups: CleanupFunction[] = [];\n private _userCleanup?: CleanupFunction;\n private _animationFrameId?: number;\n private _lastFrameTime = 0;\n private _resizeObserver?: ResizeObserver;\n private _captureHandler?: CaptureHandler;\n\n constructor(config: ExperienceConfig) {\n this._mount = config.mount;\n this._frameRate = config.frameRate ?? 60;\n\n // Apply background if provided\n if (config.background) {\n this._mount.style.background = config.background;\n }\n\n // Initialize core systems\n this._paramStore = new ParamStore(\n config.paramDefs ?? {},\n config.initialParams\n );\n this._events = new EventEmitter();\n this._objects = new ObjectRegistry();\n\n // Subscribe to param changes -> emit events\n this._paramStore.subscribe((key, value, previousValue) => {\n this._events.emit<ParamChangeEvent>({\n type: 'paramChange',\n timestamp: Date.now(),\n key,\n value,\n previousValue,\n });\n });\n\n // Setup resize observer\n this._setupResizeObserver();\n\n // Run user setup\n this._runSetup(config.setup, config.autoplay ?? true);\n }\n\n // ===== Public Getters =====\n\n get isReady(): boolean {\n return this._isReady;\n }\n\n get isPlaying(): boolean {\n return this._isPlaying;\n }\n\n get isDestroyed(): boolean {\n return this._isDestroyed;\n }\n\n get currentFrame(): number {\n return this._currentFrame;\n }\n\n get mount(): HTMLElement {\n return this._mount;\n }\n\n /** Reactive params proxy */\n get params(): ParamValues {\n return this._paramStore.getProxy();\n }\n\n /** EventEmitter for external subscriptions */\n get events(): EventEmitter {\n return this._events;\n }\n\n /** ObjectRegistry for external access */\n get objects(): ObjectRegistry {\n return this._objects;\n }\n\n // ===== Parameter Methods =====\n\n setParam(key: string, value: unknown): void {\n this._paramStore.set(key, value);\n }\n\n setParams(params: Record<string, unknown>): void {\n this._paramStore.setMultiple(params);\n }\n\n getParams(): Record<string, unknown> {\n return this._paramStore.getSnapshot();\n }\n\n getParamDefs(): ParamDefinitions {\n return this._paramStore.getDefinitions();\n }\n\n resetParams(): void {\n this._paramStore.reset();\n }\n\n // ===== Object Registry (Spline-like) =====\n\n registerObject<T = unknown>(\n name: string,\n object: T,\n metadata?: Record<string, unknown>\n ): string {\n return this._objects.register(name, object, metadata);\n }\n\n findObjectByName<T = unknown>(name: string): T | undefined {\n return this._objects.findByName<T>(name);\n }\n\n findObjectById<T = unknown>(id: string): T | undefined {\n return this._objects.findById<T>(id);\n }\n\n getAllObjects(): Map<string, unknown> {\n return this._objects.getAll();\n }\n\n // ===== Playback =====\n\n play(): void {\n if (this._isPlaying || this._isDestroyed) return;\n this._isPlaying = true;\n this._lastFrameTime = performance.now();\n this._tick();\n this._events.emit({ type: 'play', timestamp: Date.now() });\n }\n\n pause(): void {\n if (!this._isPlaying) return;\n this._isPlaying = false;\n if (this._animationFrameId) {\n cancelAnimationFrame(this._animationFrameId);\n this._animationFrameId = undefined;\n }\n this._events.emit({ type: 'pause', timestamp: Date.now() });\n }\n\n toggle(): void {\n if (this._isPlaying) {\n this.pause();\n } else {\n this.play();\n }\n }\n\n // ===== Events =====\n\n on<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): () => void {\n return this._events.on(type, handler);\n }\n\n once<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): () => void {\n return this._events.once(type, handler);\n }\n\n off<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): void {\n this._events.off(type, handler);\n }\n\n // ===== Capture =====\n\n async captureImage(format: 'png' | 'jpeg' | 'webp' = 'png'): Promise<Blob | null> {\n // Use custom handler if registered\n if (this._captureHandler) {\n return this._captureHandler(format);\n }\n\n // Default: find canvas and capture\n const canvas = this._mount.querySelector('canvas');\n if (!canvas) {\n console.warn('[Experience] No canvas found for capture');\n return null;\n }\n\n return new Promise((resolve) => {\n const mimeType = `image/${format}`;\n const quality = format === 'jpeg' ? 0.92 : undefined;\n canvas.toBlob((blob) => resolve(blob), mimeType, quality);\n });\n }\n\n getFilename(): string {\n return this._filename;\n }\n\n // ===== Lifecycle =====\n\n /**\n * Add a cleanup function to be called on destroy\n */\n addCleanup(cleanup: CleanupFunction): void {\n if (typeof cleanup === 'function') {\n this._cleanups.push(cleanup);\n }\n }\n\n /**\n * Destroy the experience and run all cleanups\n */\n destroy(): void {\n if (this._isDestroyed) return;\n this._isDestroyed = true;\n\n // Stop animation\n this.pause();\n\n // Run user cleanup first\n if (this._userCleanup) {\n try {\n this._userCleanup();\n } catch (e) {\n console.error('[Experience] User cleanup error:', e);\n }\n }\n\n // Run registered cleanups (reverse order)\n while (this._cleanups.length > 0) {\n const cleanup = this._cleanups.pop();\n if (cleanup) {\n try {\n cleanup();\n } catch (e) {\n console.error('[Experience] Cleanup error:', e);\n }\n }\n }\n\n // Disconnect observers\n this._resizeObserver?.disconnect();\n\n // Clear registry\n this._objects.clear();\n\n // Remove all event listeners\n this._events.removeAllListeners();\n\n // Emit destroyed event before clearing\n this._events.emit({ type: 'destroyed', timestamp: Date.now() });\n }\n\n // ===== Private Methods =====\n\n private async _runSetup(setup: SetupFunction, autoplay: boolean): Promise<void> {\n try {\n // Create context for user's setup\n const context = this._createContext();\n\n // Run user's setup\n const cleanup = await setup(context);\n if (typeof cleanup === 'function') {\n this._userCleanup = cleanup;\n }\n\n this._isReady = true;\n this._events.emit({ type: 'ready', timestamp: Date.now() });\n\n // Autoplay if enabled\n if (autoplay) {\n this.play();\n }\n } catch (error) {\n console.error('[Experience] Setup error:', error);\n this._events.emit<ErrorEvent>({\n type: 'error',\n timestamp: Date.now(),\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n }\n\n private _createContext(): ExperienceContext {\n return {\n mount: this._mount,\n params: this._paramStore.getProxy(),\n exports: this._createExportsApi(),\n environment: this._createEnvironmentApi(),\n registerObject: (name, object, metadata) =>\n this._objects.register(name, object, metadata),\n findObjectByName: (name) => this._objects.findByName(name),\n experience: this,\n };\n }\n\n private _createExportsApi(): ExportsApi {\n return {\n captureImage: (format) => this.captureImage(format),\n setFilename: (filename) => {\n this._filename = filename;\n },\n registerCaptureHandler: (handler) => {\n this._captureHandler = handler;\n },\n };\n }\n\n private _createEnvironmentApi(): EnvironmentApi {\n return {\n window,\n document,\n onResize: (callback) => {\n const handler = () => {\n callback(this._mount.clientWidth, this._mount.clientHeight);\n };\n\n // Call immediately with current size\n handler();\n\n // Setup observer\n const ro = new ResizeObserver(handler);\n ro.observe(this._mount);\n\n const cleanup = () => ro.disconnect();\n this._cleanups.push(cleanup);\n return cleanup;\n },\n addCleanup: (cleanup) => this.addCleanup(cleanup),\n };\n }\n\n private _setupResizeObserver(): void {\n this._resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect;\n this._events.emit<ResizeEvent>({\n type: 'resize',\n timestamp: Date.now(),\n width,\n height,\n });\n }\n });\n this._resizeObserver.observe(this._mount);\n }\n\n private _tick(): void {\n if (!this._isPlaying) return;\n\n const now = performance.now();\n const deltaTime = now - this._lastFrameTime;\n const targetInterval = 1000 / this._frameRate;\n\n if (deltaTime >= targetInterval) {\n this._currentFrame++;\n this._lastFrameTime = now - (deltaTime % targetInterval);\n\n this._events.emit<FrameEvent>({\n type: 'frame',\n timestamp: Date.now(),\n frame: this._currentFrame,\n deltaTime,\n });\n }\n\n this._animationFrameId = requestAnimationFrame(() => this._tick());\n }\n}\n",
11
- "export interface ResolvedContainer {\n element: HTMLElement;\n createdInternally: boolean;\n}\n\nexport interface ResolveContainerOptions {\n target?: HTMLElement | string | null;\n containerClassName?: string;\n documentRef?: Document;\n}\n\nexport function resolveContainer(options: ResolveContainerOptions = {}): ResolvedContainer {\n const doc = options.documentRef ?? document;\n if (!doc) {\n throw new Error('[hyper-frame] document is not available');\n }\n\n const className = options.containerClassName || 'hyper-frame';\n const target = options.target;\n\n if (target instanceof HTMLElement) {\n target.classList.add(className);\n return { element: target, createdInternally: false };\n }\n\n if (typeof target === 'string' && target.trim().length > 0) {\n const node = doc.querySelector<HTMLElement>(target);\n if (node) {\n node.classList.add(className);\n return { element: node, createdInternally: false };\n }\n console.warn(`[hyper-frame] Could not find container for selector \"${target}\", creating one instead.`);\n }\n\n const container = doc.createElement('div');\n container.classList.add(className);\n container.classList.add('hyper-frame-container');\n doc.body.appendChild(container);\n return { element: container, createdInternally: true };\n}\n",
12
- "import React, { useState, useCallback } from 'react';\nimport { ControlsPanel } from './components/ControlsPanel';\nimport { ExportWidget } from './components/ExportWidget';\nimport { SandboxContainer } from './components/SandboxContainer';\nimport { CanvasSizeWidget } from './components/CanvasSizeWidget';\nimport { CanvasProvider } from './context/CanvasContext';\nimport type { WrapperAppProps } from './types';\nimport './styles/controls.css';\nimport './styles/wrapper-app.css';\n\n/**\n * WrapperApp - Main React app that wraps the sandbox\n *\n * This is the root component that manages the layout of the entire frame:\n * - CanvasProvider (context for canvas sizing)\n * - ExportWidget (UI + logic for capture/recording)\n * - CanvasSizeWidget (Canvas resize controls)\n * - Sandbox container (where user code renders, sized by CanvasContext)\n * - Controls panel (Tweakpane)\n */\nexport const WrapperApp: React.FC<WrapperAppProps> = ({\n onContainerReady,\n controls,\n exportWidget,\n}) => {\n const [container, setContainer] = useState<HTMLElement | null>(null);\n\n const handleContainerReady = useCallback((node: HTMLElement) => {\n setContainer(node);\n onContainerReady(node);\n }, [onContainerReady]);\n\n return (\n <CanvasProvider>\n <div className=\"hyper-container flex flex-col items-center justify-center\">\n {/* Export widget - handles UI + logic for capture/recording */}\n {exportWidget && exportWidget.enabled && (\n <ExportWidget\n getContainer={() => container}\n filename={exportWidget.filename}\n useCanvasCapture={exportWidget.useCanvasCapture}\n />\n )}\n\n {/* Canvas size controls */}\n <CanvasSizeWidget />\n\n {/* Main sandbox container - sized by CanvasContext */}\n <SandboxContainer onReady={handleContainerReady} />\n\n {/* Controls panel (if configured) */}\n {controls && (\n <ControlsPanel\n definitions={controls.definitions}\n options={controls.options}\n onChange={controls.onChange}\n onReady={controls.onReady}\n />\n )}\n </div>\n </CanvasProvider>\n );\n};\n",
13
- "import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ControlType } from '../../types';\nimport type { ControlsPanelProps } from '../types';\n\n/**\n * ControlsPanel - React wrapper for Tweakpane controls\n *\n * This component creates a container for the existing HypertoolControls\n * (Tweakpane) to mount into. It manages the lifecycle of the controls\n * and forwards all changes to the parent component.\n */\nexport const ControlsPanel: React.FC<ControlsPanelProps> = ({\n definitions,\n options,\n onChange,\n onReady,\n}) => {\n const panelRef = useRef<HTMLDivElement>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const controlsRef = useRef<any>(null);\n const onReadyRef = useRef(onReady);\n const [showMenu, setShowMenu] = useState(false);\n const [isAdding, setIsAdding] = useState(false);\n const [needsScroll, setNeedsScroll] = useState(false);\n\n const controlOptions = useMemo(() => {\n const defaults: Array<{ type: ControlType; label: string; description: string }> = [\n { type: 'number', label: 'Number', description: 'Slider with min/max/step' },\n { type: 'color', label: 'Color', description: 'Color picker' },\n { type: 'boolean', label: 'Toggle', description: 'On/off switch' },\n { type: 'string', label: 'Text', description: 'Single-line string' },\n { type: 'text', label: 'Textarea', description: 'Multiline string' },\n { type: 'select', label: 'Select', description: 'Dropdown options' },\n { type: 'point2d', label: 'Point 2D', description: 'Vector {x,y}' },\n { type: 'point3d', label: 'Point 3D', description: 'Vector {x,y,z}' },\n { type: 'file', label: 'File', description: 'Upload image/audio/etc' },\n ];\n const allowed = options?.controlTypes;\n if (!allowed || allowed.length === 0) return defaults;\n return defaults.filter((item) => allowed.includes(item.type));\n }, [options?.controlTypes]);\n\n const closeMenu = useCallback(() => setShowMenu(false), []);\n\n const recomputeScroll = useCallback(() => {\n const panelEl = panelRef.current;\n const scrollEl = scrollRef.current;\n if (!panelEl || !scrollEl) return;\n\n const panelRect = panelEl.getBoundingClientRect();\n const available = window.innerHeight - panelRect.top - 12; // mirror top offset\n const contentHeight = scrollEl.scrollHeight;\n\n setNeedsScroll(contentHeight > available);\n }, []);\n\n useEffect(() => {\n const handler = (event: MouseEvent) => {\n if (!(event.target instanceof HTMLElement)) return;\n if (!event.target.closest('.hyper-frame-controls-panel')) {\n closeMenu();\n }\n };\n if (showMenu) {\n document.addEventListener('click', handler);\n }\n return () => {\n document.removeEventListener('click', handler);\n };\n }, [showMenu, closeMenu]);\n\n useEffect(() => {\n recomputeScroll();\n }, [showMenu, recomputeScroll, controlOptions.length]);\n\n useEffect(() => {\n const onResize = () => recomputeScroll();\n window.addEventListener('resize', onResize);\n return () => window.removeEventListener('resize', onResize);\n }, [recomputeScroll]);\n\n const buildSuggestedName = useCallback((type: ControlType) => {\n const suffix = Math.random().toString(36).slice(2, 6);\n return `${type}-control-${suffix}`;\n }, []);\n\n const buildPrompt = useCallback((type: ControlType, name: string) => {\n return [\n `Add a new ${type} control named \"${name}\" to the existing controls definitions.`,\n `Do NOT regenerate files; only patch the controls definitions object.`,\n `Use sensible defaults for ${type} (e.g., 0/1 for numbers, \"#00ff88\" for colors).`,\n `Return a search-replace JSON patch that only touches the controls definitions section.`,\n `Keep all other code intact.`,\n ].join(' ');\n }, []);\n\n const emitAddControlRequest = useCallback(\n (type: ControlType) => {\n const name = buildSuggestedName(type);\n const prompt = buildPrompt(type, name);\n const detail = {\n source: 'hypertool-controls',\n type: 'ADD_CONTROL_REQUEST' as const,\n controlType: type,\n name,\n prompt,\n timestamp: Date.now(),\n };\n\n // Notify host apps via optional callback\n if (options?.onAddControlRequest) {\n }\n options?.onAddControlRequest?.({ type, name, prompt });\n\n // Dispatch DOM event for same-frame listeners\n window.dispatchEvent(new CustomEvent('hypertool:add-control-request', { detail }));\n\n // Bubble to parent frame (e.g., Studio host)\n if (window.parent && window.parent !== window) {\n window.parent.postMessage(detail, '*');\n }\n },\n [buildPrompt, buildSuggestedName, options]\n );\n\n // Update the ref when onReady changes\n useEffect(() => {\n onReadyRef.current = onReady;\n }, [onReady]);\n\n useEffect(() => {\n const handleStatus = (event: Event) => {\n const custom = event as CustomEvent;\n if (!custom.detail || typeof custom.detail.loading !== 'boolean') return;\n setIsAdding(Boolean(custom.detail.loading));\n };\n window.addEventListener('hypertool:add-control-status', handleStatus as EventListener);\n return () => {\n window.removeEventListener('hypertool:add-control-status', handleStatus as EventListener);\n };\n }, []);\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n const handleAddClick = () => recomputeScroll();\n const handleResize = () => recomputeScroll();\n let addBtn: HTMLButtonElement | null = null;\n\n // Access the global hypertoolControls API\n const hyperWindow = window as any;\n if (!hyperWindow.hypertoolControls) {\n console.warn('[ControlsPanel] hypertoolControls not available on window');\n return;\n }\n\n // Create the control panel\n try {\n const controls = hyperWindow.hypertoolControls.createControlPanel(definitions, {\n title: options?.title,\n position: options?.position,\n expanded: options?.expanded,\n container: containerRef.current,\n onChange: (params: Record<string, any>, context: any) => {\n if (onChange) {\n onChange({\n key: context.key,\n value: context.value,\n event: context.event,\n });\n }\n },\n });\n\n controlsRef.current = controls;\n\n addBtn = document.querySelector('.hyper-frame-controls-panel__add-btn');\n addBtn?.addEventListener('click', handleAddClick);\n window.addEventListener('resize', handleResize);\n recomputeScroll();\n\n\n // Add-control UI is rendered separately; no-op here\n\n // Notify that controls are ready with the params object\n if (onReadyRef.current) {\n onReadyRef.current(controls);\n }\n } catch (error) {\n console.error('[ControlsPanel] Failed to create controls:', error);\n }\n\n // Cleanup\n return () => {\n if (controlsRef.current) {\n if (typeof controlsRef.current.dispose === 'function') {\n controlsRef.current.dispose();\n } else if (typeof controlsRef.current.destroy === 'function') {\n controlsRef.current.destroy();\n }\n controlsRef.current = null;\n }\n addBtn?.removeEventListener('click', handleAddClick);\n window.removeEventListener('resize', handleResize);\n };\n }, [definitions, options, onChange]);\n\n return (\n <div\n className=\"hyper-frame-controls-panel\"\n ref={panelRef}\n >\n <div\n ref={scrollRef}\n className={\n needsScroll\n ? 'hyper-frame-controls-panel__scroll hyper-frame-controls-panel__scroll--overflow'\n : 'hyper-frame-controls-panel__scroll'\n }\n >\n <div ref={containerRef} className=\"hyper-frame-controls-panel__pane\" />\n {options?.showAddControlActions !== false && controlOptions.length > 0 && (\n <div className=\"hyper-frame-controls-panel__actions\">\n <button\n type=\"button\"\n className=\"hyper-frame-controls-panel__add-btn\"\n onClick={() => setShowMenu((prev) => !prev)}\n aria-expanded={showMenu}\n aria-haspopup=\"true\"\n disabled={isAdding}\n >\n {isAdding ? <span className=\"hyper-frame-controls-panel__spinner\" /> : \"+\"}\n <span>{isAdding ? \"Adding…\" : \"Add control\"}</span>\n </button>\n {showMenu && (\n <div className=\"hyper-frame-controls-panel__menu\" role=\"menu\">\n {controlOptions.map((option) => (\n <button\n key={option.type}\n className=\"hyper-frame-controls-panel__menu-item\"\n onClick={() => {\n // Optimistically show loader immediately on selection\n setIsAdding(true);\n emitAddControlRequest(option.type);\n closeMenu();\n }}\n role=\"menuitem\"\n >\n <div className=\"hyper-frame-controls-panel__menu-title\">{option.label}:&nbsp;</div>\n <div className=\"hyper-frame-controls-panel__menu-desc\">{option.description}</div>\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n );\n};\n",
14
- "import { useState, useEffect, useRef, useCallback } from 'react';\nimport { useCanvas } from '../context/CanvasContext';\n\ninterface ExportWidgetProps {\n getContainer: () => HTMLElement | null;\n filename?: string;\n useCanvasCapture?: boolean;\n}\n\n/**\n * ExportWidget - Export controls UI and logic component\n * \n * This component manages:\n * - UI: Screenshot, recording, and download buttons\n * - Logic: Capturing PNG images, recording videos, downloading files\n * - State: Canvas availability detection and all capture/recording state\n */\nexport const ExportWidget: React.FC<ExportWidgetProps> = ({\n getContainer,\n filename = 'hyperframe-export',\n useCanvasCapture = true,\n}) => {\n const { setIsRecording } = useCanvas();\n\n const [imageEnabled, setImageEnabled] = useState(false);\n const [videoEnabled, setVideoEnabled] = useState(false);\n const [recording, setRecording] = useState(false);\n const recorderRef = useRef<MediaRecorder | null>(null);\n const recordedChunksRef = useRef<Blob[]>([]);\n\n // Update button states based on container availability\n useEffect(() => {\n const checkAvailability = () => {\n const container = getContainer();\n if (container && useCanvasCapture) {\n const canvas = container.querySelector('canvas');\n if (canvas) {\n setImageEnabled(true);\n setVideoEnabled(true);\n return true;\n }\n }\n return false;\n };\n\n if (checkAvailability()) {\n return;\n }\n\n const interval = setInterval(() => {\n if (checkAvailability()) {\n clearInterval(interval);\n }\n }, 100);\n\n return () => clearInterval(interval);\n }, [getContainer, useCanvasCapture]);\n\n // Notify parent when states change\n // useEffect(() => {\n // onImageEnabledChange(imageEnabled);\n // }, [imageEnabled, onImageEnabledChange]);\n\n // useEffect(() => {\n // onVideoEnabledChange(videoEnabled);\n // }, [videoEnabled, onVideoEnabledChange]);\n\n // useEffect(() => {\n // onRecordingChange(recording);\n // }, [recording, onRecordingChange]);\n\n const downloadBlob = useCallback((blob: Blob, filename: string) => {\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = filename;\n anchor.rel = 'noopener';\n anchor.style.display = 'none';\n document.body.appendChild(anchor);\n anchor.click();\n document.body.removeChild(anchor);\n URL.revokeObjectURL(url);\n }, []);\n\n\n const handleCapturePNG = useCallback(async () => {\n try {\n const container = getContainer();\n if (!container) {\n throw new Error('Container not available.');\n }\n\n const canvas = container.querySelector('canvas');\n if (!canvas || !(canvas instanceof HTMLCanvasElement)) {\n throw new Error('No canvas element available for capture.');\n }\n\n const blob = await new Promise<Blob | null>((resolve, reject) => {\n canvas.toBlob((blob) => {\n if (blob) {\n resolve(blob);\n } else {\n reject(new Error('Canvas capture returned an empty blob.'));\n }\n });\n });\n\n if (blob) {\n downloadBlob(blob, `${filename}.png`);\n console.log('PNG captured');\n }\n } catch (error) {\n console.error('[ExportWidget] Failed to capture image:', error);\n }\n }, [getContainer, filename, downloadBlob]);\n\n const stopRecording = useCallback(() => {\n if (!recorderRef.current) {\n console.warn('[ExportWidget] No active recorder to stop');\n return;\n }\n\n console.log('Stopping recording');\n recorderRef.current.stop();\n }, []);\n\n const startRecording = useCallback(async () => {\n try {\n const container = getContainer();\n if (!container) {\n throw new Error('Container not available.');\n }\n\n const canvas = container.querySelector('canvas');\n if (!canvas || !(canvas instanceof HTMLCanvasElement)) {\n throw new Error('No canvas element available for recording.');\n }\n\n if (typeof canvas.captureStream !== 'function') {\n throw new Error('Canvas captureStream API is not supported in this browser.');\n }\n\n const stream = canvas.captureStream(60);\n\n const formats = [\n { mimeType: 'video/mp4;codecs=avc1', extension: 'mp4' },\n { mimeType: 'video/mp4;codecs=h264', extension: 'mp4' },\n { mimeType: 'video/mp4;codecs=avc1.42E01E', extension: 'mp4' },\n { mimeType: 'video/mp4', extension: 'mp4' },\n { mimeType: 'video/webm;codecs=h264', extension: 'webm' },\n { mimeType: 'video/webm;codecs=vp9', extension: 'webm' },\n { mimeType: 'video/webm;codecs=vp8', extension: 'webm' },\n { mimeType: 'video/webm', extension: 'webm' },\n ];\n\n let format = formats.find(f => MediaRecorder.isTypeSupported(f.mimeType));\n\n if (!format) {\n format = { mimeType: '', extension: 'webm' };\n }\n\n console.log('[ExportWidget] Using video format:', format.mimeType || 'browser default');\n\n const recorderOptions: MediaRecorderOptions = {\n videoBitsPerSecond: 5_000_000,\n };\n\n if (format.mimeType) {\n recorderOptions.mimeType = format.mimeType;\n }\n\n const recorder = new MediaRecorder(stream, recorderOptions);\n const chunks: Blob[] = [];\n recordedChunksRef.current = chunks;\n\n recorder.addEventListener('dataavailable', (event) => {\n if (event.data?.size) {\n chunks.push(event.data);\n }\n });\n\n recorder.addEventListener('stop', () => {\n const mimeType = format.mimeType || recorder.mimeType || 'video/webm';\n const blob = new Blob(chunks, { type: mimeType });\n\n console.log('[ExportWidget] Recording complete:', {\n size: blob.size,\n type: blob.type,\n chunks: chunks.length,\n });\n\n downloadBlob(blob, `${filename}.${format.extension}`);\n stream.getTracks().forEach((track) => track.stop());\n setRecording(false);\n setIsRecording(false);\n recorderRef.current = null;\n recordedChunksRef.current = [];\n });\n\n recorder.start();\n recorderRef.current = recorder;\n setRecording(true);\n setIsRecording(true);\n console.log('Recording started');\n } catch (error) {\n console.error('[ExportWidget] Failed to start recording:', error);\n setRecording(false);\n setIsRecording(false);\n recorderRef.current = null;\n }\n }, [getContainer, filename, downloadBlob, setIsRecording]);\n\n const handleToggleRecording = useCallback(async () => {\n if (recording) {\n stopRecording();\n } else {\n await startRecording();\n }\n }, [recording, stopRecording, startRecording]);\n\n return (\n <div className=\"export-widget-container absolute top-0 left-0 py-2 px-2 z-[9999]\"\n >\n <div className=\"flex items-center gap-2\">\n {/* Export buttons */}\n <button\n type=\"button\"\n className={`inline-flex items-center gap-2 rounded-lg border border-border bg-background px-2 py-1 text-sm text-text transition hover:bg-muted/80 whitespace-nowrap ${\n !imageEnabled ? 'opacity-60 cursor-not-allowed' : ''\n }`}\n onClick={handleCapturePNG}\n disabled={!imageEnabled}\n title=\"Screenshot\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z\"></path>\n <circle cx=\"12\" cy=\"13\" r=\"3\"></circle>\n </svg>\n <span>Screenshot</span>\n </button>\n <button\n type=\"button\"\n className={`inline-flex items-center gap-2 rounded-lg border transition hover:bg-muted/80 whitespace-nowrap px-2 py-1 text-sm ${\n recording\n ? 'bg-red-500/20 text-red-400 border-red-500/30'\n : 'bg-background text-text border-border'\n } ${!videoEnabled ? 'opacity-60 cursor-not-allowed' : ''}`}\n onClick={handleToggleRecording}\n disabled={!videoEnabled}\n title={recording ? 'Stop Recording' : 'Record Video'}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m22 8-6 4 6 4V8Z\"></path>\n <rect x=\"2\" y=\"6\" width=\"14\" height=\"12\" rx=\"2\" ry=\"2\"></rect>\n </svg>\n <span>{recording ? 'Stop' : 'Rec'}</span>\n </button>\n </div>\n </div>\n );\n};\n\n",
15
- "import React, { createContext, useContext, useState, useEffect, useCallback, ReactNode, useMemo } from 'react';\n\ninterface CanvasContextValue {\n // Canvas dimensions (actual render size the user wants)\n canvasWidth: number;\n canvasHeight: number;\n \n // Maximum constraints based on viewport\n maxCanvasWidth: number;\n maxCanvasHeight: number;\n \n // Scale factor (how much the canvas is scaled to fit viewport if too large)\n scale: number;\n \n isFittedToScreen: boolean;\n \n // Recording state\n isRecording: boolean;\n setIsRecording: (recording: boolean) => void;\n \n // Canvas size setters\n setCanvasWidth: (width: number) => void;\n setCanvasHeight: (height: number) => void;\n setCanvasSize: (width: number, height: number) => void;\n \n // Set aspect ratio and maximize to container\n setAspectRatio: (aspectWidth: number, aspectHeight: number) => void;\n \n // Sync with actual canvas element dimensions\n syncWithCanvas: (canvasElement: HTMLCanvasElement) => void;\n \n fitToScreen: () => void;\n}\n\nconst CanvasContext = createContext<CanvasContextValue | null>(null);\n\ninterface CanvasProviderProps {\n children: ReactNode;\n}\n\n// Calculate available viewport space\nconst calculateAvailableSpace = () => {\n const availableWidth = window.innerWidth;\n const availableHeight = window.innerHeight;\n \n return {\n width: Math.max(100, Math.round(availableWidth)),\n height: Math.max(100, Math.round(availableHeight))\n };\n};\n\n/**\n * CanvasProvider - Manages canvas/container sizing state with scaling support\n * \n * Features:\n * - Canvas size: The actual render dimensions (can be larger than viewport)\n * - Auto-scaling: Canvas is scaled down to fit viewport if too large\n * - Display container matches the scaled canvas size\n */\nexport const CanvasProvider: React.FC<CanvasProviderProps> = ({ children }) => {\n const initialDimensions = useMemo(() => {\n const space = calculateAvailableSpace();\n const dpr = window.devicePixelRatio || 1;\n const maxWidth = Math.round(space.width * dpr);\n const maxHeight = Math.round(space.height * dpr);\n return {\n canvasWidth: Math.max(100, Math.round(maxWidth * 0.9)),\n canvasHeight: Math.max(100, Math.round(maxHeight * 0.9)),\n maxWidth,\n maxHeight,\n };\n }, []);\n \n // Canvas dimensions (actual render size)\n const [canvasWidth, setCanvasWidthState] = useState(initialDimensions.canvasWidth);\n const [canvasHeight, setCanvasHeightState] = useState(initialDimensions.canvasHeight);\n \n // Maximum constraints based on viewport\n const [maxCanvasWidth, setMaxCanvasWidth] = useState(initialDimensions.maxWidth);\n const [maxCanvasHeight, setMaxCanvasHeight] = useState(initialDimensions.maxHeight);\n \n const [isFittedToScreen, setIsFittedToScreen] = useState(false);\n \n // Recording state - blocks canvas resizing when true\n const [isRecording, setIsRecording] = useState(false);\n \n // Track aspect ratio to maintain it on resize (null = free form)\n const [aspectRatio, setAspectRatioState] = useState<number | null>(null);\n \n // Remember previous state before fitting to screen\n const [previousState, setPreviousState] = useState<{ width: number; height: number } | null>(null);\n\n // Calculate scale factor - scale down if canvas is larger than viewport\n const scale = useMemo(() => {\n const dpr = window.devicePixelRatio || 1;\n const displayCanvasWidth = canvasWidth / dpr;\n const displayCanvasHeight = canvasHeight / dpr;\n\n if (displayCanvasWidth === 0 || displayCanvasHeight === 0) {\n return 1;\n }\n\n const availableWidth = maxCanvasWidth / dpr;\n const availableHeight = maxCanvasHeight / dpr;\n\n const scaleX = availableWidth / displayCanvasWidth;\n const scaleY = availableHeight / displayCanvasHeight;\n return Math.min(scaleX, scaleY, 1); // Never scale up, only down\n }, [canvasWidth, canvasHeight, maxCanvasWidth, maxCanvasHeight]);\n\n // Handle window resize - update max constraints\n useEffect(() => {\n const handleResize = () => {\n const space = calculateAvailableSpace();\n const dpr = window.devicePixelRatio || 1;\n const newMaxWidth = Math.round(space.width * dpr);\n const newMaxHeight = Math.round(space.height * dpr);\n \n setMaxCanvasWidth(newMaxWidth);\n setMaxCanvasHeight(newMaxHeight);\n \n // If fitted to screen, update canvas dimensions\n if (isFittedToScreen) {\n setCanvasWidthState(newMaxWidth);\n setCanvasHeightState(newMaxHeight);\n }\n // If aspect ratio is set, recalculate dimensions to maintain ratio\n else if (aspectRatio !== null) {\n let newWidth: number;\n let newHeight: number;\n \n if (newMaxWidth / newMaxHeight > aspectRatio) {\n // Container is wider than aspect ratio - constrain by height\n newHeight = newMaxHeight;\n newWidth = Math.round(newHeight * aspectRatio);\n } else {\n // Container is taller than aspect ratio - constrain by width\n newWidth = newMaxWidth;\n newHeight = Math.round(newWidth / aspectRatio);\n }\n \n setCanvasWidthState(newWidth);\n setCanvasHeightState(newHeight);\n }\n };\n\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [isFittedToScreen, aspectRatio]);\n\n const setCanvasWidth = useCallback((w: number) => {\n const clampedWidth = Math.max(100, Math.round(w)); // Round to integer\n setCanvasWidthState(clampedWidth);\n setIsFittedToScreen(false);\n setAspectRatioState(null); // Clear aspect ratio when manually setting dimensions\n }, []);\n\n const setCanvasHeight = useCallback((h: number) => {\n const clampedHeight = Math.max(100, Math.round(h)); // Round to integer\n setCanvasHeightState(clampedHeight);\n setIsFittedToScreen(false);\n setAspectRatioState(null); // Clear aspect ratio when manually setting dimensions\n }, []);\n\n const setCanvasSize = useCallback((w: number, h: number) => {\n const clampedWidth = Math.max(100, Math.round(w)); // Round to integer\n const clampedHeight = Math.max(100, Math.round(h)); // Round to integer\n setCanvasWidthState(clampedWidth);\n setCanvasHeightState(clampedHeight);\n setIsFittedToScreen(false);\n setAspectRatioState(null); // Clear aspect ratio when manually setting dimensions\n }, []);\n\n const setAspectRatio = useCallback((aspectWidth: number, aspectHeight: number) => {\n const space = calculateAvailableSpace();\n const dpr = window.devicePixelRatio || 1;\n \n // Calculate maximum size that fits in viewport with given aspect ratio\n const ratio = aspectWidth / aspectHeight;\n const maxWidth = Math.round(space.width * dpr);\n const maxHeight = Math.round(space.height * dpr);\n \n let newWidth: number;\n let newHeight: number;\n \n // Fit to container while maintaining aspect ratio\n if (maxWidth / maxHeight > ratio) {\n // Container is wider than aspect ratio - constrain by height\n newHeight = maxHeight;\n newWidth = Math.round(newHeight * ratio);\n } else {\n // Container is taller than aspect ratio - constrain by width\n newWidth = maxWidth;\n newHeight = Math.round(newWidth / ratio);\n }\n \n setCanvasWidthState(newWidth);\n setCanvasHeightState(newHeight);\n setAspectRatioState(ratio); // Store ratio for window resize\n setIsFittedToScreen(false);\n }, []);\n\n const syncWithCanvas = useCallback((canvasElement: HTMLCanvasElement) => {\n // Read actual canvas dimensions (including devicePixelRatio)\n const actualWidth = canvasElement.width;\n const actualHeight = canvasElement.height;\n \n if (actualWidth > 0 && actualHeight > 0) {\n console.log('[CanvasContext] Syncing with actual canvas:', { \n actual: { width: actualWidth, height: actualHeight },\n current: { width: canvasWidth, height: canvasHeight }\n });\n \n setCanvasWidthState(actualWidth);\n setCanvasHeightState(actualHeight);\n setIsFittedToScreen(false);\n setAspectRatioState(null); // Clear aspect ratio when syncing\n }\n }, [canvasWidth, canvasHeight]);\n\n const fitToScreen = useCallback(() => {\n if (isFittedToScreen && previousState) {\n // Toggle back to previous state\n setCanvasWidthState(previousState.width);\n setCanvasHeightState(previousState.height);\n setIsFittedToScreen(false);\n setPreviousState(null);\n } else {\n // Save current state and fit to screen\n setPreviousState({ width: canvasWidth, height: canvasHeight });\n const space = calculateAvailableSpace();\n const dpr = window.devicePixelRatio || 1;\n const newWidth = Math.round(space.width * dpr);\n const newHeight = Math.round(space.height * dpr);\n setCanvasWidthState(newWidth);\n setCanvasHeightState(newHeight);\n setAspectRatioState(null); // Clear aspect ratio when fitting to screen\n setIsFittedToScreen(true);\n }\n }, [isFittedToScreen, previousState, canvasWidth, canvasHeight]);\n\n const value: CanvasContextValue = {\n canvasWidth,\n canvasHeight,\n maxCanvasWidth,\n maxCanvasHeight,\n scale,\n isFittedToScreen,\n isRecording,\n setIsRecording,\n setCanvasWidth,\n setCanvasHeight,\n setCanvasSize,\n setAspectRatio,\n syncWithCanvas,\n fitToScreen,\n };\n\n return <CanvasContext.Provider value={value}>{children}</CanvasContext.Provider>;\n};\n\n/**\n * useCanvas - Hook to access canvas context\n * \n * @throws Error if used outside CanvasProvider\n */\nexport const useCanvas = (): CanvasContextValue => {\n const context = useContext(CanvasContext);\n if (!context) {\n throw new Error('useCanvas must be used within a CanvasProvider');\n }\n return context;\n};\n",
16
- "import React, { useRef, useEffect, useState } from 'react';\nimport { useCanvas } from '../context/CanvasContext';\nimport { ResizeHandles } from './ResizeHandles';\nimport type { SandboxContainerProps } from '../types';\n\n/**\n * SandboxContainer - Container for the user's canvas/sketch with drag-resizing\n *\n * Features:\n * - Renders user code (p5.js, Three.js, etc.) at canvas size\n * - Canvas dimensions are PRECISELY set via CanvasContext (DPI-aware)\n * - Display container size is derived from canvas size ÷ DPR\n * - If canvas is larger than viewport we scale the container via CSS transforms\n * - Presets set aspect ratio and maximize to fill container\n * - Drag handles on all edges and corners for resizing\n * - Dispatches window resize events when dimensions change\n */\nexport const SandboxContainer: React.FC<SandboxContainerProps> = ({ onReady }) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const { canvasWidth, canvasHeight, scale, setCanvasSize, syncWithCanvas } = useCanvas();\n\n const [canvasSynced, setCanvasSynced] = useState(false);\n\n // Calculate physical and scaled dimensions\n const dpr = window.devicePixelRatio || 1;\n const containerWidth = Math.max(1, Math.round(canvasWidth / dpr));\n const containerHeight = Math.max(1, Math.round(canvasHeight / dpr));\n const scaledWidth = Math.max(1, Math.round(containerWidth * scale));\n const scaledHeight = Math.max(1, Math.round(containerHeight * scale));\n\n useEffect(() => {\n if (containerRef.current) {\n onReady(containerRef.current);\n }\n }, [onReady]);\n\n // Detect and sync with actual canvas element dimensions\n useEffect(() => {\n if (!containerRef.current || canvasSynced) return;\n\n const checkCanvas = () => {\n const canvas = containerRef.current?.querySelector('canvas');\n if (canvas && canvas instanceof HTMLCanvasElement) {\n const actualWidth = canvas.width;\n const actualHeight = canvas.height;\n \n // Only sync if canvas has meaningful dimensions and differs from current\n if (actualWidth > 100 && actualHeight > 100) {\n const widthDiff = Math.abs(actualWidth - canvasWidth);\n const heightDiff = Math.abs(actualHeight - canvasHeight);\n \n // Sync if there's a significant difference (more than 10%)\n if (widthDiff > canvasWidth * 0.1 || heightDiff > canvasHeight * 0.1) {\n console.log('[SandboxContainer] Canvas detected, syncing dimensions');\n syncWithCanvas(canvas);\n setCanvasSynced(true);\n }\n }\n }\n };\n\n // Check immediately\n checkCanvas();\n\n // Also check periodically for up to 3 seconds\n const interval = setInterval(checkCanvas, 100);\n const timeout = setTimeout(() => {\n clearInterval(interval);\n setCanvasSynced(true); // Stop trying after 3 seconds\n }, 3000);\n\n return () => {\n clearInterval(interval);\n clearTimeout(timeout);\n };\n }, [containerRef, canvasWidth, canvasHeight, canvasSynced, syncWithCanvas]);\n\n // Dispatch window resize event when canvas dimensions or scale change\n useEffect(() => {\n const resizeEvent = new Event('resize');\n window.dispatchEvent(resizeEvent);\n \n console.log('[SandboxContainer] Dispatched resize event:', { \n canvas: { width: canvasWidth, height: canvasHeight },\n container: { width: containerWidth, height: containerHeight },\n display: { width: scaledWidth, height: scaledHeight },\n scale \n });\n }, [canvasWidth, canvasHeight, containerWidth, containerHeight, scaledWidth, scaledHeight, scale]);\n\n return (\n <div className=\"hyper-frame-sandbox-wrapper absolute inset-0 flex items-center justify-center pointer-events-none\">\n <div\n ref={wrapperRef}\n className=\"hyper-frame-sandbox-display-container relative pointer-events-auto\"\n style={{\n width: `${scaledWidth}px`,\n height: `${scaledHeight}px`,\n boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',\n }}\n >\n {/* Resize Handles */}\n <ResizeHandles \n canvasWidth={canvasWidth}\n canvasHeight={canvasHeight}\n scale={scale}\n onResize={setCanvasSize}\n />\n\n {/* Canvas container - scaled to fit */}\n <div\n ref={containerRef}\n className=\"hyper-frame-sandbox-container absolute top-0 left-0 flex items-center justify-center\"\n style={{\n width: `${containerWidth}px`,\n height: `${containerHeight}px`,\n overflow: 'hidden',\n transform: `scale(${scale})`,\n transformOrigin: 'top left',\n }}\n />\n </div>\n </div>\n );\n};\n",
17
- "import React, { useState, useEffect, useCallback, useRef } from 'react';\nimport { useCanvas } from '../context/CanvasContext';\n\ntype ResizeHandle = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';\n\ninterface ResizeHandlesProps {\n canvasWidth: number;\n canvasHeight: number;\n scale: number;\n onResize: (width: number, height: number) => void;\n}\n\n/**\n * ResizeHandles - Drag handles for resizing the canvas container\n * \n * Provides 8 resize handles with complete resize logic:\n * - 4 corners: nw, ne, sw, se\n * - 4 edges: n, s, e, w\n * \n * Handles all mouse events and dimension calculations internally.\n */\nexport const ResizeHandles: React.FC<ResizeHandlesProps> = ({ \n canvasWidth, \n canvasHeight, \n scale, \n onResize \n}) => {\n const { isRecording } = useCanvas();\n const [isResizing, setIsResizing] = useState(false);\n const [resizeHandle, setResizeHandle] = useState<ResizeHandle | null>(null);\n const [startPos, setStartPos] = useState({ x: 0, y: 0 });\n const [startSize, setStartSize] = useState({ width: 0, height: 0 });\n\n const dpr = window.devicePixelRatio || 1;\n const scaleRef = useRef(scale);\n const MIN_SIZE = 1;\n\n useEffect(() => {\n scaleRef.current = scale;\n }, [scale]);\n\n const handleMouseDown = useCallback((handle: ResizeHandle, e: React.MouseEvent) => {\n if (isRecording) return; // Block resizing during recording\n \n e.preventDefault();\n e.stopPropagation();\n \n setIsResizing(true);\n setResizeHandle(handle);\n setStartPos({ x: e.clientX, y: e.clientY });\n setStartSize({ width: canvasWidth, height: canvasHeight });\n }, [canvasWidth, canvasHeight, isRecording]);\n\n useEffect(() => {\n if (!isResizing || !resizeHandle) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n const deltaX = e.clientX - startPos.x;\n const deltaY = e.clientY - startPos.y;\n const currentScale = scaleRef.current || 1;\n const isCorner = resizeHandle.length === 2;\n const isHorizontalEdge = resizeHandle === 'e' || resizeHandle === 'w';\n const isVerticalEdge = resizeHandle === 'n' || resizeHandle === 's';\n\n let newWidth = startSize.width;\n let newHeight = startSize.height;\n\n const widthDelta =\n resizeHandle.includes('e')\n ? (deltaX * dpr) / currentScale\n : resizeHandle.includes('w')\n ? (-deltaX * dpr) / currentScale\n : 0;\n\n const heightDelta =\n resizeHandle.includes('s')\n ? (deltaY * dpr) / currentScale\n : resizeHandle.includes('n')\n ? (-deltaY * dpr) / currentScale\n : 0;\n\n newWidth = startSize.width + widthDelta;\n newHeight = startSize.height + heightDelta;\n\n if (e.shiftKey) {\n const baseWidth = Math.max(MIN_SIZE, startSize.width);\n const baseHeight = Math.max(MIN_SIZE, startSize.height);\n const normalizedWidthDelta = widthDelta / baseWidth;\n const normalizedHeightDelta = heightDelta / baseHeight;\n const clampScaleFactor = (scaleFactor: number, base: number) => {\n if (!Number.isFinite(scaleFactor) || scaleFactor <= 0) {\n return MIN_SIZE / base;\n }\n return scaleFactor;\n };\n\n if (isHorizontalEdge && !isVerticalEdge) {\n const scaleFactor = clampScaleFactor(1 + normalizedWidthDelta, baseWidth);\n newWidth = baseWidth * scaleFactor;\n newHeight = baseHeight * scaleFactor;\n } else if (isVerticalEdge && !isHorizontalEdge) {\n const scaleFactor = clampScaleFactor(1 + normalizedHeightDelta, baseHeight);\n newWidth = baseWidth * scaleFactor;\n newHeight = baseHeight * scaleFactor;\n } else if (isCorner) {\n const widthDominant = Math.abs(normalizedWidthDelta) >= Math.abs(normalizedHeightDelta);\n const dominantDelta = widthDominant ? normalizedWidthDelta : normalizedHeightDelta;\n const baseForMin = widthDominant ? baseWidth : baseHeight;\n const scaleFactor = clampScaleFactor(1 + dominantDelta, baseForMin);\n newWidth = baseWidth * scaleFactor;\n newHeight = baseHeight * scaleFactor;\n }\n }\n\n newWidth = Math.max(MIN_SIZE, newWidth);\n newHeight = Math.max(MIN_SIZE, newHeight);\n\n onResize(newWidth, newHeight);\n };\n\n const handleMouseUp = () => {\n setIsResizing(false);\n setResizeHandle(null);\n };\n\n const handleMouseLeave = () => {\n setIsResizing(false);\n setResizeHandle(null);\n };\n\n document.addEventListener('mousemove', handleMouseMove);\n document.addEventListener('mouseup', handleMouseUp);\n document.addEventListener('mouseleave', handleMouseLeave);\n\n return () => {\n document.removeEventListener('mousemove', handleMouseMove);\n document.removeEventListener('mouseup', handleMouseUp);\n document.removeEventListener('mouseleave', handleMouseLeave);\n };\n }, [isResizing, resizeHandle, startPos, startSize, dpr, onResize]);\n\n // Individual resize handle component\n const ResizeHandleComponent = ({ \n handle, \n className \n }: { \n handle: ResizeHandle; \n className: string;\n }) => (\n <div\n className={`absolute ${className} group ${isRecording ? 'cursor-not-allowed opacity-0' : ''}`}\n onMouseDown={(e) => handleMouseDown(handle, e)}\n style={{ zIndex: 10 }}\n title={isRecording ? 'Canvas resizing is locked during recording' : undefined}\n >\n <div className={`w-full h-full transition-opacity bg-accent/20 ${isRecording ? 'opacity-0' : 'opacity-0 group-hover:opacity-100'}`} />\n </div>\n );\n\n return (\n <>\n {/* Corners */}\n <ResizeHandleComponent \n handle=\"nw\" \n className=\"top-0 left-0 w-3 h-3 cursor-nw-resize\" \n />\n <ResizeHandleComponent \n handle=\"ne\" \n className=\"top-0 right-0 w-3 h-3 cursor-ne-resize\" \n />\n <ResizeHandleComponent \n handle=\"sw\" \n className=\"bottom-0 left-0 w-3 h-3 cursor-sw-resize\" \n />\n <ResizeHandleComponent \n handle=\"se\" \n className=\"bottom-0 right-0 w-3 h-3 cursor-se-resize\" \n />\n \n {/* Edges */}\n <ResizeHandleComponent \n handle=\"n\" \n className=\"top-0 left-3 right-3 h-1 cursor-n-resize\" \n />\n <ResizeHandleComponent \n handle=\"s\" \n className=\"bottom-0 left-3 right-3 h-1 cursor-s-resize\" \n />\n <ResizeHandleComponent \n handle=\"w\" \n className=\"left-0 top-3 bottom-3 w-1 cursor-w-resize\" \n />\n <ResizeHandleComponent \n handle=\"e\" \n className=\"right-0 top-3 bottom-3 w-1 cursor-e-resize\" \n />\n </>\n );\n};\n\n",
18
- "import React, { useState, useEffect } from 'react';\nimport { useCanvas } from '../context/CanvasContext';\n\n// Standard screen presets\nconst PRESETS = [\n { label: '16:9 Landscape', width: 1920, height: 1080 },\n { label: '9:16 Portrait', width: 1080, height: 1920 },\n { label: '4:3 Standard', width: 1024, height: 768 },\n { label: '1:1 Square', width: 1080, height: 1080 },\n { label: '21:9 Ultrawide', width: 2560, height: 1080 },\n { label: '3:2 Classic', width: 1440, height: 960 },\n { label: '---', width: 0, height: 0 }, // Divider\n { label: 'iPhone 15 Pro', width: 1179, height: 2556 },\n { label: 'iPhone 15 Pro Max', width: 1290, height: 2796 },\n { label: 'iPhone SE', width: 750, height: 1334 },\n { label: 'iPhone 15', width: 1170, height: 2532 },\n { label: '---', width: 0, height: 0 }, // Divider\n { label: 'MacBook Air 13\"', width: 2560, height: 1664 },\n { label: 'MacBook Pro 14\"', width: 3024, height: 1964 },\n { label: 'MacBook Pro 16\"', width: 3456, height: 2234 },\n { label: 'iMac 24\"', width: 4480, height: 2520 },\n { label: 'Studio Display', width: 5120, height: 2880 },\n];\n\n/**\n * CanvasSizeWidget - Canvas size control UI\n * \n * Displays and manages:\n * - Width input (updates on Enter or blur)\n * - Height input (updates on Enter or blur)\n * - Preset aspect ratios dropdown (maximizes to container with chosen ratio)\n * - Scale indicator (shows current zoom level)\n * - Fit to screen button\n * \n * Presets set aspect ratio only - canvas size always maximizes to fill container.\n * Manual width/height inputs allow free-form sizing.\n * All state and logic come from CanvasContext.\n */\nexport const CanvasSizeWidget: React.FC = () => {\n const { \n canvasWidth, \n canvasHeight, \n scale,\n isRecording,\n setCanvasWidth, \n setCanvasHeight,\n setAspectRatio,\n fitToScreen \n } = useCanvas();\n \n // Local state for inputs\n const [widthInput, setWidthInput] = useState(canvasWidth.toString());\n const [heightInput, setHeightInput] = useState(canvasHeight.toString());\n\n // Sync local state when canvas context changes externally\n useEffect(() => {\n setWidthInput(canvasWidth.toString());\n }, [canvasWidth]);\n\n useEffect(() => {\n setHeightInput(canvasHeight.toString());\n }, [canvasHeight]);\n\n const applyWidth = () => {\n if (isRecording) return; // Block resizing during recording\n const value = Math.round(parseFloat(widthInput)); // Round to integer\n if (!isNaN(value) && value >= 100) {\n setCanvasWidth(value);\n setWidthInput(value.toString()); // Update input to show rounded value\n } else {\n // Reset to current value if invalid\n setWidthInput(canvasWidth.toString());\n }\n };\n\n const applyHeight = () => {\n if (isRecording) return; // Block resizing during recording\n const value = Math.round(parseFloat(heightInput)); // Round to integer\n if (!isNaN(value) && value >= 100) {\n setCanvasHeight(value);\n setHeightInput(value.toString()); // Update input to show rounded value\n } else {\n // Reset to current value if invalid\n setHeightInput(canvasHeight.toString());\n }\n };\n\n const handleWidthKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n applyWidth();\n e.currentTarget.blur();\n }\n };\n\n const handleHeightKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n applyHeight();\n e.currentTarget.blur();\n }\n };\n\n const handlePresetChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\n if (isRecording) return; // Block resizing during recording\n const preset = PRESETS.find(p => p.label === e.target.value);\n if (preset && preset.width > 0 && preset.height > 0) {\n // Set aspect ratio - canvas will maximize to container with this ratio\n setAspectRatio(preset.width, preset.height);\n }\n };\n\n // Calculate display dimensions (what's actually shown on screen)\n const dpr = window.devicePixelRatio || 1;\n const displayWidth = Math.round((canvasWidth / dpr) * scale);\n const displayHeight = Math.round((canvasHeight / dpr) * scale);\n \n // Show comparison: canvas size vs display size\n const canvasSize = `${canvasWidth}×${canvasHeight}`;\n const displaySize = `${displayWidth}×${displayHeight}`;\n const isScaled = scale < 1;\n const scalePercent = Math.round(scale * 100);\n\n return (\n <div className=\"canvas-size-widget-container absolute top-0 center px-2 py-2 z-[9999] flex items-center gap-2\">\n {/* Presets Dropdown */}\n <select\n onChange={handlePresetChange}\n className={`rounded border border-border w-[90px] bg-background px-2 py-1 text-sm text-text focus:border-accent focus:outline-none ${\n isRecording ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'\n }`}\n defaultValue=\"\"\n disabled={isRecording}\n title={isRecording ? 'Canvas resizing is locked during recording' : 'Choose a preset size'}\n >\n <option value=\"\" disabled>Presets</option>\n {PRESETS.map((preset, idx) => \n preset.label === '---' ? (\n <option key={idx} disabled>────────</option>\n ) : (\n <option key={idx} value={preset.label}>\n {preset.label}\n </option>\n )\n )}\n </select>\n\n {/* Width Input */}\n <div className=\"flex items-center gap-1\">\n <label className=\"text-sm text-accent\">W:</label>\n <input\n // type=\"number\"\n value={widthInput}\n onChange={(e) => setWidthInput(e.target.value)}\n onBlur={applyWidth}\n onKeyDown={handleWidthKeyDown}\n className={`rounded border border-border bg-background px-2 py-1 text-sm text-text focus:border-accent focus:outline-none ${\n isRecording ? 'opacity-50 cursor-not-allowed' : ''\n }`}\n style={{ width: `${Math.max(widthInput.length * 8 + 16, 55)}px` }}\n min=\"60\"\n step=\"1\"\n disabled={isRecording}\n title={isRecording ? 'Canvas resizing is locked during recording' : 'Canvas width'}\n />\n </div>\n\n {/* Height Input */}\n <div className=\"flex items-center gap-1\">\n <label className=\"text-sm text-accent\">H:</label>\n <input\n // type=\"number\"\n value={heightInput}\n onChange={(e) => setHeightInput(e.target.value)}\n onBlur={applyHeight}\n onKeyDown={handleHeightKeyDown}\n className={`rounded border border-border bg-background px-2 py-1 text-sm text-text focus:border-accent focus:outline-none ${\n isRecording ? 'opacity-50 cursor-not-allowed' : ''\n }`}\n style={{ width: `${Math.max(heightInput.length * 8 + 16, 55)}px` }}\n min=\"60\"\n step=\"1\"\n disabled={isRecording}\n title={isRecording ? 'Canvas resizing is locked during recording' : 'Canvas height'}\n />\n </div>\n\n {/* Scale Indicator - Shows canvas vs display comparison */}\n <div \n className=\"flex items-center gap-1.5 px-2 py-1 rounded border border-border bg-background/50\"\n title={isScaled \n ? `Canvas: ${canvasSize} → Display: ${displaySize} (scaled to ${scalePercent}%)`\n : `Canvas: ${canvasSize} = Display: ${displaySize} (no scaling)`\n }\n style={{\n display: isScaled ? 'flex' : 'none',\n }}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={isScaled ? \"text-accent\" : \"text-muted\"}\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <path d=\"m21 21-4.3-4.3\"></path>\n <line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\"></line>\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\"></line>\n </svg>\n <div className=\"flex items-center gap-1\">\n {/* <span className={`text-xs font-medium ${isScaled ? \"text-accent\" : \"text-muted\"}`}>\n {canvasSize}\n </span> */}\n {/* {isScaled && (\n <>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"text-accent\"\n >\n <polyline points=\"9 18 15 12 9 6\"></polyline>\n </svg>\n <span className=\"text-xs font-medium text-accent\">\n {displaySize}\n </span>\n </>\n )} */}\n <span className={`text-xs ${isScaled ? \"text-accent\" : \"text-muted\"}`}>\n {scalePercent}%\n </span>\n </div>\n </div>\n\n {/* Fit to Screen Button */}\n <button\n type=\"button\"\n className={`inline-flex items-center gap-1 h-[30px] rounded-lg border border-border bg-background px-3 py-2 text-sm text-text transition whitespace-nowrap ${\n isRecording ? 'opacity-50 cursor-not-allowed' : 'hover:bg-muted/80'\n }`}\n onClick={fitToScreen}\n disabled={isRecording}\n title={isRecording ? 'Canvas resizing is locked during recording' : 'Fit to screen'}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M8 3H5a2 2 0 0 0-2 2v3\"></path>\n <path d=\"M21 8V5a2 2 0 0 0-2-2h-3\"></path>\n <path d=\"M3 16v3a2 2 0 0 0 2 2h3\"></path>\n <path d=\"M16 21h3a2 2 0 0 0 2-2v-3\"></path>\n </svg>\n </button>\n </div>\n );\n};\n\n",
19
- "// Type imports\nimport type {\n HyperFrameRuntimeConfig,\n HyperFrameSandboxHandle,\n HyperFrameSandboxOptions,\n} from './types';\n\n// Implementation imports\nimport { HyperFrameRuntime } from './runtime';\n\n// Runtime instance\nconst defaultConfig: HyperFrameRuntimeConfig = { mirrorCss: true };\nconst runtime = new HyperFrameRuntime(defaultConfig);\n\n// Exports\nexport { runtime };\n\nexport function configureRuntime(config: HyperFrameRuntimeConfig) {\n return new HyperFrameRuntime(config);\n}\n\nexport function createSandbox(options: HyperFrameSandboxOptions): Promise<HyperFrameSandboxHandle> {\n return runtime.createSandbox(options);\n}\n\n\n\nexport function mirrorCss() {\n runtime.mirrorCss();\n}\n\n// Type exports - re-export all public types from types.ts\nexport type {\n // Core types\n HyperFrameRuntimeConfig,\n HyperFrameRuntimeApi,\n HyperFrameSandboxOptions,\n HyperFrameSandboxHandle,\n\n // Control types (re-exported from controls)\n ControlType,\n ControlDefinition,\n ControlDefinitions,\n NumberControlDefinition,\n ColorControlDefinition,\n BooleanControlDefinition,\n StringControlDefinition,\n SelectControlDefinition,\n\n // Sandbox types\n SandboxContext,\n SandboxEnvironment,\n SandboxControlsHandle,\n SandboxExportsApi,\n SandboxCaptureFn,\n SandboxCaptureResult,\n SandboxImageCaptureHandler,\n SandboxVideoCaptureHandler,\n SandboxControlChangeHandler,\n\n // Control panel types\n ControlChangePayload,\n ControlPanelOptions,\n\n // Mount types\n MountOptions,\n MountResult,\n\n\n} from './types';\n"
20
- ],
21
- "mappings": "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",
22
- "debugId": "0C88A8B0F323342264756E2164756E21",
23
- "names": []
24
- }
@@ -1,39 +0,0 @@
1
- /**
2
- * Frame Adapter - Thin wiring layer for editor iframe (WebContainer)
3
- *
4
- * This adapter:
5
- * - Uses Core Experience for ALL logic
6
- * - Optionally attaches Controls UI (Tweakpane)
7
- * - Wires postMessage for param sync with parent
8
- * - Wires postMessage for capture requests
9
- * - Handles CSS mirroring from parent
10
- *
11
- * THIN LAYER - no business logic here, just wiring!
12
- */
13
- import { HyperFrameRuntimeApi, HyperFrameRuntimeConfig, HyperFrameSandboxHandle, HyperFrameSandboxOptions } from './types';
14
- export declare class HyperFrameRuntime implements HyperFrameRuntimeApi {
15
- private cssBridge;
16
- private config;
17
- private currentExperience;
18
- constructor(config?: HyperFrameRuntimeConfig);
19
- private setupMessageHandlers;
20
- private handleCaptureScreenshot;
21
- private handleSetParams;
22
- private handleGetParams;
23
- private sendToParent;
24
- private notifyParamChange;
25
- private createOptimizedThumbnail;
26
- mirrorCss(): void;
27
- createSandbox(options: HyperFrameSandboxOptions): Promise<HyperFrameSandboxHandle>;
28
- /**
29
- * Wrap user's setup to adapt from our context to theirs
30
- * This is the THIN adapter part - just mapping
31
- */
32
- private wrapUserSetup;
33
- /**
34
- * Wire controls UI to Experience params
35
- */
36
- private wireControlsToExperience;
37
- private createReactMount;
38
- }
39
- //# sourceMappingURL=runtime.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/frame/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EAIzB,MAAM,SAAS,CAAC;AAQjB,qBAAa,iBAAkB,YAAW,oBAAoB;IAC5D,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,iBAAiB,CAA2B;gBAExC,MAAM,GAAE,uBAA4B;IAOhD,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,uBAAuB;IAuD/B,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,wBAAwB;IAkChC,SAAS,IAAI,IAAI;IAQX,aAAa,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAoDxF;;;OAGG;IACH,OAAO,CAAC,aAAa;IAoCrB;;OAEG;IACH,OAAO,CAAC,wBAAwB;YAWlB,gBAAgB;CAuE/B"}
@@ -1,119 +0,0 @@
1
- import type { ControlType, ControlDefinition, ControlDefinitions, NumberControlDefinition, ColorControlDefinition, BooleanControlDefinition, StringControlDefinition, SelectControlDefinition } from '../controls/types';
2
- export type { ControlType, ControlDefinition, ControlDefinitions, NumberControlDefinition, ColorControlDefinition, BooleanControlDefinition, StringControlDefinition, SelectControlDefinition, };
3
- export interface ControlChangePayload {
4
- key: string;
5
- value: any;
6
- event: any;
7
- }
8
- export interface ControlPanelOptions {
9
- title?: string;
10
- position?: string;
11
- expanded?: boolean;
12
- container?: HTMLElement | string | null;
13
- onChange?: (change: ControlChangePayload, context: SandboxContext) => void;
14
- /**
15
- * Toggle + add-control affordance rendered under the Tweakpane panel.
16
- * Defaults to true.
17
- */
18
- showAddControlActions?: boolean;
19
- /**
20
- * Optional whitelist of control types to show in the add-control dropdown.
21
- * Falls back to a sensible default set if omitted.
22
- */
23
- controlTypes?: ControlType[];
24
- /**
25
- * Callback fired when the user requests a new control from the UI.
26
- * Host apps can use this to trigger an AI prompt / patch flow.
27
- */
28
- onAddControlRequest?: (request: {
29
- type: ControlType;
30
- name: string;
31
- prompt: string;
32
- }) => void;
33
- }
34
- export interface MountOptions {
35
- target?: HTMLElement | string | null;
36
- containerClassName?: string;
37
- onReady?: (context: {
38
- container: HTMLElement;
39
- }) => void;
40
- }
41
- export interface SandboxControlsHandle {
42
- params: Record<string, any>;
43
- destroy?(): void;
44
- dispose?(): void;
45
- [key: string]: any;
46
- }
47
- export type SandboxControlChangeHandler = (change: ControlChangePayload, context: SandboxContext) => void;
48
- export type SandboxCaptureResult = Blob | string | HTMLCanvasElement | OffscreenCanvas | null;
49
- export type SandboxCaptureFn = () => Promise<SandboxCaptureResult> | SandboxCaptureResult;
50
- export interface SandboxImageCaptureHandler {
51
- capture: SandboxCaptureFn;
52
- filename?: string;
53
- mimeType?: string;
54
- }
55
- export interface SandboxVideoCaptureHandler {
56
- requestStream: () => Promise<MediaStream> | MediaStream;
57
- filename?: string;
58
- mimeType?: string;
59
- bitsPerSecond?: number;
60
- timeSlice?: number;
61
- }
62
- export interface SandboxExportsApi {
63
- registerImageCapture(handler: SandboxImageCaptureHandler | SandboxCaptureFn | null): void;
64
- registerVideoCapture(handler: SandboxVideoCaptureHandler | null): void;
65
- setFilename(filename: string): void;
66
- setVisible(visible: boolean): void;
67
- useDefaultCanvasCapture(enable?: boolean): void;
68
- destroy(): void;
69
- }
70
- export interface SandboxEnvironment {
71
- window: Window;
72
- document: Document;
73
- addCleanup(cleanup: () => void): void;
74
- onResize(handler: () => void, options?: AddEventListenerOptions): () => void;
75
- }
76
- export interface SandboxContext {
77
- mount: HTMLElement;
78
- params: Record<string, any>;
79
- controls: SandboxControlsHandle | null;
80
- exports: SandboxExportsApi;
81
- runtime: HyperFrameRuntimeApi;
82
- environment: SandboxEnvironment;
83
- }
84
- export interface MountResult<TInstance = any> {
85
- container: HTMLElement;
86
- getInstance(): TInstance | null;
87
- destroy(): void;
88
- }
89
- export interface HyperFrameSandboxHandle {
90
- destroy(): void;
91
- container: HTMLElement;
92
- controls: SandboxControlsHandle | null;
93
- params: Record<string, any>;
94
- }
95
- export interface HyperFrameRuntimeConfig {
96
- mirrorCss?: boolean;
97
- }
98
- export interface HyperFrameSandboxOptions {
99
- name?: string;
100
- mirrorCss?: boolean;
101
- mount?: MountOptions | Record<string, any>;
102
- controls?: {
103
- definitions: ControlDefinitions;
104
- options?: ControlPanelOptions;
105
- onChange?: SandboxControlChangeHandler;
106
- };
107
- exportWidget?: {
108
- enabled?: boolean;
109
- filename?: string;
110
- useCanvasCapture?: boolean;
111
- position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
112
- };
113
- setup(context: SandboxContext): Promise<void | (() => void)> | void | (() => void);
114
- }
115
- export interface HyperFrameRuntimeApi {
116
- mirrorCss(): void;
117
- createSandbox(options: HyperFrameSandboxOptions): Promise<HyperFrameSandboxHandle>;
118
- }
119
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/frame/types.ts"],"names":[],"mappings":"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"}
@@ -1,11 +0,0 @@
1
- export interface ResolvedContainer {
2
- element: HTMLElement;
3
- createdInternally: boolean;
4
- }
5
- export interface ResolveContainerOptions {
6
- target?: HTMLElement | string | null;
7
- containerClassName?: string;
8
- documentRef?: Document;
9
- }
10
- export declare function resolveContainer(options?: ResolveContainerOptions): ResolvedContainer;
11
- //# sourceMappingURL=dom.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../../src/frame/utils/dom.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,WAAW,CAAC;IACrB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAAC;IACrC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,QAAQ,CAAC;CACxB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B,GAAG,iBAAiB,CA4BzF"}
@@ -1,16 +0,0 @@
1
- import React from 'react';
2
- import type { WrapperAppProps } from './types';
3
- import './styles/controls.css';
4
- import './styles/wrapper-app.css';
5
- /**
6
- * WrapperApp - Main React app that wraps the sandbox
7
- *
8
- * This is the root component that manages the layout of the entire frame:
9
- * - CanvasProvider (context for canvas sizing)
10
- * - ExportWidget (UI + logic for capture/recording)
11
- * - CanvasSizeWidget (Canvas resize controls)
12
- * - Sandbox container (where user code renders, sized by CanvasContext)
13
- * - Controls panel (Tweakpane)
14
- */
15
- export declare const WrapperApp: React.FC<WrapperAppProps>;
16
- //# sourceMappingURL=WrapperApp.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"WrapperApp.d.ts","sourceRoot":"","sources":["../../../src/frame/wrapper-app/WrapperApp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAMrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,uBAAuB,CAAC;AAC/B,OAAO,0BAA0B,CAAC;AAElC;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA0ChD,CAAC"}
@@ -1,17 +0,0 @@
1
- import React from 'react';
2
- /**
3
- * CanvasSizeWidget - Canvas size control UI
4
- *
5
- * Displays and manages:
6
- * - Width input (updates on Enter or blur)
7
- * - Height input (updates on Enter or blur)
8
- * - Preset aspect ratios dropdown (maximizes to container with chosen ratio)
9
- * - Scale indicator (shows current zoom level)
10
- * - Fit to screen button
11
- *
12
- * Presets set aspect ratio only - canvas size always maximizes to fill container.
13
- * Manual width/height inputs allow free-form sizing.
14
- * All state and logic come from CanvasContext.
15
- */
16
- export declare const CanvasSizeWidget: React.FC;
17
- //# sourceMappingURL=CanvasSizeWidget.d.ts.map