@hypertools/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +443 -0
- package/dist/capture/CaptureManager.d.ts +55 -0
- package/dist/capture/CaptureManager.d.ts.map +1 -0
- package/dist/capture/index.d.ts +27 -0
- package/dist/capture/index.d.ts.map +1 -0
- package/dist/capture/index.js +11 -0
- package/dist/capture/index.js.map +10 -0
- package/dist/capture/types.d.ts +76 -0
- package/dist/capture/types.d.ts.map +1 -0
- package/dist/codegen/index.d.ts +6 -0
- package/dist/codegen/index.d.ts.map +1 -0
- package/dist/codegen/index.js +800 -0
- package/dist/codegen/index.js.map +13 -0
- package/dist/controls/HypertoolControls.d.ts +84 -0
- package/dist/controls/HypertoolControls.d.ts.map +1 -0
- package/dist/controls/index.d.ts +11 -0
- package/dist/controls/index.d.ts.map +1 -0
- package/dist/controls/index.js +28 -0
- package/dist/controls/index.js.map +12 -0
- package/dist/controls/simple-api.d.ts +43 -0
- package/dist/controls/simple-api.d.ts.map +1 -0
- package/dist/controls/theme.d.ts +80 -0
- package/dist/controls/theme.d.ts.map +1 -0
- package/dist/controls/types.d.ts +178 -0
- package/dist/controls/types.d.ts.map +1 -0
- package/dist/core/EventEmitter.d.ts +76 -0
- package/dist/core/EventEmitter.d.ts.map +1 -0
- package/dist/core/Experience.d.ts +128 -0
- package/dist/core/Experience.d.ts.map +1 -0
- package/dist/core/ObjectRegistry.d.ts +76 -0
- package/dist/core/ObjectRegistry.d.ts.map +1 -0
- package/dist/core/ParamStore.d.ts +66 -0
- package/dist/core/ParamStore.d.ts.map +1 -0
- package/dist/core/index.d.ts +12 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +13 -0
- package/dist/export/bundler.d.ts +55 -0
- package/dist/export/bundler.d.ts.map +1 -0
- package/dist/export/generators/index.d.ts +6 -0
- package/dist/export/generators/index.d.ts.map +1 -0
- package/dist/export/generators/webComponent.d.ts +29 -0
- package/dist/export/generators/webComponent.d.ts.map +1 -0
- package/dist/export/index.d.ts +19 -0
- package/dist/export/index.d.ts.map +1 -0
- package/dist/export/index.js +800 -0
- package/dist/export/index.js.map +13 -0
- package/dist/export/runtime.d.ts +46 -0
- package/dist/export/runtime.d.ts.map +1 -0
- package/dist/frame/cssBridge.d.ts +34 -0
- package/dist/frame/cssBridge.d.ts.map +1 -0
- package/dist/frame/index.d.ts +9 -0
- package/dist/frame/index.d.ts.map +1 -0
- package/dist/frame/index.js +3 -0
- package/dist/frame/index.js.map +24 -0
- package/dist/frame/runtime.d.ts +39 -0
- package/dist/frame/runtime.d.ts.map +1 -0
- package/dist/frame/types.d.ts +119 -0
- package/dist/frame/types.d.ts.map +1 -0
- package/dist/frame/utils/dom.d.ts +11 -0
- package/dist/frame/utils/dom.d.ts.map +1 -0
- package/dist/frame/wrapper-app/WrapperApp.d.ts +16 -0
- package/dist/frame/wrapper-app/WrapperApp.d.ts.map +1 -0
- package/dist/frame/wrapper-app/components/CanvasSizeWidget.d.ts +17 -0
- package/dist/frame/wrapper-app/components/CanvasSizeWidget.d.ts.map +1 -0
- package/dist/frame/wrapper-app/components/ControlsPanel.d.ts +11 -0
- package/dist/frame/wrapper-app/components/ControlsPanel.d.ts.map +1 -0
- package/dist/frame/wrapper-app/components/ExportWidget.d.ts +16 -0
- package/dist/frame/wrapper-app/components/ExportWidget.d.ts.map +1 -0
- package/dist/frame/wrapper-app/components/ResizeHandles.d.ts +19 -0
- package/dist/frame/wrapper-app/components/ResizeHandles.d.ts.map +1 -0
- package/dist/frame/wrapper-app/components/SandboxContainer.d.ts +16 -0
- package/dist/frame/wrapper-app/components/SandboxContainer.d.ts.map +1 -0
- package/dist/frame/wrapper-app/components/index.d.ts +5 -0
- package/dist/frame/wrapper-app/components/index.d.ts.map +1 -0
- package/dist/frame/wrapper-app/context/CanvasContext.d.ts +37 -0
- package/dist/frame/wrapper-app/context/CanvasContext.d.ts.map +1 -0
- package/dist/frame/wrapper-app/context/index.d.ts +2 -0
- package/dist/frame/wrapper-app/context/index.d.ts.map +1 -0
- package/dist/frame/wrapper-app/index.d.ts +9 -0
- package/dist/frame/wrapper-app/index.d.ts.map +1 -0
- package/dist/frame/wrapper-app/types.d.ts +38 -0
- package/dist/frame/wrapper-app/types.d.ts.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +189 -0
- package/dist/index.js.map +35 -0
- package/dist/react/ExperienceView.d.ts +53 -0
- package/dist/react/ExperienceView.d.ts.map +1 -0
- package/dist/react/index.d.ts +8 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +3 -0
- package/dist/react/index.js.map +15 -0
- package/dist/react/useExperience.d.ts +55 -0
- package/dist/react/useExperience.d.ts.map +1 -0
- package/dist/recording/ImageCapture.d.ts +46 -0
- package/dist/recording/ImageCapture.d.ts.map +1 -0
- package/dist/recording/Timeline.d.ts +105 -0
- package/dist/recording/Timeline.d.ts.map +1 -0
- package/dist/recording/VideoRecorder.d.ts +64 -0
- package/dist/recording/VideoRecorder.d.ts.map +1 -0
- package/dist/recording/index.d.ts +10 -0
- package/dist/recording/index.d.ts.map +1 -0
- package/dist/recording/index.js +3 -0
- package/dist/recording/index.js.map +12 -0
- package/package.json +141 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 HyperTool Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
# @hypertool/sdk
|
|
2
|
+
|
|
3
|
+
Vanilla-first SDK for embedding interactive creative coding experiences. Works with p5.js, Three.js, WebGL, Canvas, and any other rendering library.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@hypertool/sdk)
|
|
6
|
+
[](https://www.npmjs.com/package/@hypertool/sdk)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Framework-agnostic** - Works with p5.js, Three.js, vanilla Canvas, WebGL, or any rendering library
|
|
12
|
+
- **Reactive parameters** - Define control parameters that automatically trigger updates
|
|
13
|
+
- **Video & image capture** - Built-in recording with MediaRecorder and canvas capture
|
|
14
|
+
- **Timeline animations** - Keyframe-based animation system with easing functions
|
|
15
|
+
- **React integration** - Optional React hooks and components
|
|
16
|
+
- **TypeScript first** - Full type definitions included
|
|
17
|
+
- **Zero dependencies** - Core SDK has no runtime dependencies
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# npm
|
|
23
|
+
npm install @hypertool/sdk
|
|
24
|
+
|
|
25
|
+
# yarn
|
|
26
|
+
yarn add @hypertool/sdk
|
|
27
|
+
|
|
28
|
+
# pnpm
|
|
29
|
+
pnpm add @hypertool/sdk
|
|
30
|
+
|
|
31
|
+
# bun
|
|
32
|
+
bun add @hypertool/sdk
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
### Basic Usage
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { Experience } from '@hypertool/sdk';
|
|
41
|
+
|
|
42
|
+
const experience = new Experience({
|
|
43
|
+
mount: document.getElementById('canvas-container'),
|
|
44
|
+
paramDefs: {
|
|
45
|
+
color: { type: 'color', value: '#ff0000', label: 'Color' },
|
|
46
|
+
speed: { type: 'number', value: 5, min: 1, max: 10, label: 'Speed' },
|
|
47
|
+
showGrid: { type: 'boolean', value: true, label: 'Show Grid' },
|
|
48
|
+
},
|
|
49
|
+
setup(context) {
|
|
50
|
+
const canvas = document.createElement('canvas');
|
|
51
|
+
const ctx = canvas.getContext('2d');
|
|
52
|
+
canvas.width = 800;
|
|
53
|
+
canvas.height = 600;
|
|
54
|
+
context.mount.appendChild(canvas);
|
|
55
|
+
|
|
56
|
+
// Access reactive parameters
|
|
57
|
+
console.log(context.params.color); // '#ff0000'
|
|
58
|
+
console.log(context.params.speed); // 5
|
|
59
|
+
console.log(context.params.showGrid); // true
|
|
60
|
+
|
|
61
|
+
// Draw loop
|
|
62
|
+
function draw() {
|
|
63
|
+
ctx.fillStyle = context.params.color;
|
|
64
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Listen to frame events
|
|
68
|
+
context.experience.on('frame', draw);
|
|
69
|
+
|
|
70
|
+
// Return cleanup function
|
|
71
|
+
return () => {
|
|
72
|
+
canvas.remove();
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Control playback
|
|
78
|
+
experience.play();
|
|
79
|
+
experience.pause();
|
|
80
|
+
|
|
81
|
+
// Update parameters programmatically
|
|
82
|
+
experience.setParam('color', '#00ff00');
|
|
83
|
+
experience.setParams({ speed: 8, showGrid: false });
|
|
84
|
+
|
|
85
|
+
// Capture images
|
|
86
|
+
const blob = await experience.captureImage('png');
|
|
87
|
+
|
|
88
|
+
// Clean up when done
|
|
89
|
+
experience.destroy();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### With p5.js
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { Experience } from '@hypertool/sdk';
|
|
96
|
+
import p5 from 'p5';
|
|
97
|
+
|
|
98
|
+
new Experience({
|
|
99
|
+
mount: document.getElementById('sketch'),
|
|
100
|
+
paramDefs: {
|
|
101
|
+
backgroundColor: { type: 'color', value: '#1a1a2e' },
|
|
102
|
+
circleCount: { type: 'number', value: 10, min: 1, max: 50 },
|
|
103
|
+
animate: { type: 'boolean', value: true },
|
|
104
|
+
},
|
|
105
|
+
setup(context) {
|
|
106
|
+
let sketch;
|
|
107
|
+
|
|
108
|
+
new p5((p) => {
|
|
109
|
+
sketch = p;
|
|
110
|
+
|
|
111
|
+
p.setup = () => {
|
|
112
|
+
p.createCanvas(800, 600);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
p.draw = () => {
|
|
116
|
+
if (!context.params.animate) return;
|
|
117
|
+
|
|
118
|
+
p.background(context.params.backgroundColor);
|
|
119
|
+
|
|
120
|
+
for (let i = 0; i < context.params.circleCount; i++) {
|
|
121
|
+
p.circle(
|
|
122
|
+
p.random(p.width),
|
|
123
|
+
p.random(p.height),
|
|
124
|
+
p.random(20, 50)
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}, context.mount);
|
|
129
|
+
|
|
130
|
+
return () => sketch?.remove();
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### With Three.js
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { Experience } from '@hypertool/sdk';
|
|
139
|
+
import * as THREE from 'three';
|
|
140
|
+
|
|
141
|
+
new Experience({
|
|
142
|
+
mount: document.getElementById('scene'),
|
|
143
|
+
paramDefs: {
|
|
144
|
+
rotationSpeed: { type: 'number', value: 0.01, min: 0, max: 0.1, step: 0.001 },
|
|
145
|
+
cubeColor: { type: 'color', value: '#00ff88' },
|
|
146
|
+
wireframe: { type: 'boolean', value: false },
|
|
147
|
+
},
|
|
148
|
+
setup(context) {
|
|
149
|
+
const scene = new THREE.Scene();
|
|
150
|
+
const camera = new THREE.PerspectiveCamera(75, 800 / 600, 0.1, 1000);
|
|
151
|
+
const renderer = new THREE.WebGLRenderer();
|
|
152
|
+
|
|
153
|
+
renderer.setSize(800, 600);
|
|
154
|
+
context.mount.appendChild(renderer.domElement);
|
|
155
|
+
|
|
156
|
+
const geometry = new THREE.BoxGeometry();
|
|
157
|
+
const material = new THREE.MeshBasicMaterial({
|
|
158
|
+
color: context.params.cubeColor,
|
|
159
|
+
wireframe: context.params.wireframe,
|
|
160
|
+
});
|
|
161
|
+
const cube = new THREE.Mesh(geometry, material);
|
|
162
|
+
scene.add(cube);
|
|
163
|
+
|
|
164
|
+
camera.position.z = 5;
|
|
165
|
+
|
|
166
|
+
// Register object for external access
|
|
167
|
+
context.registerObject('mainCube', cube);
|
|
168
|
+
|
|
169
|
+
// Animation loop
|
|
170
|
+
context.experience.on('frame', () => {
|
|
171
|
+
cube.rotation.x += context.params.rotationSpeed;
|
|
172
|
+
cube.rotation.y += context.params.rotationSpeed;
|
|
173
|
+
material.color.set(context.params.cubeColor);
|
|
174
|
+
material.wireframe = context.params.wireframe;
|
|
175
|
+
renderer.render(scene, camera);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
return () => {
|
|
179
|
+
renderer.dispose();
|
|
180
|
+
geometry.dispose();
|
|
181
|
+
material.dispose();
|
|
182
|
+
};
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Entry Points
|
|
188
|
+
|
|
189
|
+
The SDK is modular - import only what you need:
|
|
190
|
+
|
|
191
|
+
| Entry | Purpose |
|
|
192
|
+
|-------|---------|
|
|
193
|
+
| `@hypertool/sdk` | Core Experience class + utilities |
|
|
194
|
+
| `@hypertool/sdk/controls` | Tweakpane-based control panel (requires `tweakpane` peer dep) |
|
|
195
|
+
| `@hypertool/sdk/recording` | Video/image capture & timeline |
|
|
196
|
+
| `@hypertool/sdk/react` | React hooks & components (requires `react` peer dep) |
|
|
197
|
+
| `@hypertool/sdk/capture` | Low-level capture utilities |
|
|
198
|
+
|
|
199
|
+
## API Reference
|
|
200
|
+
|
|
201
|
+
### Experience
|
|
202
|
+
|
|
203
|
+
The main class for creating interactive experiences.
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
interface ExperienceConfig {
|
|
207
|
+
mount: HTMLElement; // Container element
|
|
208
|
+
paramDefs?: ParamDefinitions; // Parameter schema
|
|
209
|
+
initialParams?: Record<string, unknown>; // Override defaults
|
|
210
|
+
setup: SetupFunction; // Your code
|
|
211
|
+
autoplay?: boolean; // Start immediately (default: true)
|
|
212
|
+
frameRate?: number; // Target FPS (default: 60)
|
|
213
|
+
background?: string; // CSS background
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### Methods
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
// Playback
|
|
221
|
+
experience.play();
|
|
222
|
+
experience.pause();
|
|
223
|
+
experience.toggle();
|
|
224
|
+
|
|
225
|
+
// Parameters
|
|
226
|
+
experience.setParam('key', value);
|
|
227
|
+
experience.setParams({ key1: value1, key2: value2 });
|
|
228
|
+
experience.getParams(); // Get all current values
|
|
229
|
+
experience.resetParams(); // Reset to defaults
|
|
230
|
+
|
|
231
|
+
// Object registry (Spline-like API)
|
|
232
|
+
experience.registerObject('name', object, metadata);
|
|
233
|
+
experience.findObjectByName('name');
|
|
234
|
+
experience.findObjectById('id');
|
|
235
|
+
experience.getAllObjects();
|
|
236
|
+
|
|
237
|
+
// Events
|
|
238
|
+
experience.on('ready', () => {});
|
|
239
|
+
experience.on('frame', ({ frame, deltaTime }) => {});
|
|
240
|
+
experience.on('paramChange', ({ key, value, previousValue }) => {});
|
|
241
|
+
experience.on('resize', ({ width, height }) => {});
|
|
242
|
+
experience.on('error', ({ error }) => {});
|
|
243
|
+
experience.once('ready', () => {});
|
|
244
|
+
experience.off('ready', handler);
|
|
245
|
+
|
|
246
|
+
// Capture
|
|
247
|
+
const blob = await experience.captureImage('png');
|
|
248
|
+
|
|
249
|
+
// Cleanup
|
|
250
|
+
experience.destroy();
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### Properties
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
experience.isReady; // boolean
|
|
257
|
+
experience.isPlaying; // boolean
|
|
258
|
+
experience.isDestroyed; // boolean
|
|
259
|
+
experience.currentFrame; // number
|
|
260
|
+
experience.params; // Reactive proxy
|
|
261
|
+
experience.mount; // HTMLElement
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Parameter Types
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
// Number
|
|
268
|
+
{ type: 'number', value: 5, min: 0, max: 10, step: 0.1, label: 'Speed' }
|
|
269
|
+
|
|
270
|
+
// Color
|
|
271
|
+
{ type: 'color', value: '#ff0000', label: 'Background' }
|
|
272
|
+
|
|
273
|
+
// Boolean
|
|
274
|
+
{ type: 'boolean', value: true, label: 'Show Grid' }
|
|
275
|
+
|
|
276
|
+
// String
|
|
277
|
+
{ type: 'string', value: 'hello', label: 'Text' }
|
|
278
|
+
|
|
279
|
+
// Select
|
|
280
|
+
{ type: 'select', value: 'option1', options: [
|
|
281
|
+
{ label: 'Option 1', value: 'option1' },
|
|
282
|
+
{ label: 'Option 2', value: 'option2' },
|
|
283
|
+
], label: 'Mode' }
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Recording Module
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import { VideoRecorder, ImageCapture, Timeline } from '@hypertool/sdk/recording';
|
|
290
|
+
|
|
291
|
+
// Video recording
|
|
292
|
+
const recorder = VideoRecorder.start(canvas, {
|
|
293
|
+
format: 'webm', // 'webm' | 'mp4'
|
|
294
|
+
quality: 0.9, // 0-1
|
|
295
|
+
frameRate: 60, // FPS
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// Later...
|
|
299
|
+
const videoBlob = await recorder.stop();
|
|
300
|
+
|
|
301
|
+
// Image capture
|
|
302
|
+
const imageBlob = await ImageCapture.capture(canvas, 'png');
|
|
303
|
+
|
|
304
|
+
// Timeline animation
|
|
305
|
+
const timeline = new Timeline({
|
|
306
|
+
loop: true,
|
|
307
|
+
duration: 5000, // 5 seconds
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
timeline
|
|
311
|
+
.addKeyframe(0, { opacity: 0, scale: 0.5 })
|
|
312
|
+
.addKeyframe(1000, { opacity: 1, scale: 1 }, 'easeOutBack')
|
|
313
|
+
.addKeyframe(4000, { opacity: 1, scale: 1 })
|
|
314
|
+
.addKeyframe(5000, { opacity: 0, scale: 0.5 }, 'easeInQuad');
|
|
315
|
+
|
|
316
|
+
timeline.onUpdate((params) => {
|
|
317
|
+
experience.setParams(params);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
timeline.play();
|
|
321
|
+
timeline.pause();
|
|
322
|
+
timeline.seek(2500); // Jump to 2.5s
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### React Integration
|
|
326
|
+
|
|
327
|
+
```tsx
|
|
328
|
+
import { useExperience, ExperienceView } from '@hypertool/sdk/react';
|
|
329
|
+
|
|
330
|
+
function MyVisualization() {
|
|
331
|
+
const {
|
|
332
|
+
experience,
|
|
333
|
+
isReady,
|
|
334
|
+
isPlaying,
|
|
335
|
+
params,
|
|
336
|
+
setParam,
|
|
337
|
+
play,
|
|
338
|
+
pause,
|
|
339
|
+
toggle,
|
|
340
|
+
} = useExperience({
|
|
341
|
+
paramDefs: {
|
|
342
|
+
color: { type: 'color', value: '#ff0000' },
|
|
343
|
+
speed: { type: 'number', value: 5, min: 1, max: 10 },
|
|
344
|
+
},
|
|
345
|
+
setup(context) {
|
|
346
|
+
// Your setup code
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
return (
|
|
351
|
+
<div>
|
|
352
|
+
<ExperienceView
|
|
353
|
+
experience={experience}
|
|
354
|
+
className="w-full h-96"
|
|
355
|
+
/>
|
|
356
|
+
|
|
357
|
+
<div className="controls">
|
|
358
|
+
<button onClick={toggle}>
|
|
359
|
+
{isPlaying ? 'Pause' : 'Play'}
|
|
360
|
+
</button>
|
|
361
|
+
|
|
362
|
+
<input
|
|
363
|
+
type="color"
|
|
364
|
+
value={params.color}
|
|
365
|
+
onChange={(e) => setParam('color', e.target.value)}
|
|
366
|
+
/>
|
|
367
|
+
|
|
368
|
+
<input
|
|
369
|
+
type="range"
|
|
370
|
+
min={1}
|
|
371
|
+
max={10}
|
|
372
|
+
value={params.speed}
|
|
373
|
+
onChange={(e) => setParam('speed', Number(e.target.value))}
|
|
374
|
+
/>
|
|
375
|
+
</div>
|
|
376
|
+
</div>
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Controls Module (Tweakpane)
|
|
382
|
+
|
|
383
|
+
Add a visual control panel with Tweakpane:
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
import { HypertoolControls } from '@hypertool/sdk/controls';
|
|
387
|
+
|
|
388
|
+
const controls = new HypertoolControls({
|
|
389
|
+
container: document.getElementById('controls'),
|
|
390
|
+
definitions: {
|
|
391
|
+
color: { type: 'color', value: '#ff0000' },
|
|
392
|
+
speed: { type: 'number', value: 5, min: 1, max: 10 },
|
|
393
|
+
},
|
|
394
|
+
onChange: (key, value) => {
|
|
395
|
+
console.log(`${key} changed to ${value}`);
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// Programmatic updates
|
|
400
|
+
controls.set('color', '#00ff00');
|
|
401
|
+
controls.refresh();
|
|
402
|
+
controls.dispose();
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Examples
|
|
406
|
+
|
|
407
|
+
See the `/examples` directory for complete working examples:
|
|
408
|
+
|
|
409
|
+
- `examples/vanilla-canvas/` - Pure Canvas API
|
|
410
|
+
- `examples/p5js/` - p5.js sketch
|
|
411
|
+
- `examples/threejs/` - Three.js scene
|
|
412
|
+
- `examples/react/` - React integration
|
|
413
|
+
- `examples/recording/` - Video capture & timeline
|
|
414
|
+
|
|
415
|
+
## Browser Support
|
|
416
|
+
|
|
417
|
+
- Chrome 80+
|
|
418
|
+
- Firefox 78+
|
|
419
|
+
- Safari 14+
|
|
420
|
+
- Edge 80+
|
|
421
|
+
|
|
422
|
+
## TypeScript
|
|
423
|
+
|
|
424
|
+
Full TypeScript support with type definitions included.
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
import type {
|
|
428
|
+
Experience,
|
|
429
|
+
ExperienceConfig,
|
|
430
|
+
ExperienceContext,
|
|
431
|
+
ParamDefinitions,
|
|
432
|
+
ParamValues,
|
|
433
|
+
ExperienceEvent,
|
|
434
|
+
} from '@hypertool/sdk';
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## Contributing
|
|
438
|
+
|
|
439
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
440
|
+
|
|
441
|
+
## License
|
|
442
|
+
|
|
443
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CaptureManager - Rendering-target agnostic capture system
|
|
3
|
+
*
|
|
4
|
+
* Supports capturing from ANY rendering target:
|
|
5
|
+
* - Canvas (2D, WebGL, WebGPU)
|
|
6
|
+
* - SVG elements
|
|
7
|
+
* - HTML elements (via html2canvas-like approach)
|
|
8
|
+
* - Custom targets via handlers
|
|
9
|
+
*/
|
|
10
|
+
import type { CaptureFormat, CaptureResult, CaptureHandler, CaptureConfig } from './types';
|
|
11
|
+
export declare class CaptureManager {
|
|
12
|
+
private config;
|
|
13
|
+
private customHandler;
|
|
14
|
+
constructor(config?: CaptureConfig);
|
|
15
|
+
/**
|
|
16
|
+
* Register a custom capture handler
|
|
17
|
+
* Use this to support any rendering target
|
|
18
|
+
*/
|
|
19
|
+
registerHandler(handler: CaptureHandler): void;
|
|
20
|
+
/**
|
|
21
|
+
* Capture image from the render target
|
|
22
|
+
*/
|
|
23
|
+
capture(container: HTMLElement, format?: CaptureFormat): Promise<CaptureResult | null>;
|
|
24
|
+
/**
|
|
25
|
+
* Find the render target in a container
|
|
26
|
+
* Priority: custom selector > canvas > svg > container itself
|
|
27
|
+
*/
|
|
28
|
+
private findRenderTarget;
|
|
29
|
+
/**
|
|
30
|
+
* Detect the type of an element
|
|
31
|
+
*/
|
|
32
|
+
private detectType;
|
|
33
|
+
/**
|
|
34
|
+
* Capture from canvas element
|
|
35
|
+
*/
|
|
36
|
+
private captureCanvas;
|
|
37
|
+
/**
|
|
38
|
+
* Capture from SVG element
|
|
39
|
+
*/
|
|
40
|
+
private captureSvg;
|
|
41
|
+
/**
|
|
42
|
+
* Convert SVG to raster image via canvas
|
|
43
|
+
*/
|
|
44
|
+
private svgToRaster;
|
|
45
|
+
/**
|
|
46
|
+
* Capture from HTML element
|
|
47
|
+
* Uses a simple approach - for complex HTML, consider html2canvas
|
|
48
|
+
*/
|
|
49
|
+
private captureHtml;
|
|
50
|
+
/**
|
|
51
|
+
* Get MIME type for format
|
|
52
|
+
*/
|
|
53
|
+
private getMimeType;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=CaptureManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CaptureManager.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,cAAc,EACd,aAAa,EAEd,MAAM,SAAS,CAAC;AAEjB,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,aAAa,CAA+B;gBAExC,MAAM,GAAE,aAAkB;IAYtC;;;OAGG;IACH,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAI9C;;OAEG;IACG,OAAO,CACX,SAAS,EAAE,WAAW,EACtB,MAAM,GAAE,aAAkD,GACzD,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IA4BhC;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA8BxB;;OAEG;IACH,OAAO,CAAC,UAAU;IAMlB;;OAEG;YACW,aAAa;IA2B3B;;OAEG;YACW,UAAU;IAsBxB;;OAEG;YACW,WAAW;IAwCzB;;;OAGG;YACW,WAAW;IAwDzB;;OAEG;IACH,OAAO,CAAC,WAAW;CAcpB"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture module - rendering-target agnostic capture system
|
|
3
|
+
*
|
|
4
|
+
* This module provides a flexible capture system that works with ANY rendering target:
|
|
5
|
+
* - Canvas (2D, WebGL, WebGPU)
|
|
6
|
+
* - SVG elements
|
|
7
|
+
* - HTML elements
|
|
8
|
+
* - Custom targets via handlers
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { CaptureManager } from '@hypertool/sdk/capture';
|
|
13
|
+
*
|
|
14
|
+
* // Auto-detect render target
|
|
15
|
+
* const capture = new CaptureManager();
|
|
16
|
+
* const result = await capture.capture(container, 'png');
|
|
17
|
+
*
|
|
18
|
+
* // Custom handler for complex scenarios
|
|
19
|
+
* capture.registerHandler(async (format) => {
|
|
20
|
+
* // Your custom capture logic
|
|
21
|
+
* return { blob, width, height, format };
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export { CaptureManager } from './CaptureManager';
|
|
26
|
+
export type { CaptureFormat, VideoFormat, CaptureResult, VideoCaptureResult, CaptureHandler, VideoCaptureHandler, RenderTargetType, CaptureConfig, } from './types';
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capture/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EACV,aAAa,EACb,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,GACd,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class G{config;customHandler=null;constructor(p={}){if(this.config={defaultFormat:"png",quality:0.92,...p},p.customHandler)this.customHandler=p.customHandler}registerHandler(p){this.customHandler=p}async capture(p,u=this.config.defaultFormat||"png"){if(this.customHandler)return this.customHandler(u);let H=this.findRenderTarget(p);if(!H)return console.warn("[CaptureManager] No render target found in container"),null;let{element:C,type:V}=H;switch(V){case"canvas":return this.captureCanvas(C,u);case"svg":return this.captureSvg(C,u);case"html":return this.captureHtml(C,u);default:return console.warn("[CaptureManager] Unknown render target type:",V),null}}findRenderTarget(p){if(this.config.targetSelector){let C=p.querySelector(this.config.targetSelector);if(C)return{element:C,type:this.config.targetType||this.detectType(C)}}let u=p.querySelector("canvas");if(u)return{element:u,type:"canvas"};let H=p.querySelector("svg");if(H)return{element:H,type:"svg"};return{element:p,type:"html"}}detectType(p){if(p instanceof HTMLCanvasElement)return"canvas";if(p instanceof SVGSVGElement)return"svg";return"html"}async captureCanvas(p,u){let H=this.getMimeType(u),C=u==="jpeg"?this.config.quality:void 0;return new Promise((V)=>{p.toBlob((d)=>{if(!d){V(null);return}V({blob:d,width:p.width,height:p.height,format:u})},H,C)})}async captureSvg(p,u){if(u==="svg"){let C=new XMLSerializer().serializeToString(p),V=new Blob([C],{type:"image/svg+xml"}),d=p.getBBox();return{blob:V,width:d.width||p.clientWidth,height:d.height||p.clientHeight,format:"svg"}}return this.svgToRaster(p,u)}async svgToRaster(p,u){let C=new XMLSerializer().serializeToString(p),V=new Blob([C],{type:"image/svg+xml;charset=utf-8"}),d=URL.createObjectURL(V),R=new Image;return R.src=d,new Promise((A)=>{R.onload=()=>{URL.revokeObjectURL(d);let k=document.createElement("canvas"),y=p.clientWidth||R.width,T=p.clientHeight||R.height;k.width=y,k.height=T;let F=k.getContext("2d");if(!F){A(null);return}F.drawImage(R,0,0,y,T),this.captureCanvas(k,u).then(A)},R.onerror=()=>{URL.revokeObjectURL(d),A(null)}})}async captureHtml(p,u){let H=p,C=H.offsetWidth,V=H.offsetHeight,d=document.createElement("canvas");d.width=C,d.height=V;let R=d.getContext("2d");if(!R)return null;let A=`
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="${C}" height="${V}">
|
|
3
|
+
<foreignObject width="100%" height="100%">
|
|
4
|
+
<div xmlns="http://www.w3.org/1999/xhtml">
|
|
5
|
+
${H.outerHTML}
|
|
6
|
+
</div>
|
|
7
|
+
</foreignObject>
|
|
8
|
+
</svg>
|
|
9
|
+
`,k=new Blob([A],{type:"image/svg+xml;charset=utf-8"}),y=URL.createObjectURL(k),T=new Image;return T.src=y,new Promise((F)=>{T.onload=()=>{URL.revokeObjectURL(y),R.drawImage(T,0,0),this.captureCanvas(d,u).then(F)},T.onerror=()=>{URL.revokeObjectURL(y),console.warn("[CaptureManager] HTML capture failed. Consider using a custom capture handler."),F(null)}})}getMimeType(p){switch(p){case"png":return"image/png";case"jpeg":return"image/jpeg";case"webp":return"image/webp";case"svg":return"image/svg+xml";default:return"image/png"}}}export{G as CaptureManager};
|
|
10
|
+
|
|
11
|
+
//# debugId=5A7F3124CCD112A664756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/capture/CaptureManager.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * CaptureManager - Rendering-target agnostic capture system\n *\n * Supports capturing from ANY rendering target:\n * - Canvas (2D, WebGL, WebGPU)\n * - SVG elements\n * - HTML elements (via html2canvas-like approach)\n * - Custom targets via handlers\n */\n\nimport type {\n CaptureFormat,\n CaptureResult,\n CaptureHandler,\n CaptureConfig,\n RenderTargetType,\n} from './types';\n\nexport class CaptureManager {\n private config: CaptureConfig;\n private customHandler: CaptureHandler | null = null;\n\n constructor(config: CaptureConfig = {}) {\n this.config = {\n defaultFormat: 'png',\n quality: 0.92,\n ...config,\n };\n\n if (config.customHandler) {\n this.customHandler = config.customHandler;\n }\n }\n\n /**\n * Register a custom capture handler\n * Use this to support any rendering target\n */\n registerHandler(handler: CaptureHandler): void {\n this.customHandler = handler;\n }\n\n /**\n * Capture image from the render target\n */\n async capture(\n container: HTMLElement,\n format: CaptureFormat = this.config.defaultFormat || 'png'\n ): Promise<CaptureResult | null> {\n // Use custom handler if registered\n if (this.customHandler) {\n return this.customHandler(format);\n }\n\n // Auto-detect render target\n const target = this.findRenderTarget(container);\n if (!target) {\n console.warn('[CaptureManager] No render target found in container');\n return null;\n }\n\n const { element, type } = target;\n\n switch (type) {\n case 'canvas':\n return this.captureCanvas(element as HTMLCanvasElement, format);\n case 'svg':\n return this.captureSvg(element as SVGSVGElement, format);\n case 'html':\n return this.captureHtml(element, format);\n default:\n console.warn('[CaptureManager] Unknown render target type:', type);\n return null;\n }\n }\n\n /**\n * Find the render target in a container\n * Priority: custom selector > canvas > svg > container itself\n */\n private findRenderTarget(\n container: HTMLElement\n ): { element: Element; type: RenderTargetType } | null {\n // Use custom selector if specified\n if (this.config.targetSelector) {\n const element = container.querySelector(this.config.targetSelector);\n if (element) {\n return {\n element,\n type: this.config.targetType || this.detectType(element),\n };\n }\n }\n\n // Auto-detect: canvas first\n const canvas = container.querySelector('canvas');\n if (canvas) {\n return { element: canvas, type: 'canvas' };\n }\n\n // Then SVG\n const svg = container.querySelector('svg');\n if (svg) {\n return { element: svg, type: 'svg' };\n }\n\n // Fall back to the container itself (HTML capture)\n return { element: container, type: 'html' };\n }\n\n /**\n * Detect the type of an element\n */\n private detectType(element: Element): RenderTargetType {\n if (element instanceof HTMLCanvasElement) return 'canvas';\n if (element instanceof SVGSVGElement) return 'svg';\n return 'html';\n }\n\n /**\n * Capture from canvas element\n */\n private async captureCanvas(\n canvas: HTMLCanvasElement,\n format: CaptureFormat\n ): Promise<CaptureResult | null> {\n const mimeType = this.getMimeType(format);\n const quality = format === 'jpeg' ? this.config.quality : undefined;\n\n return new Promise((resolve) => {\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n resolve(null);\n return;\n }\n resolve({\n blob,\n width: canvas.width,\n height: canvas.height,\n format,\n });\n },\n mimeType,\n quality\n );\n });\n }\n\n /**\n * Capture from SVG element\n */\n private async captureSvg(\n svg: SVGSVGElement,\n format: CaptureFormat\n ): Promise<CaptureResult | null> {\n // For SVG format, return the SVG directly\n if (format === 'svg') {\n const serializer = new XMLSerializer();\n const svgString = serializer.serializeToString(svg);\n const blob = new Blob([svgString], { type: 'image/svg+xml' });\n const bbox = svg.getBBox();\n return {\n blob,\n width: bbox.width || svg.clientWidth,\n height: bbox.height || svg.clientHeight,\n format: 'svg',\n };\n }\n\n // For raster formats, render SVG to canvas first\n return this.svgToRaster(svg, format);\n }\n\n /**\n * Convert SVG to raster image via canvas\n */\n private async svgToRaster(\n svg: SVGSVGElement,\n format: CaptureFormat\n ): Promise<CaptureResult | null> {\n const serializer = new XMLSerializer();\n const svgString = serializer.serializeToString(svg);\n const svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });\n const url = URL.createObjectURL(svgBlob);\n\n const img = new Image();\n img.src = url;\n\n return new Promise((resolve) => {\n img.onload = () => {\n URL.revokeObjectURL(url);\n\n const canvas = document.createElement('canvas');\n const width = svg.clientWidth || img.width;\n const height = svg.clientHeight || img.height;\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n resolve(null);\n return;\n }\n\n ctx.drawImage(img, 0, 0, width, height);\n\n this.captureCanvas(canvas, format).then(resolve);\n };\n\n img.onerror = () => {\n URL.revokeObjectURL(url);\n resolve(null);\n };\n });\n }\n\n /**\n * Capture from HTML element\n * Uses a simple approach - for complex HTML, consider html2canvas\n */\n private async captureHtml(\n element: Element,\n format: CaptureFormat\n ): Promise<CaptureResult | null> {\n // Simple approach: use browser's native rendering\n // For production, you might want to use html2canvas or similar\n\n const htmlElement = element as HTMLElement;\n const width = htmlElement.offsetWidth;\n const height = htmlElement.offsetHeight;\n\n // Create a canvas and draw the element\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return null;\n }\n\n // Use foreignObject approach\n const svgString = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\">\n <foreignObject width=\"100%\" height=\"100%\">\n <div xmlns=\"http://www.w3.org/1999/xhtml\">\n ${htmlElement.outerHTML}\n </div>\n </foreignObject>\n </svg>\n `;\n\n const svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });\n const url = URL.createObjectURL(svgBlob);\n\n const img = new Image();\n img.src = url;\n\n return new Promise((resolve) => {\n img.onload = () => {\n URL.revokeObjectURL(url);\n ctx.drawImage(img, 0, 0);\n this.captureCanvas(canvas, format).then(resolve);\n };\n\n img.onerror = () => {\n URL.revokeObjectURL(url);\n // Fallback: return null, user should use custom handler for complex HTML\n console.warn(\n '[CaptureManager] HTML capture failed. Consider using a custom capture handler.'\n );\n resolve(null);\n };\n });\n }\n\n /**\n * Get MIME type for format\n */\n private getMimeType(format: CaptureFormat): string {\n switch (format) {\n case 'png':\n return 'image/png';\n case 'jpeg':\n return 'image/jpeg';\n case 'webp':\n return 'image/webp';\n case 'svg':\n return 'image/svg+xml';\n default:\n return 'image/png';\n }\n }\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "5A7F3124CCD112A664756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture types - rendering-target agnostic capture system
|
|
3
|
+
*
|
|
4
|
+
* The capture system supports ANY rendering target:
|
|
5
|
+
* - Canvas (2D, WebGL, WebGPU)
|
|
6
|
+
* - SVG
|
|
7
|
+
* - HTML elements
|
|
8
|
+
* - Custom render targets
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Supported capture formats
|
|
12
|
+
*/
|
|
13
|
+
export type CaptureFormat = 'png' | 'jpeg' | 'webp' | 'svg';
|
|
14
|
+
/**
|
|
15
|
+
* Supported video formats
|
|
16
|
+
*/
|
|
17
|
+
export type VideoFormat = 'webm' | 'mp4';
|
|
18
|
+
/**
|
|
19
|
+
* Capture result from any render target
|
|
20
|
+
*/
|
|
21
|
+
export interface CaptureResult {
|
|
22
|
+
/** The captured image as Blob */
|
|
23
|
+
blob: Blob;
|
|
24
|
+
/** Image width */
|
|
25
|
+
width: number;
|
|
26
|
+
/** Image height */
|
|
27
|
+
height: number;
|
|
28
|
+
/** Format used */
|
|
29
|
+
format: CaptureFormat;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Video capture result
|
|
33
|
+
*/
|
|
34
|
+
export interface VideoCaptureResult {
|
|
35
|
+
/** The captured video as Blob */
|
|
36
|
+
blob: Blob;
|
|
37
|
+
/** Video duration in seconds */
|
|
38
|
+
duration: number;
|
|
39
|
+
/** Format used */
|
|
40
|
+
format: VideoFormat;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Custom capture handler function
|
|
44
|
+
* Implement this to support any rendering target (canvas, SVG, HTML, etc.)
|
|
45
|
+
*/
|
|
46
|
+
export type CaptureHandler = (format: CaptureFormat) => Promise<CaptureResult | null>;
|
|
47
|
+
/**
|
|
48
|
+
* Custom video capture handler function
|
|
49
|
+
*/
|
|
50
|
+
export type VideoCaptureHandler = () => {
|
|
51
|
+
start: () => void;
|
|
52
|
+
stop: () => Promise<VideoCaptureResult>;
|
|
53
|
+
cancel: () => void;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Render target types supported out of the box
|
|
57
|
+
*/
|
|
58
|
+
export type RenderTargetType = 'canvas' | 'svg' | 'html' | 'custom';
|
|
59
|
+
/**
|
|
60
|
+
* Configuration for automatic capture target detection
|
|
61
|
+
*/
|
|
62
|
+
export interface CaptureConfig {
|
|
63
|
+
/** Preferred render target type (auto-detected if not specified) */
|
|
64
|
+
targetType?: RenderTargetType;
|
|
65
|
+
/** Custom CSS selector to find the render target */
|
|
66
|
+
targetSelector?: string;
|
|
67
|
+
/** Custom capture handler (overrides automatic detection) */
|
|
68
|
+
customHandler?: CaptureHandler;
|
|
69
|
+
/** Default filename for exports */
|
|
70
|
+
filename?: string;
|
|
71
|
+
/** Default format for image capture */
|
|
72
|
+
defaultFormat?: CaptureFormat;
|
|
73
|
+
/** Quality for JPEG/WebP (0-1) */
|
|
74
|
+
quality?: number;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/capture/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,IAAI,EAAE,IAAI,CAAC;IACX,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB;IAClB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,iCAAiC;IACjC,IAAI,EAAE,IAAI,CAAC;IACX,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB;IAClB,MAAM,EAAE,WAAW,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;AAEtF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM;IACtC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACxC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAE9B,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,6DAA6D;IAC7D,aAAa,CAAC,EAAE,cAAc,CAAC;IAE/B,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,uCAAuC;IACvC,aAAa,CAAC,EAAE,aAAa,CAAC;IAE9B,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|