@hypertools/sdk 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,800 +0,0 @@
1
- import{createRequire as T}from"node:module";var v=Object.create;var{getPrototypeOf:S,defineProperty:G,getOwnPropertyNames:j}=Object;var D=Object.prototype.hasOwnProperty;var _=(q,z,A)=>{A=q!=null?v(S(q)):{};let B=z||!q||!q.__esModule?G(A,"default",{value:q,enumerable:!0}):A;for(let M of j(q))if(!D.call(B,M))G(B,M,{get:()=>q[M],enumerable:!0});return B};var $=T(import.meta.url);async function P(q){let z;try{z=await import("esbuild")}catch{throw Error("esbuild is not available. This function is meant to run server-side.")}let{mkdtemp:A,writeFile:B,readFile:M,rm:R,mkdir:O}=await import("fs/promises"),{tmpdir:L}=await import("os"),{join:K,dirname:U}=await import("path"),Q=await A(K(L(),"hypertool-bundle-"));try{if(q.files)for(let[Y,F]of Object.entries(q.files)){let W=K(Q,Y.replace(/^\//,"")),J=U(W);await O(J,{recursive:!0}),await B(W,F)}let X;if(typeof q.entry==="string")X=K(Q,q.entry.replace(/^\//,""));else{let Y=q.entry.filename??"entry.ts";X=K(Q,Y),await B(X,q.entry.code)}let Z=await z.build({entryPoints:[X],bundle:!0,outfile:K(Q,"out.js"),platform:q.target==="node"?"node":"browser",format:q.format??"iife",minify:q.minify??!0,sourcemap:q.sourcemap?"external":!1,globalName:q.globalName,external:q.external,define:q.define,write:!0,metafile:!0}),I=await M(K(Q,"out.js"),"utf-8"),V;if(q.sourcemap)try{V=await M(K(Q,"out.js.map"),"utf-8")}catch{}return{code:I,map:V,warnings:Z.warnings.map((Y)=>Y.text),size:Buffer.byteLength(I,"utf-8")}}finally{await R(Q,{recursive:!0,force:!0})}}function k(q){if(!q.match(/export\s+(?:const|let|var)\s+(?:paramDefs|controlDefinitions)\s*=\s*(\{[\s\S]*?\});?/))return null;try{return null}catch{return null}}function w(q){return`
2
- ${q}
3
-
4
- // Expose setup function globally for web component
5
- if (typeof setup === 'function') {
6
- window.__hypertool_setup__ = setup;
7
- }
8
- if (typeof paramDefs !== 'undefined') {
9
- window.__hypertool_paramDefs__ = paramDefs;
10
- }
11
- `}function C(q){return q.replace(/\\/g,"\\\\").replace(/`/g,"\\`").replace(/\$/g,"\\$").replace(/<\/script>/gi,"<\\/script>")}function x(q){let{tagName:z,className:A,bundledCode:B,paramDefs:M,currentParams:R={},showControls:O=!1,background:L="transparent"}=q,K=JSON.stringify(R).replace(/</g,"\\u003c").replace(/>/g,"\\u003e"),U=JSON.stringify(M).replace(/</g,"\\u003c").replace(/>/g,"\\u003e"),Q=O?`
12
- // Load Tweakpane for controls
13
- async function loadTweakpane() {
14
- if (window.Tweakpane) return window.Tweakpane;
15
- return new Promise((resolve, reject) => {
16
- const script = document.createElement('script');
17
- script.src = 'https://cdn.jsdelivr.net/npm/tweakpane@4.0.5/dist/tweakpane.min.js';
18
- script.onload = () => resolve(window.Tweakpane);
19
- script.onerror = reject;
20
- document.head.appendChild(script);
21
- });
22
- }
23
-
24
- async function createControls(params, defs, container) {
25
- try {
26
- const Tweakpane = await loadTweakpane();
27
- const pane = new Tweakpane.Pane({
28
- title: '${A} Controls',
29
- container,
30
- });
31
-
32
- for (const [key, def] of Object.entries(defs)) {
33
- const config = { label: def.label || key };
34
- if (def.type === 'number') {
35
- if (def.min !== undefined) config.min = def.min;
36
- if (def.max !== undefined) config.max = def.max;
37
- if (def.step !== undefined) config.step = def.step;
38
- }
39
- if (def.type === 'select' && def.options) {
40
- config.options = def.options.reduce((acc, opt) => {
41
- const val = typeof opt === 'object' ? opt.value : opt;
42
- const label = typeof opt === 'object' ? opt.label : opt;
43
- acc[label] = val;
44
- return acc;
45
- }, {});
46
- }
47
- try {
48
- pane.addBinding(params, key, config);
49
- } catch (e) {
50
- console.warn('Failed to add control:', key, e);
51
- }
52
- }
53
-
54
- return pane;
55
- } catch (e) {
56
- console.warn('Failed to load Tweakpane:', e);
57
- return null;
58
- }
59
- }
60
- `:"";return`
61
- /**
62
- * ${A} Web Component
63
- * Generated by HyperTool SDK
64
- */
65
-
66
- (function() {
67
- 'use strict';
68
-
69
- const __PARAMS__ = ${K};
70
- const __PARAM_DEFS__ = ${U};
71
- const __SHOW_CONTROLS__ = ${O};
72
- const __BACKGROUND__ = '${L}';
73
-
74
- ${Q}
75
-
76
- class ${A}Element extends HTMLElement {
77
- #mount = null;
78
- #params = null;
79
- #cleanup = null;
80
- #resizeObserver = null;
81
- #pane = null;
82
- #isReady = false;
83
-
84
- constructor() {
85
- super();
86
- this.attachShadow({ mode: 'open' });
87
- }
88
-
89
- static get observedAttributes() {
90
- return ['autoplay', 'background', ...Object.keys(__PARAM_DEFS__)];
91
- }
92
-
93
- connectedCallback() {
94
- this.#render();
95
- this.#initialize();
96
- }
97
-
98
- disconnectedCallback() {
99
- this.#destroy();
100
- }
101
-
102
- attributeChangedCallback(name, oldValue, newValue) {
103
- if (oldValue === newValue) return;
104
-
105
- if (name === 'background') {
106
- if (this.#mount) {
107
- this.#mount.style.background = newValue || __BACKGROUND__;
108
- }
109
- return;
110
- }
111
-
112
- if (name in __PARAM_DEFS__ && this.#params) {
113
- this.#params[name] = this.#parseAttribute(newValue, __PARAM_DEFS__[name].type);
114
- }
115
- }
116
-
117
- #render() {
118
- this.shadowRoot.innerHTML = \`
119
- <style>
120
- :host {
121
- display: block;
122
- width: 100%;
123
- height: 100%;
124
- position: relative;
125
- }
126
- .mount {
127
- width: 100%;
128
- height: 100%;
129
- position: relative;
130
- overflow: hidden;
131
- background: \${__BACKGROUND__};
132
- }
133
- .controls-container {
134
- position: absolute;
135
- top: 8px;
136
- right: 8px;
137
- z-index: 1000;
138
- }
139
- </style>
140
- <div class="mount"></div>
141
- \${__SHOW_CONTROLS__ ? '<div class="controls-container"></div>' : ''}
142
- \`;
143
-
144
- this.#mount = this.shadowRoot.querySelector('.mount');
145
- }
146
-
147
- async #initialize() {
148
- // Initialize params from defaults + attributes
149
- this.#params = { ...__PARAMS__ };
150
-
151
- for (const [key, def] of Object.entries(__PARAM_DEFS__)) {
152
- const attrValue = this.getAttribute(key);
153
- if (attrValue !== null) {
154
- this.#params[key] = this.#parseAttribute(attrValue, def.type);
155
- }
156
- }
157
-
158
- // Create reactive proxy
159
- const self = this;
160
- this.#params = new Proxy(this.#params, {
161
- set(target, prop, value) {
162
- const previous = target[prop];
163
- target[prop] = value;
164
- if (previous !== value) {
165
- self.dispatchEvent(new CustomEvent('paramchange', {
166
- detail: { key: prop, value, previousValue: previous },
167
- bubbles: true,
168
- }));
169
- }
170
- return true;
171
- }
172
- });
173
-
174
- // Setup resize observer
175
- this.#resizeObserver = new ResizeObserver(() => {
176
- this.dispatchEvent(new CustomEvent('resize', {
177
- detail: {
178
- width: this.#mount.clientWidth,
179
- height: this.#mount.clientHeight
180
- },
181
- bubbles: true,
182
- }));
183
- });
184
- this.#resizeObserver.observe(this.#mount);
185
-
186
- // Setup controls if enabled
187
- if (__SHOW_CONTROLS__) {
188
- const controlsContainer = this.shadowRoot.querySelector('.controls-container');
189
- if (controlsContainer && typeof createControls === 'function') {
190
- this.#pane = await createControls(this.#params, __PARAM_DEFS__, controlsContainer);
191
- }
192
- }
193
-
194
- // Run experience setup
195
- try {
196
- const context = {
197
- mount: this.#mount,
198
- params: this.#params,
199
- exports: {
200
- captureImage: (format) => this.captureImage(format),
201
- setFilename: () => {},
202
- useDefaultCanvasCapture: () => {},
203
- },
204
- environment: {
205
- window,
206
- document,
207
- onResize: (cb) => {
208
- const handler = () => cb(this.#mount.clientWidth, this.#mount.clientHeight);
209
- handler();
210
- const ro = new ResizeObserver(handler);
211
- ro.observe(this.#mount);
212
- return () => ro.disconnect();
213
- },
214
- },
215
- registerObject: () => {},
216
- };
217
-
218
- // Execute bundled code
219
- ${C(B)}
220
-
221
- // Call setup if defined
222
- if (typeof window.__hypertool_setup__ === 'function') {
223
- this.#cleanup = await window.__hypertool_setup__(context);
224
- } else if (typeof setup === 'function') {
225
- this.#cleanup = await setup(context);
226
- }
227
-
228
- this.#isReady = true;
229
- this.dispatchEvent(new CustomEvent('ready', { bubbles: true }));
230
-
231
- // Autoplay by default
232
- if (this.getAttribute('autoplay') !== 'false') {
233
- this.play();
234
- }
235
- } catch (error) {
236
- console.error('[${A}] Setup error:', error);
237
- this.dispatchEvent(new CustomEvent('error', {
238
- detail: { error },
239
- bubbles: true,
240
- }));
241
- }
242
- }
243
-
244
- #destroy() {
245
- if (this.#cleanup && typeof this.#cleanup === 'function') {
246
- try {
247
- this.#cleanup();
248
- } catch (e) {
249
- console.error('[${A}] Cleanup error:', e);
250
- }
251
- }
252
- this.#resizeObserver?.disconnect();
253
- this.#pane?.dispose();
254
- this.#cleanup = null;
255
- this.#params = null;
256
- this.#isReady = false;
257
- }
258
-
259
- #parseAttribute(value, type) {
260
- switch (type) {
261
- case 'number':
262
- return parseFloat(value);
263
- case 'boolean':
264
- return value === 'true' || value === '';
265
- case 'color':
266
- return value;
267
- default:
268
- return value;
269
- }
270
- }
271
-
272
- // Public API
273
- get isReady() { return this.#isReady; }
274
-
275
- setParam(key, value) {
276
- if (this.#params && key in __PARAM_DEFS__) {
277
- this.#params[key] = value;
278
- this.#pane?.refresh();
279
- }
280
- }
281
-
282
- setParams(params) {
283
- if (!this.#params) return;
284
- for (const [key, value] of Object.entries(params)) {
285
- if (key in __PARAM_DEFS__) {
286
- this.#params[key] = value;
287
- }
288
- }
289
- this.#pane?.refresh();
290
- }
291
-
292
- getParams() {
293
- return this.#params ? { ...this.#params } : {};
294
- }
295
-
296
- getParamDefs() {
297
- return __PARAM_DEFS__;
298
- }
299
-
300
- async captureImage(format = 'png') {
301
- const canvas = this.#mount?.querySelector('canvas');
302
- if (!canvas) return null;
303
-
304
- return new Promise((resolve) => {
305
- canvas.toBlob(resolve, \`image/\${format}\`, format === 'jpeg' ? 0.92 : undefined);
306
- });
307
- }
308
-
309
- play() {
310
- this.dispatchEvent(new CustomEvent('play', { bubbles: true }));
311
- }
312
-
313
- pause() {
314
- this.dispatchEvent(new CustomEvent('pause', { bubbles: true }));
315
- }
316
- }
317
-
318
- // Register custom element
319
- if (!customElements.get('${z}')) {
320
- customElements.define('${z}', ${A}Element);
321
- }
322
- })();
323
- `}function H(q){let{className:z,tagName:A,paramDefs:B}=q,M=Object.entries(B).map(([R,O])=>{let L;switch(O.type){case"number":L="number";break;case"boolean":L="boolean";break;case"color":case"string":L="string";break;case"select":if(O.options)L=O.options.map((K)=>`'${typeof K==="object"?K.value:K}'`).join(" | ");else L="string";break;default:L="unknown"}return` ${R}?: ${L};`}).join(`
324
- `);return`/**
325
- * TypeScript definitions for ${z}
326
- * Generated by HyperTool SDK
327
- */
328
-
329
- declare namespace JSX {
330
- interface IntrinsicElements {
331
- '${A}': ${z}Attributes;
332
- }
333
- }
334
-
335
- interface ${z}Attributes {
336
- autoplay?: boolean | 'true' | 'false';
337
- background?: string;
338
- ${M}
339
- }
340
-
341
- interface ${z}Element extends HTMLElement {
342
- readonly isReady: boolean;
343
- setParam(key: string, value: unknown): void;
344
- setParams(params: Record<string, unknown>): void;
345
- getParams(): Record<string, unknown>;
346
- getParamDefs(): Record<string, { type: string; value: unknown; [key: string]: unknown }>;
347
- captureImage(format?: 'png' | 'jpeg' | 'webp'): Promise<Blob | null>;
348
- play(): void;
349
- pause(): void;
350
- }
351
-
352
- interface ${z}Events {
353
- ready: CustomEvent<void>;
354
- error: CustomEvent<{ error: Error }>;
355
- paramchange: CustomEvent<{ key: string; value: unknown; previousValue: unknown }>;
356
- resize: CustomEvent<{ width: number; height: number }>;
357
- play: CustomEvent<void>;
358
- pause: CustomEvent<void>;
359
- }
360
- `}var E={cssVariables:{"--bg":"#0a0e14","--bg-elevated":"#0f1419","--muted":"#1a2332","--text":"#e6edf3","--text-secondary":"#8b949e","--accent":"#58d5ff","--accent-2":"#42a5cc","--border":"#21262d","--border-hover":"#30363d","--success":"#3fb950","--error":"#f85149","--ht-text-color-main-200":"#00ffd4","--ht-text-color-main-300":"#6ff3dd","--ht-text-color-main-500":"#4b8e85","--ht-text-color-grey-200":"#8c8d8f","--ht-bg-color-200":"#8c8d8f","--ht-bg-color-200-active":"#7a7b7d","--ht-bg-color-200-focus":"#7e7f81","--ht-bg-color-200-hover":"#828384","--ht-bg-color-300":"#5e6068","--ht-bg-color-300-active":"#4c4e56","--ht-bg-color-300-focus":"#55575f","--ht-bg-color-300-hover":"#595b63","--ht-bg-color-400":"#cccccc","--ht-bg-color-400-active":"#b3b3b3","--ht-bg-color-400-focus":"#c0c0c0","--ht-bg-color-400-hover":"#c6c6c6","--ht-bg-color-500":"#1C1D20","--ht-bg-color-500-active":"#0a0b0e","--ht-bg-color-500-focus":"#131417","--ht-bg-color-500-hover":"#16171a","--ht-bg-color-600":"#37383D","--ht-bg-color-600-active":"#25262b","--ht-bg-color-600-focus":"#2e2f34","--ht-bg-color-600-hover":"#323338","--ht-bg-color-700":"#0f1419","--ht-bg-color-700-active":"#16171c","--ht-bg-color-700-focus":"#1f2025","--ht-bg-color-700-hover":"#232429","--ht-border-radius":"8px","--ht-base-font-family-base":'"HydrogenType400", ui-sans-serif, system-ui, sans-serif',"--ht-base-font-family-display":'"Departure Mono", Roboto Mono, Source Code Pro, Menlo, Courier, monospace',"--ht-base-font-family-sans":'"Routed Gothic", ui-sans-serif, system-ui, sans-serif',"--ht-base-font-family-mono":'"Routed Gothic Narrow", ui-monospace, SFMono-Regular, SF Mono, Consolas, Liberation Mono, Menlo, monospace'},tweakpane:{"--tp-base-background-color":"var(--ht-bg-color-700)","--tp-base-shadow-color":"hsla(0, 0%, 0%, 0.2)","--tp-container-background-color":"var(--ht-bg-color-600)","--tp-container-background-color-active":"var(--ht-bg-color-600-active)","--tp-container-background-color-focus":"var(--ht-bg-color-600-focus)","--tp-container-background-color-hover":"var(--ht-bg-color-600-hover)","--tp-container-foreground-color":"var(--ht-text-color-main-300)","--tp-button-background-color":"var(--ht-bg-color-400)","--tp-button-background-color-active":"color-mix(in srgb, var(--ht-bg-color-400-active) 80%, white)","--tp-button-background-color-focus":"color-mix(in srgb, var(--ht-bg-color-400-focus) 85%, white)","--tp-button-background-color-hover":"color-mix(in srgb, var(--ht-bg-color-400-hover) 90%, white)","--tp-button-foreground-color":"var(--ht-text-color-main-300)","--tp-groove-foreground-color":"var(--ht-bg-color-300)","--tp-input-background-color":"var(--ht-bg-color-500)","--tp-input-background-color-active":"var(--ht-bg-color-500-active)","--tp-input-background-color-focus":"var(--ht-bg-color-500-focus)","--tp-input-background-color-hover":"var(--ht-bg-color-500-hover)","--tp-input-foreground-color":"var(--ht-text-color-main-300)","--tp-label-foreground-color":"var(--ht-text-color-main-300)","--tp-monitor-background-color":"var(--ht-bg-color-500)","--tp-monitor-foreground-color":"var(--ht-text-color-main-300)"}};function b(q){return JSON.stringify(q).replace(/</g,"\\u003c").replace(/>/g,"\\u003e").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}function f(){return`
361
- /* Hypertool Theme - generated from studioTheme */
362
- :host {
363
- ${Object.entries({...E.cssVariables,...E.tweakpane}).map(([z,A])=>` ${z}: ${A};`).join(`
364
- `)}
365
- }
366
-
367
- /* Ensure Tweakpane uses our theme */
368
- .tp-dfwv {
369
- background-color: var(--tp-base-background-color) !important;
370
- border-radius: 8px;
371
- }
372
- `}function h(q){return`
373
- // Tweakpane loaded dynamically from esm.sh CDN at runtime
374
- let __Pane__: any = null;
375
-
376
- async function __loadTweakpane__(): Promise<void> {
377
- if (__Pane__) return;
378
- try {
379
- const module = await import('https://esm.sh/tweakpane@4');
380
- __Pane__ = module.Pane;
381
- } catch (e) {
382
- console.warn('[Controls] Failed to load Tweakpane from CDN:', e);
383
- }
384
- }
385
-
386
- const __THEME_CSS__ = \`${f()}\`;
387
-
388
- async function __createControls__(params: Record<string, unknown>, defs: Record<string, any>, container: HTMLElement, shadowRoot: ShadowRoot) {
389
- await __loadTweakpane__();
390
- if (!__Pane__) return null;
391
-
392
- try {
393
- const pane = new __Pane__({
394
- title: '${q}',
395
- container,
396
- });
397
-
398
- for (const [key, def] of Object.entries(defs)) {
399
- if (!def || def.type === 'folder') continue;
400
-
401
- const config: Record<string, unknown> = { label: def.label || key };
402
-
403
- if (def.type === 'number') {
404
- if (def.min !== undefined) config.min = def.min;
405
- if (def.max !== undefined) config.max = def.max;
406
- if (def.step !== undefined) config.step = def.step;
407
- }
408
-
409
- if (def.type === 'select' && def.options) {
410
- config.options = def.options.reduce((acc: Record<string, unknown>, opt: unknown) => {
411
- const val = typeof opt === 'object' && opt !== null ? (opt as any).value : opt;
412
- const label = typeof opt === 'object' && opt !== null ? (opt as any).label : String(opt);
413
- acc[label] = val;
414
- return acc;
415
- }, {});
416
- }
417
-
418
- try {
419
- pane.addBinding(params, key, config);
420
- } catch (e) {
421
- console.warn('[Controls] Failed to add binding for:', key, e);
422
- }
423
- }
424
-
425
- // Tweakpane injects CSS into document.head - copy it to shadow root for isolation
426
- setTimeout(() => {
427
- const tpStyles = document.querySelectorAll('style');
428
- tpStyles.forEach(style => {
429
- if (style.textContent?.includes('.tp-') || style.textContent?.includes('tp-dfwv')) {
430
- const clone = style.cloneNode(true) as HTMLStyleElement;
431
- shadowRoot.appendChild(clone);
432
- }
433
- });
434
- }, 0);
435
-
436
- return pane;
437
- } catch (e) {
438
- console.warn('[Controls] Failed to create controls:', e);
439
- return null;
440
- }
441
- }
442
- `}function y(){return`
443
- // Make controls panel draggable
444
- function __setupDraggable__(container, pane) {
445
- if (!pane || !pane.element) return;
446
-
447
- const titleEl = pane.element.querySelector('.tp-rotv_t');
448
- if (!titleEl) return;
449
-
450
- let isDragging = false;
451
- let startX = 0;
452
- let startY = 0;
453
- let initialRight = 8;
454
- let initialTop = 8;
455
-
456
- titleEl.style.cursor = 'grab';
457
-
458
- titleEl.addEventListener('mousedown', (e) => {
459
- if (e.button !== 0) return;
460
- isDragging = true;
461
- startX = e.clientX;
462
- startY = e.clientY;
463
-
464
- const style = getComputedStyle(container);
465
- initialRight = parseInt(style.right) || 8;
466
- initialTop = parseInt(style.top) || 8;
467
-
468
- titleEl.style.cursor = 'grabbing';
469
- e.preventDefault();
470
- });
471
-
472
- document.addEventListener('mousemove', (e) => {
473
- if (!isDragging) return;
474
-
475
- const deltaX = e.clientX - startX;
476
- const deltaY = e.clientY - startY;
477
-
478
- container.style.right = Math.max(0, initialRight - deltaX) + 'px';
479
- container.style.top = Math.max(0, initialTop + deltaY) + 'px';
480
- });
481
-
482
- document.addEventListener('mouseup', () => {
483
- if (isDragging) {
484
- isDragging = false;
485
- titleEl.style.cursor = 'grab';
486
- }
487
- });
488
- }
489
- `}function u(q){let{tagName:z,currentParams:A={},showControls:B=!1,controlsTitle:M,background:R="transparent"}=q,O=b(A),L=M||z.split("-").map((Z)=>Z.charAt(0).toUpperCase()+Z.slice(1)).join(" "),K=B?h(L):"",U=B?y():"",Q=B?'<div class="controls-container"></div>':"";return`
490
- // Export-friendly HyperTool Runtime
491
- // Generated by @hypertools/sdk
492
- // Controls: ${B?"enabled":"disabled"}
493
-
494
- // Baked-in current params from export
495
- const __BAKED_PARAMS__ = ${O};
496
- const __SHOW_CONTROLS__ = ${B};
497
- const __BACKGROUND__ = '${R}';
498
-
499
- ${K}
500
- ${U}
501
-
502
- export type ControlDefinitions = Record<string, {
503
- type: string;
504
- value: unknown;
505
- label?: string;
506
- min?: number;
507
- max?: number;
508
- step?: number;
509
- options?: unknown[];
510
- }>;
511
-
512
- export interface SandboxContext {
513
- mount: HTMLElement;
514
- params: Record<string, unknown>;
515
- exports: {
516
- setFilename: (name: string) => void;
517
- useDefaultCanvasCapture: (use: boolean) => void;
518
- captureImage: () => Promise<Blob>;
519
- };
520
- environment: {
521
- onResize: (callback: () => void) => () => void;
522
- window: Window;
523
- document: Document;
524
- };
525
- controls: null;
526
- }
527
-
528
- interface SandboxConfig {
529
- controls?: {
530
- definitions?: ControlDefinitions;
531
- options?: { title?: string };
532
- };
533
- exportWidget?: {
534
- filename?: string;
535
- useCanvasCapture?: boolean;
536
- enabled?: boolean;
537
- };
538
- setup: (context: SandboxContext) => (() => void) | void;
539
- }
540
-
541
- // Store for the experience definition
542
- let __experienceDef__: SandboxConfig | null = null;
543
-
544
- /**
545
- * createSandbox - Export version
546
- * Instead of connecting to studio, registers a web component
547
- */
548
- export async function createSandbox(config: SandboxConfig): Promise<void> {
549
- __experienceDef__ = config;
550
-
551
- // Create the web component
552
- class HypertoolElement extends HTMLElement {
553
- private _mount: HTMLElement | null = null;
554
- private _controlsContainer: HTMLElement | null = null;
555
- private _cleanup: (() => void) | void = undefined;
556
- private _params: Record<string, unknown> = {};
557
- private _pane: any = null;
558
-
559
- constructor() {
560
- super();
561
- this.attachShadow({ mode: 'open' });
562
- }
563
-
564
- connectedCallback() {
565
- if (!this.shadowRoot || !__experienceDef__) return;
566
-
567
- // Setup styles (includes theme CSS when controls enabled)
568
- const style = document.createElement('style');
569
- style.textContent = \`
570
- \${__SHOW_CONTROLS__ && typeof __THEME_CSS__ !== 'undefined' ? __THEME_CSS__ : ''}
571
- :host { display: block; width: 100%; height: 100%; }
572
- .mount {
573
- width: 100%;
574
- height: 100%;
575
- position: relative;
576
- overflow: hidden;
577
- background: \${__BACKGROUND__};
578
- }
579
- ${B?`
580
- .controls-container {
581
- position: absolute;
582
- top: 8px;
583
- right: 8px;
584
- z-index: 1000;
585
- max-height: calc(100% - 16px);
586
- overflow-y: auto;
587
- }
588
- /* Tweakpane theme overrides */
589
- .controls-container .tp-dfwv {
590
- background-color: rgba(15, 20, 25, 0.95) !important;
591
- }
592
- `:""}
593
- \`;
594
- this.shadowRoot.appendChild(style);
595
-
596
- // Create mount
597
- this._mount = document.createElement('div');
598
- this._mount.className = 'mount';
599
- this.shadowRoot.appendChild(this._mount);
600
-
601
- // Create controls container if enabled
602
- if (__SHOW_CONTROLS__) {
603
- this._controlsContainer = document.createElement('div');
604
- this._controlsContainer.className = 'controls-container';
605
- this.shadowRoot.appendChild(this._controlsContainer);
606
- }
607
-
608
- // Initialize params: baked params > HTML attributes > definition defaults
609
- const defs = __experienceDef__.controls?.definitions || {};
610
- for (const [key, def] of Object.entries(defs)) {
611
- // Priority: HTML attribute > baked param > definition default
612
- if (this.getAttribute(key) !== null) {
613
- this._params[key] = this._parseAttr(key, this.getAttribute(key)!, def);
614
- } else if (key in __BAKED_PARAMS__) {
615
- this._params[key] = __BAKED_PARAMS__[key];
616
- } else {
617
- this._params[key] = def.value;
618
- }
619
- }
620
-
621
- // Make params reactive
622
- const self = this;
623
- this._params = new Proxy(this._params, {
624
- set: (target, prop, value) => {
625
- const previous = target[prop as string];
626
- target[prop as string] = value;
627
- if (previous !== value) {
628
- self.dispatchEvent(new CustomEvent('paramchange', {
629
- detail: { key: prop, value, previousValue: previous },
630
- bubbles: true,
631
- }));
632
- }
633
- return true;
634
- }
635
- });
636
-
637
- // Create context
638
- const context: SandboxContext = {
639
- mount: this._mount,
640
- params: this._params,
641
- exports: {
642
- setFilename: () => {},
643
- useDefaultCanvasCapture: () => {},
644
- captureImage: async () => {
645
- const canvas = this._mount?.querySelector('canvas');
646
- if (!canvas) throw new Error('No canvas found');
647
- return new Promise((res, rej) => {
648
- canvas.toBlob(b => b ? res(b) : rej(new Error('Failed to capture')));
649
- });
650
- },
651
- },
652
- environment: {
653
- onResize: (callback) => {
654
- const ro = new ResizeObserver(() => callback());
655
- ro.observe(this._mount!);
656
- return () => ro.disconnect();
657
- },
658
- window,
659
- document,
660
- },
661
- controls: null,
662
- };
663
-
664
- // Run setup
665
- this._cleanup = __experienceDef__.setup(context);
666
-
667
- // Setup controls if enabled (async - loads Tweakpane from CDN)
668
- if (__SHOW_CONTROLS__ && this._controlsContainer && typeof __createControls__ === 'function') {
669
- __createControls__(this._params, defs, this._controlsContainer, this.shadowRoot!).then((pane: any) => {
670
- this._pane = pane;
671
- if (this._pane && typeof __setupDraggable__ === 'function') {
672
- __setupDraggable__(this._controlsContainer, this._pane);
673
- }
674
- });
675
- }
676
-
677
- // Dispatch ready event
678
- this.dispatchEvent(new CustomEvent('ready', { bubbles: true }));
679
- }
680
-
681
- disconnectedCallback() {
682
- if (this._cleanup) this._cleanup();
683
- if (this._pane?.dispose) this._pane.dispose();
684
- }
685
-
686
- private _parseAttr(key: string, value: string, def: { type: string }): unknown {
687
- switch (def.type) {
688
- case 'number': return parseFloat(value);
689
- case 'boolean': return value === 'true' || value === '';
690
- default: return value;
691
- }
692
- }
693
-
694
- // Public API
695
- setParam(key: string, value: unknown) {
696
- this._params[key] = value;
697
- this._pane?.refresh();
698
- }
699
- setParams(params: Record<string, unknown>) {
700
- for (const [k, v] of Object.entries(params)) this._params[k] = v;
701
- this._pane?.refresh();
702
- }
703
- getParams() { return { ...this._params }; }
704
- getParamDefs() { return __experienceDef__?.controls?.definitions || {}; }
705
- }
706
-
707
- // Register the component
708
- if (!customElements.get('${z}')) {
709
- customElements.define('${z}', HypertoolElement);
710
- }
711
- }
712
- `}function d(q){return`<!DOCTYPE html>
713
- <html lang="en">
714
- <head>
715
- <meta charset="UTF-8">
716
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
717
- <title>${q}</title>
718
- <style>
719
- * { margin: 0; padding: 0; box-sizing: border-box; }
720
- html, body { width: 100%; height: 100%; overflow: hidden; background: #0a0a0a; }
721
- ${q} { display: block; width: 100%; height: 100%; }
722
- </style>
723
- </head>
724
- <body>
725
- <${q}></${q}>
726
- <script src="./${q}.js"></script>
727
- </body>
728
- </html>`}function g(q,z){let A=["https://cdnjs.cloudflare.com","https://cdn.jsdelivr.net","https://unpkg.com","https://esm.sh","https://cdn.skypack.dev"].join(" ");return`<!DOCTYPE html>
729
- <html lang="en">
730
- <head>
731
- <meta charset="UTF-8">
732
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
733
- <meta http-equiv="Content-Security-Policy" content="default-src 'self' blob: data: ${A}; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: data: ${A}; style-src 'self' 'unsafe-inline' ${A}; img-src 'self' blob: data: *; media-src 'self' blob: data: *; connect-src *; font-src 'self' data: ${A};">
734
- <title>${q}</title>
735
- <style>
736
- * { margin: 0; padding: 0; box-sizing: border-box; }
737
- html, body { width: 100%; height: 100%; overflow: hidden; background: #0a0a0a; }
738
- ${q} { display: block; width: 100%; height: 100%; }
739
- </style>
740
- </head>
741
- <body>
742
- <${q}></${q}>
743
- <script>
744
- ${z}
745
- </script>
746
- </body>
747
- </html>`}function c(q,z){return`# ${z}
748
-
749
- ## Usage
750
-
751
- \`\`\`html
752
- <script src="${q}.js"></script>
753
- <${q}></${q}>
754
- \`\`\`
755
-
756
- ## API
757
-
758
- \`\`\`javascript
759
- const el = document.querySelector('${q}');
760
-
761
- // Set parameters
762
- el.setParam('paramName', value);
763
- el.setParams({ param1: value1, param2: value2 });
764
-
765
- // Get current parameters
766
- const params = el.getParams();
767
-
768
- // Get parameter definitions
769
- const defs = el.getParamDefs();
770
- \`\`\`
771
-
772
- ## Events
773
-
774
- \`\`\`javascript
775
- el.addEventListener('ready', () => console.log('Ready!'));
776
- el.addEventListener('paramchange', (e) => {
777
- console.log('Param changed:', e.detail.key, e.detail.value);
778
- });
779
- \`\`\`
780
-
781
- ## Files
782
-
783
- - \`${q}.js\` - The bundled component
784
- - \`index.html\` - Example page (loads external JS)
785
- - \`preview.html\` - Standalone preview (inline JS)
786
- `}function N(q,z){return`export interface ${z}Element extends HTMLElement {
787
- setParam(key: string, value: unknown): void;
788
- setParams(params: Record<string, unknown>): void;
789
- getParams(): Record<string, unknown>;
790
- getParamDefs(): Record<string, { type: string; value: unknown; [key: string]: unknown }>;
791
- }
792
-
793
- declare global {
794
- interface HTMLElementTagNameMap {
795
- '${q}': ${z}Element;
796
- }
797
- }
798
- `}export{w as wrapSetupCode,x as generateWebComponent,H as generateTypeDefinitions,g as generatePreviewHtml,N as generateExportTypes,u as generateExportRuntime,c as generateExportReadme,d as generateExportHtml,P as generateBundle,k as extractParamDefs};
799
-
800
- //# debugId=BBAF843355D811CE64756E2164756E21