@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.
- package/dist/scene/SceneContext.d.ts +167 -0
- package/dist/scene/SceneContext.d.ts.map +1 -0
- package/dist/scene/SceneContext.js +86 -0
- package/dist/scene/SceneFromJson.d.ts +27 -0
- package/dist/scene/SceneFromJson.d.ts.map +1 -0
- package/dist/scene/SceneFromJson.js +74 -0
- package/dist/scene/SceneRenderer.d.ts +26 -0
- package/dist/scene/SceneRenderer.d.ts.map +1 -0
- package/dist/scene/SceneRenderer.js +201 -0
- package/dist/scene/camera/CameraController.d.ts +6 -0
- package/dist/scene/camera/CameraController.d.ts.map +1 -0
- package/dist/scene/camera/CameraController.js +84 -0
- package/dist/scene/components/ComponentRunner.d.ts +22 -0
- package/dist/scene/components/ComponentRunner.d.ts.map +1 -0
- package/dist/scene/components/ComponentRunner.js +197 -0
- package/dist/scene/effects/GlowFilter.d.ts +38 -0
- package/dist/scene/effects/GlowFilter.d.ts.map +1 -0
- package/dist/scene/effects/GlowFilter.js +40 -0
- package/dist/scene/effects/ParticleSystem.d.ts +52 -0
- package/dist/scene/effects/ParticleSystem.d.ts.map +1 -0
- package/dist/scene/effects/ParticleSystem.js +107 -0
- package/dist/scene/entities/EntityRenderer.d.ts +14 -0
- package/dist/scene/entities/EntityRenderer.d.ts.map +1 -0
- package/dist/scene/entities/EntityRenderer.js +203 -0
- package/dist/scene/index.d.ts +46 -0
- package/dist/scene/index.d.ts.map +1 -0
- package/dist/scene/index.js +50 -0
- package/dist/scene/input/InputManager.d.ts +18 -0
- package/dist/scene/input/InputManager.d.ts.map +1 -0
- package/dist/scene/input/InputManager.js +86 -0
- package/dist/scene/physics/PhysicsEngine.d.ts +15 -0
- package/dist/scene/physics/PhysicsEngine.d.ts.map +1 -0
- package/dist/scene/physics/PhysicsEngine.js +252 -0
- package/dist/scene/timeline/TimelineExecutor.d.ts +6 -0
- package/dist/scene/timeline/TimelineExecutor.d.ts.map +1 -0
- package/dist/scene/timeline/TimelineExecutor.js +236 -0
- package/dist/spec/schema.d.ts +12 -12
- package/package.json +14 -2
|
@@ -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
|
+
}
|
package/dist/spec/schema.d.ts
CHANGED
|
@@ -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" | "
|
|
31
|
+
$action: "navigate" | "setState" | "emit" | "fx" | "sequence" | "openTile" | "openFull" | "dismiss";
|
|
32
32
|
payload?: Record<string, unknown> | undefined;
|
|
33
33
|
}, {
|
|
34
|
-
$action: "navigate" | "setState" | "emit" | "
|
|
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.
|
|
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",
|