@hypertools/sdk 0.3.2 → 0.4.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.
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Vanilla Canvas Example
3
+ *
4
+ * Demonstrates basic usage of @hypertools/sdk with the Canvas API.
5
+ * Creates an animated particle system with reactive parameters.
6
+ */
7
+
8
+ import { Experience } from '@hypertools/sdk';
9
+
10
+ interface Particle {
11
+ x: number;
12
+ y: number;
13
+ vx: number;
14
+ vy: number;
15
+ radius: number;
16
+ life: number;
17
+ }
18
+
19
+ const experience = new Experience({
20
+ mount: document.getElementById('canvas-container')!,
21
+ paramDefs: {
22
+ color: { type: 'color', value: '#00ff88', label: 'Particle Color' },
23
+ speed: { type: 'number', value: 5, min: 1, max: 20, label: 'Speed' },
24
+ showTrails: { type: 'boolean', value: true, label: 'Show Trails' },
25
+ },
26
+ setup(context) {
27
+ // Create canvas
28
+ const canvas = document.createElement('canvas');
29
+ const ctx = canvas.getContext('2d')!;
30
+ canvas.width = 800;
31
+ canvas.height = 600;
32
+ context.mount.appendChild(canvas);
33
+
34
+ // Particle system state
35
+ const particles: Particle[] = [];
36
+ let mouseX = canvas.width / 2;
37
+ let mouseY = canvas.height / 2;
38
+
39
+ // Track mouse position
40
+ canvas.addEventListener('mousemove', (e) => {
41
+ const rect = canvas.getBoundingClientRect();
42
+ mouseX = e.clientX - rect.left;
43
+ mouseY = e.clientY - rect.top;
44
+ });
45
+
46
+ // Spawn particles
47
+ function spawnParticle() {
48
+ const angle = Math.random() * Math.PI * 2;
49
+ const speed = context.params.speed as number;
50
+
51
+ particles.push({
52
+ x: mouseX,
53
+ y: mouseY,
54
+ vx: Math.cos(angle) * speed * (0.5 + Math.random()),
55
+ vy: Math.sin(angle) * speed * (0.5 + Math.random()),
56
+ radius: 3 + Math.random() * 5,
57
+ life: 1,
58
+ });
59
+ }
60
+
61
+ // Draw frame
62
+ function draw() {
63
+ // Clear or fade based on trails setting
64
+ if (context.params.showTrails) {
65
+ ctx.fillStyle = 'rgba(26, 26, 46, 0.1)';
66
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
67
+ } else {
68
+ ctx.fillStyle = '#1a1a2e';
69
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
70
+ }
71
+
72
+ // Spawn new particles
73
+ for (let i = 0; i < 3; i++) {
74
+ spawnParticle();
75
+ }
76
+
77
+ // Update and draw particles
78
+ const color = context.params.color as string;
79
+
80
+ for (let i = particles.length - 1; i >= 0; i--) {
81
+ const p = particles[i];
82
+
83
+ // Update position
84
+ p.x += p.vx;
85
+ p.y += p.vy;
86
+ p.life -= 0.01;
87
+
88
+ // Remove dead particles
89
+ if (p.life <= 0) {
90
+ particles.splice(i, 1);
91
+ continue;
92
+ }
93
+
94
+ // Draw particle
95
+ ctx.beginPath();
96
+ ctx.arc(p.x, p.y, p.radius * p.life, 0, Math.PI * 2);
97
+ ctx.fillStyle = color + Math.floor(p.life * 255).toString(16).padStart(2, '0');
98
+ ctx.fill();
99
+ }
100
+
101
+ // Draw particle count
102
+ ctx.fillStyle = '#fff';
103
+ ctx.font = '14px monospace';
104
+ ctx.fillText(`Particles: ${particles.length}`, 10, 20);
105
+ }
106
+
107
+ // Listen to frame events
108
+ context.experience.on('frame', draw);
109
+
110
+ // Initial draw
111
+ draw();
112
+
113
+ // Cleanup
114
+ return () => {
115
+ canvas.remove();
116
+ particles.length = 0;
117
+ };
118
+ },
119
+ });
120
+
121
+ // Wire up UI controls
122
+ const toggleBtn = document.getElementById('toggle') as HTMLButtonElement;
123
+ const captureBtn = document.getElementById('capture') as HTMLButtonElement;
124
+ const colorInput = document.getElementById('color') as HTMLInputElement;
125
+ const speedInput = document.getElementById('speed') as HTMLInputElement;
126
+ const trailsInput = document.getElementById('showTrails') as HTMLInputElement;
127
+
128
+ toggleBtn.addEventListener('click', () => {
129
+ experience.toggle();
130
+ toggleBtn.textContent = experience.isPlaying ? 'Pause' : 'Play';
131
+ });
132
+
133
+ captureBtn.addEventListener('click', async () => {
134
+ const blob = await experience.captureImage('png');
135
+ if (blob) {
136
+ const url = URL.createObjectURL(blob);
137
+ const a = document.createElement('a');
138
+ a.href = url;
139
+ a.download = 'capture.png';
140
+ a.click();
141
+ URL.revokeObjectURL(url);
142
+ }
143
+ });
144
+
145
+ colorInput.addEventListener('input', (e) => {
146
+ experience.setParam('color', (e.target as HTMLInputElement).value);
147
+ });
148
+
149
+ speedInput.addEventListener('input', (e) => {
150
+ experience.setParam('speed', Number((e.target as HTMLInputElement).value));
151
+ });
152
+
153
+ trailsInput.addEventListener('change', (e) => {
154
+ experience.setParam('showTrails', (e.target as HTMLInputElement).checked);
155
+ });
156
+
157
+ // Sync initial values
158
+ experience.on('ready', () => {
159
+ colorInput.value = experience.params.color as string;
160
+ speedInput.value = String(experience.params.speed);
161
+ trailsInput.checked = experience.params.showTrails as boolean;
162
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypertools/sdk",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "Vanilla-first SDK for embedding interactive creative coding experiences. Supports p5.js, Three.js, WebGL, and more.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -43,6 +43,7 @@
43
43
  "dist/recording",
44
44
  "dist/react",
45
45
  "dist/capture",
46
+ "examples",
46
47
  "README.md",
47
48
  "LICENSE"
48
49
  ],
@@ -158,5 +159,8 @@
158
159
  "react": "^18.3.1",
159
160
  "react-dom": "^18.3.1",
160
161
  "typescript": "^5.6.2"
162
+ },
163
+ "dependencies": {
164
+ "@hypertools/sdk": "0.3.3"
161
165
  }
162
166
  }