@thewhateverapp/tile-sdk 0.13.37 → 0.14.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 (38) hide show
  1. package/dist/scene/SceneContext.d.ts +167 -0
  2. package/dist/scene/SceneContext.d.ts.map +1 -0
  3. package/dist/scene/SceneContext.js +86 -0
  4. package/dist/scene/SceneFromJson.d.ts +27 -0
  5. package/dist/scene/SceneFromJson.d.ts.map +1 -0
  6. package/dist/scene/SceneFromJson.js +74 -0
  7. package/dist/scene/SceneRenderer.d.ts +26 -0
  8. package/dist/scene/SceneRenderer.d.ts.map +1 -0
  9. package/dist/scene/SceneRenderer.js +201 -0
  10. package/dist/scene/camera/CameraController.d.ts +6 -0
  11. package/dist/scene/camera/CameraController.d.ts.map +1 -0
  12. package/dist/scene/camera/CameraController.js +84 -0
  13. package/dist/scene/components/ComponentRunner.d.ts +22 -0
  14. package/dist/scene/components/ComponentRunner.d.ts.map +1 -0
  15. package/dist/scene/components/ComponentRunner.js +197 -0
  16. package/dist/scene/effects/GlowFilter.d.ts +38 -0
  17. package/dist/scene/effects/GlowFilter.d.ts.map +1 -0
  18. package/dist/scene/effects/GlowFilter.js +40 -0
  19. package/dist/scene/effects/ParticleSystem.d.ts +52 -0
  20. package/dist/scene/effects/ParticleSystem.d.ts.map +1 -0
  21. package/dist/scene/effects/ParticleSystem.js +107 -0
  22. package/dist/scene/entities/EntityRenderer.d.ts +14 -0
  23. package/dist/scene/entities/EntityRenderer.d.ts.map +1 -0
  24. package/dist/scene/entities/EntityRenderer.js +203 -0
  25. package/dist/scene/index.d.ts +46 -0
  26. package/dist/scene/index.d.ts.map +1 -0
  27. package/dist/scene/index.js +50 -0
  28. package/dist/scene/input/InputManager.d.ts +18 -0
  29. package/dist/scene/input/InputManager.d.ts.map +1 -0
  30. package/dist/scene/input/InputManager.js +86 -0
  31. package/dist/scene/physics/PhysicsEngine.d.ts +15 -0
  32. package/dist/scene/physics/PhysicsEngine.d.ts.map +1 -0
  33. package/dist/scene/physics/PhysicsEngine.js +252 -0
  34. package/dist/scene/timeline/TimelineExecutor.d.ts +6 -0
  35. package/dist/scene/timeline/TimelineExecutor.d.ts.map +1 -0
  36. package/dist/scene/timeline/TimelineExecutor.js +236 -0
  37. package/dist/spec/schema.d.ts +12 -12
  38. package/package.json +14 -2
@@ -0,0 +1,6 @@
1
+ import type { SceneContextValue } from '../SceneContext';
2
+ /**
3
+ * Hook to execute timeline events
4
+ */
5
+ export declare function useTimelineExecutor(context: SceneContextValue): void;
6
+ //# sourceMappingURL=TimelineExecutor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimelineExecutor.d.ts","sourceRoot":"","sources":["../../../src/scene/timeline/TimelineExecutor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAe,MAAM,iBAAiB,CAAC;AAItE;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,QAsC7D"}
@@ -0,0 +1,236 @@
1
+ 'use client';
2
+ import { useGameLoop } from '../../pixi';
3
+ import { getEasing } from '@thewhateverapp/scene-sdk';
4
+ /**
5
+ * Hook to execute timeline events
6
+ */
7
+ export function useTimelineExecutor(context) {
8
+ const { spec, timeline, entities, camera, emitEvent, spawnEntity, bpm } = context;
9
+ const timelineEvents = spec.timeline ?? [];
10
+ useGameLoop((delta) => {
11
+ const state = timeline.current;
12
+ const elapsedMs = state.elapsedMs;
13
+ const currentBeat = state.currentBeat;
14
+ // Process pending timeline events
15
+ while (state.nextEventIndex < timelineEvents.length) {
16
+ const event = timelineEvents[state.nextEventIndex];
17
+ // Calculate event trigger time
18
+ let triggerTime;
19
+ if (event.atBeat !== undefined) {
20
+ triggerTime = beatToMs(event.atBeat, bpm);
21
+ }
22
+ else if (event.atTimeMs !== undefined) {
23
+ triggerTime = event.atTimeMs;
24
+ }
25
+ else {
26
+ // No timing specified, skip
27
+ state.nextEventIndex++;
28
+ continue;
29
+ }
30
+ // Check if event should fire
31
+ if (elapsedMs >= triggerTime) {
32
+ executeEvent(event, context);
33
+ state.nextEventIndex++;
34
+ }
35
+ else {
36
+ // Events are ordered, so we can stop here
37
+ break;
38
+ }
39
+ }
40
+ // Update active tweens
41
+ updateTweens(state.activeTweens, elapsedMs, context);
42
+ });
43
+ }
44
+ /**
45
+ * Convert beat number to milliseconds
46
+ */
47
+ function beatToMs(beat, bpm) {
48
+ return (beat / (bpm / 60)) * 1000;
49
+ }
50
+ /**
51
+ * Execute a timeline event
52
+ */
53
+ function executeEvent(event, context) {
54
+ const { entities, camera, timeline, emitEvent, spawnEntity } = context;
55
+ switch (event.type) {
56
+ case 'tween': {
57
+ const targetEntity = event.target ? entities.current.get(event.target) : null;
58
+ if (!targetEntity)
59
+ break;
60
+ const params = event.params;
61
+ const startValue = params.from ?? getPropertyValue(targetEntity, params.property);
62
+ const endValue = params.to;
63
+ const duration = params.duration;
64
+ // Add to active tweens
65
+ timeline.current.activeTweens.push({
66
+ targetId: event.target,
67
+ property: params.property,
68
+ startValue,
69
+ endValue,
70
+ startTime: timeline.current.elapsedMs,
71
+ duration,
72
+ easing: params.easing ?? 'linear',
73
+ });
74
+ break;
75
+ }
76
+ case 'pulse': {
77
+ const targetEntity = event.target ? entities.current.get(event.target) : null;
78
+ if (!targetEntity)
79
+ break;
80
+ const params = event.params;
81
+ const originalScale = targetEntity.scaleX;
82
+ const targetScale = params.scale ?? 1.2;
83
+ const duration = params.durationMs ?? (params.durationBeats ? beatToMs(params.durationBeats, context.bpm) : 200);
84
+ // Create scale up tween
85
+ timeline.current.activeTweens.push({
86
+ targetId: event.target,
87
+ property: 'scaleX',
88
+ startValue: originalScale,
89
+ endValue: originalScale * targetScale,
90
+ startTime: timeline.current.elapsedMs,
91
+ duration: duration / 2,
92
+ easing: 'easeOut',
93
+ });
94
+ // Create scale down tween (delayed)
95
+ setTimeout(() => {
96
+ timeline.current.activeTweens.push({
97
+ targetId: event.target,
98
+ property: 'scaleX',
99
+ startValue: originalScale * targetScale,
100
+ endValue: originalScale,
101
+ startTime: timeline.current.elapsedMs,
102
+ duration: duration / 2,
103
+ easing: 'easeIn',
104
+ });
105
+ }, duration / 2);
106
+ break;
107
+ }
108
+ case 'colorSwap': {
109
+ const targetEntity = event.target ? entities.current.get(event.target) : null;
110
+ if (!targetEntity)
111
+ break;
112
+ targetEntity.fill = event.params.to;
113
+ break;
114
+ }
115
+ case 'cameraShake': {
116
+ const params = event.params;
117
+ const duration = params.durationMs ?? (params.durationBeats ? beatToMs(params.durationBeats, context.bpm) : 200);
118
+ camera.current.shakeIntensity = params.strength;
119
+ camera.current.shakeTimeRemaining = duration;
120
+ break;
121
+ }
122
+ case 'spawn': {
123
+ const params = event.params;
124
+ if (params.prefabId) {
125
+ const pos = params.at ?? { x: 0, y: 0 };
126
+ spawnEntity(params.prefabId, pos.x, pos.y);
127
+ }
128
+ break;
129
+ }
130
+ case 'toggle': {
131
+ const targetEntity = event.target ? entities.current.get(event.target) : null;
132
+ if (!targetEntity)
133
+ break;
134
+ const property = event.params.property ?? 'visible';
135
+ if (property === 'visible') {
136
+ targetEntity.visible = event.params.value ?? !targetEntity.visible;
137
+ }
138
+ break;
139
+ }
140
+ case 'set': {
141
+ const targetEntity = event.target ? entities.current.get(event.target) : null;
142
+ if (!targetEntity)
143
+ break;
144
+ setPropertyValue(targetEntity, event.params.path, event.params.value);
145
+ break;
146
+ }
147
+ case 'emit': {
148
+ emitEvent(event.params.event, event.params.payload);
149
+ break;
150
+ }
151
+ }
152
+ }
153
+ /**
154
+ * Update active tweens
155
+ */
156
+ function updateTweens(tweens, elapsedMs, context) {
157
+ const { entities } = context;
158
+ const completedIndices = [];
159
+ for (let i = 0; i < tweens.length; i++) {
160
+ const tween = tweens[i];
161
+ const targetEntity = entities.current.get(tween.targetId);
162
+ if (!targetEntity) {
163
+ completedIndices.push(i);
164
+ continue;
165
+ }
166
+ const elapsed = elapsedMs - tween.startTime;
167
+ const progress = Math.min(elapsed / tween.duration, 1);
168
+ // Apply easing
169
+ const easingFn = getEasing(tween.easing);
170
+ const easedProgress = easingFn ? easingFn(progress) : progress;
171
+ // Interpolate value
172
+ const value = tween.startValue + (tween.endValue - tween.startValue) * easedProgress;
173
+ // Set property
174
+ setPropertyValue(targetEntity, tween.property, value);
175
+ // Check if complete
176
+ if (progress >= 1) {
177
+ completedIndices.push(i);
178
+ }
179
+ }
180
+ // Remove completed tweens (in reverse order to preserve indices)
181
+ for (let i = completedIndices.length - 1; i >= 0; i--) {
182
+ tweens.splice(completedIndices[i], 1);
183
+ }
184
+ }
185
+ /**
186
+ * Get a property value from an entity
187
+ */
188
+ function getPropertyValue(entity, path) {
189
+ switch (path) {
190
+ case 'x':
191
+ return entity.x;
192
+ case 'y':
193
+ return entity.y;
194
+ case 'rotation':
195
+ return entity.rotation;
196
+ case 'scaleX':
197
+ return entity.scaleX;
198
+ case 'scaleY':
199
+ return entity.scaleY;
200
+ case 'alpha':
201
+ return entity.alpha;
202
+ default:
203
+ return 0;
204
+ }
205
+ }
206
+ /**
207
+ * Set a property value on an entity
208
+ */
209
+ function setPropertyValue(entity, path, value) {
210
+ switch (path) {
211
+ case 'x':
212
+ entity.x = value;
213
+ break;
214
+ case 'y':
215
+ entity.y = value;
216
+ break;
217
+ case 'rotation':
218
+ entity.rotation = value;
219
+ break;
220
+ case 'scaleX':
221
+ entity.scaleX = value;
222
+ break;
223
+ case 'scaleY':
224
+ entity.scaleY = value;
225
+ break;
226
+ case 'alpha':
227
+ entity.alpha = value;
228
+ break;
229
+ case 'visible':
230
+ entity.visible = value;
231
+ break;
232
+ case 'fill':
233
+ entity.fill = value;
234
+ break;
235
+ }
236
+ }
@@ -28,10 +28,10 @@ declare const ActionSchema: z.ZodObject<{
28
28
  $action: z.ZodEnum<["emit", "setState", "sequence", "openTile", "openFull", "navigate", "dismiss", "fx"]>;
29
29
  payload: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
30
30
  }, "strip", z.ZodTypeAny, {
31
- $action: "navigate" | "setState" | "emit" | "sequence" | "openTile" | "openFull" | "dismiss" | "fx";
31
+ $action: "navigate" | "setState" | "emit" | "fx" | "sequence" | "openTile" | "openFull" | "dismiss";
32
32
  payload?: Record<string, unknown> | undefined;
33
33
  }, {
34
- $action: "navigate" | "setState" | "emit" | "sequence" | "openTile" | "openFull" | "dismiss" | "fx";
34
+ $action: "navigate" | "setState" | "emit" | "fx" | "sequence" | "openTile" | "openFull" | "dismiss";
35
35
  payload?: Record<string, unknown> | undefined;
36
36
  }>;
37
37
  declare const PropValueSchema: z.ZodType<unknown>;
@@ -347,11 +347,11 @@ export declare const OverlaySpecSchema: z.ZodObject<{
347
347
  offsetMs: z.ZodOptional<z.ZodNumber>;
348
348
  scale: z.ZodOptional<z.ZodNumber>;
349
349
  }, "strip", z.ZodTypeAny, {
350
- offsetMs?: number | undefined;
351
350
  scale?: number | undefined;
352
- }, {
353
351
  offsetMs?: number | undefined;
352
+ }, {
354
353
  scale?: number | undefined;
354
+ offsetMs?: number | undefined;
355
355
  }>>;
356
356
  freezeWhen: z.ZodOptional<z.ZodType<unknown, z.ZodTypeDef, unknown>>;
357
357
  }, "strip", z.ZodTypeAny, {
@@ -360,8 +360,8 @@ export declare const OverlaySpecSchema: z.ZodObject<{
360
360
  toleranceMs: number;
361
361
  onSeek: "recompute";
362
362
  transform?: {
363
- offsetMs?: number | undefined;
364
363
  scale?: number | undefined;
364
+ offsetMs?: number | undefined;
365
365
  } | undefined;
366
366
  freezeWhen?: unknown;
367
367
  }, {
@@ -370,8 +370,8 @@ export declare const OverlaySpecSchema: z.ZodObject<{
370
370
  toleranceMs: number;
371
371
  onSeek: "recompute";
372
372
  transform?: {
373
- offsetMs?: number | undefined;
374
373
  scale?: number | undefined;
374
+ offsetMs?: number | undefined;
375
375
  } | undefined;
376
376
  freezeWhen?: unknown;
377
377
  }>;
@@ -703,14 +703,14 @@ export declare const OverlaySpecSchema: z.ZodObject<{
703
703
  }, "strip", z.ZodTypeAny, {
704
704
  id: string;
705
705
  type: "realtime" | "keyspace" | "host";
706
- channel: string;
707
706
  target: string;
707
+ channel: string;
708
708
  transform?: string | undefined;
709
709
  }, {
710
710
  id: string;
711
711
  type: "realtime" | "keyspace" | "host";
712
- channel: string;
713
712
  target: string;
713
+ channel: string;
714
714
  transform?: string | undefined;
715
715
  }>, "many">>;
716
716
  }, "strip", z.ZodTypeAny, {
@@ -726,8 +726,8 @@ export declare const OverlaySpecSchema: z.ZodObject<{
726
726
  toleranceMs: number;
727
727
  onSeek: "recompute";
728
728
  transform?: {
729
- offsetMs?: number | undefined;
730
729
  scale?: number | undefined;
730
+ offsetMs?: number | undefined;
731
731
  } | undefined;
732
732
  freezeWhen?: unknown;
733
733
  };
@@ -788,8 +788,8 @@ export declare const OverlaySpecSchema: z.ZodObject<{
788
788
  subscriptions?: {
789
789
  id: string;
790
790
  type: "realtime" | "keyspace" | "host";
791
- channel: string;
792
791
  target: string;
792
+ channel: string;
793
793
  transform?: string | undefined;
794
794
  }[] | undefined;
795
795
  }, {
@@ -805,8 +805,8 @@ export declare const OverlaySpecSchema: z.ZodObject<{
805
805
  toleranceMs: number;
806
806
  onSeek: "recompute";
807
807
  transform?: {
808
- offsetMs?: number | undefined;
809
808
  scale?: number | undefined;
809
+ offsetMs?: number | undefined;
810
810
  } | undefined;
811
811
  freezeWhen?: unknown;
812
812
  };
@@ -867,8 +867,8 @@ export declare const OverlaySpecSchema: z.ZodObject<{
867
867
  subscriptions?: {
868
868
  id: string;
869
869
  type: "realtime" | "keyspace" | "host";
870
- channel: string;
871
870
  target: string;
871
+ channel: string;
872
872
  transform?: string | undefined;
873
873
  }[] | undefined;
874
874
  }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thewhateverapp/tile-sdk",
3
- "version": "0.13.37",
3
+ "version": "0.14.1",
4
4
  "description": "SDK for building interactive tiles on The Whatever App platform",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -32,6 +32,10 @@
32
32
  "./templates/video": {
33
33
  "types": "./dist/templates/video/index.d.ts",
34
34
  "import": "./dist/templates/video/index.js"
35
+ },
36
+ "./scene": {
37
+ "types": "./dist/scene/index.d.ts",
38
+ "import": "./dist/scene/index.js"
35
39
  }
36
40
  },
37
41
  "files": [
@@ -60,12 +64,15 @@
60
64
  "author": "The Whatever App",
61
65
  "license": "MIT",
62
66
  "dependencies": {
67
+ "@thewhateverapp/scene-sdk": "^0.1.1",
68
+ "matter-js": "^0.19.0",
63
69
  "zod": "^3.22.0"
64
70
  },
65
71
  "peerDependencies": {
66
72
  "react": "^18.0.0",
67
73
  "@pixi/react": "^7.0.0",
68
- "pixi.js": "^7.0.0"
74
+ "pixi.js": "^7.0.0",
75
+ "@pixi/filter-glow": "^5.0.0"
69
76
  },
70
77
  "peerDependenciesMeta": {
71
78
  "@pixi/react": {
@@ -73,10 +80,15 @@
73
80
  },
74
81
  "pixi.js": {
75
82
  "optional": true
83
+ },
84
+ "@pixi/filter-glow": {
85
+ "optional": true
76
86
  }
77
87
  },
78
88
  "devDependencies": {
89
+ "@pixi/filter-glow": "^5.0.0",
79
90
  "@pixi/react": "^7.1.2",
91
+ "@types/matter-js": "^0.19.0",
80
92
  "@types/node": "^20.0.0",
81
93
  "@types/react": "^18.2.48",
82
94
  "eslint": "^9.39.1",