@solidrt/2d 0.0.57 → 0.0.59
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/AGENTS.md +536 -374
- package/examples/anim.tsx +3 -3
- package/examples/parity.tsx +4 -4
- package/examples/springs.tsx +29 -7
- package/package.json +3 -3
- package/src/animation.ts +5 -9
- package/src/camera2d.ts +20 -3
- package/src/components/group.tsx +6 -6
- package/src/components/sprite-layer.tsx +8 -0
- package/src/components/sprite.tsx +6 -6
- package/src/components/view2d.tsx +8 -0
- package/src/dispatch.ts +2 -2
- package/src/index.ts +6 -3
- package/src/layer.ts +231 -52
- package/src/records.ts +6 -6
- package/src/shaders.ts +22 -18
- package/src/tiles.ts +4 -4
- package/src/views.ts +13 -13
package/examples/anim.tsx
CHANGED
|
@@ -62,15 +62,15 @@ function App() {
|
|
|
62
62
|
}, period / 2)
|
|
63
63
|
setTimeout(() => {
|
|
64
64
|
check(shownIndex(looped[1]!) === 1, "loop advanced to frame 1")
|
|
65
|
-
check(looping.frame === shownIndex(looped[1]!), "anim.frame matches the sprite's shown frame")
|
|
65
|
+
check(looping.frame() === shownIndex(looped[1]!), "anim.frame matches the sprite's shown frame")
|
|
66
66
|
}, period * 1.5)
|
|
67
67
|
setTimeout(() => {
|
|
68
68
|
check(shownIndex(looped[2]!) === 0, "loop wrapped back to frame 0 after a full cycle")
|
|
69
69
|
// One-shot: 4 frames at 5fps end at 800ms - long since done here.
|
|
70
70
|
check(shownIndex(shotSprite) === frames.length - 1, "one-shot holds its last frame")
|
|
71
|
-
check(!shot.playing, "one-shot stopped playing")
|
|
71
|
+
check(!shot.playing(), "one-shot stopped playing")
|
|
72
72
|
check(ended === 1, `onFinish fired once, got ${ended}`)
|
|
73
|
-
check(looping.playing, "the looping clip is still playing")
|
|
73
|
+
check(looping.playing(), "the looping clip is still playing")
|
|
74
74
|
console.log(failures.length === 0 ? "ANIM-OK" : `ANIM-FAIL: ${failures.join("; ")}`)
|
|
75
75
|
}, period * 4.5)
|
|
76
76
|
|
package/examples/parity.tsx
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
createSpriteLayer,
|
|
18
18
|
getSprite,
|
|
19
19
|
grid,
|
|
20
|
-
|
|
20
|
+
destroySprite,
|
|
21
21
|
setGroup,
|
|
22
22
|
setSprite,
|
|
23
23
|
} from "@solidrt/2d"
|
|
@@ -83,11 +83,11 @@ function App() {
|
|
|
83
83
|
{
|
|
84
84
|
let extra = addSprite(nodes, { x: 10, y: 10, w: 8, h: 8 })
|
|
85
85
|
let slotBefore = extra._slot
|
|
86
|
-
|
|
86
|
+
destroySprite(extra)
|
|
87
87
|
let reused = addSprite(nodes, { x: -100, y: -100, w: 0, h: 0 })
|
|
88
88
|
check(reused._slot === slotBefore, "removed slot recycles to the next add")
|
|
89
89
|
check(getSprite(extra) === null, "removed handle is inert")
|
|
90
|
-
|
|
90
|
+
destroySprite(reused)
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
let pixelParity = () => {
|
|
@@ -158,7 +158,7 @@ function App() {
|
|
|
158
158
|
check(nodes.pick(150, 100)[0] !== child, "the ungrouped position no longer hits")
|
|
159
159
|
let f = getSprite(child)!
|
|
160
160
|
check(f.x === 50 && f.y === 0, "getSprite reads the local pose")
|
|
161
|
-
|
|
161
|
+
destroySprite(child)
|
|
162
162
|
// The group node stays for the layer to dispose.
|
|
163
163
|
})
|
|
164
164
|
}
|
package/examples/springs.tsx
CHANGED
|
@@ -13,8 +13,15 @@
|
|
|
13
13
|
// random angle always takes the short arc, and the position spring keeps
|
|
14
14
|
// its velocity when a shuffle lands mid-flight - retarget as fast as you
|
|
15
15
|
// like, the motion stays continuous.
|
|
16
|
+
//
|
|
17
|
+
// Tap a sprite and it LEAVES: destroySprite lets go of the handle, and the
|
|
18
|
+
// `exit` on its scale entry shrinks it away on an ease-in of its own while
|
|
19
|
+
// the sprite is a ghost - drawn, but no tap or pick reaches it - then the
|
|
20
|
+
// core frees it. A fresh sprite pops into the empty slot a moment later,
|
|
21
|
+
// entering from scale zero (`from`); no settle callback, no bookkeeping.
|
|
16
22
|
import { decodeImage, render } from "@solidrt/core"
|
|
17
|
-
import { addSprite, createAtlas, createSpriteLayer, grid, setSprite, setSpriteTransition } from "@solidrt/2d"
|
|
23
|
+
import { addSprite, createAtlas, createSpriteLayer, destroySprite, grid, setSprite, setSpriteTransition } from "@solidrt/2d"
|
|
24
|
+
import type { SpriteHandle, SpriteTransition } from "@solidrt/2d"
|
|
18
25
|
import logoBytes from "./logo.png" with { type: "binary" }
|
|
19
26
|
|
|
20
27
|
const COLS = 20
|
|
@@ -23,6 +30,16 @@ const COUNT = COLS * ROWS
|
|
|
23
30
|
const W = 720
|
|
24
31
|
const H = 720
|
|
25
32
|
const SPRITE = 30
|
|
33
|
+
// The pop-in / shrink-out of a sprite's size, and the pause before a
|
|
34
|
+
// tapped-away sprite is replaced.
|
|
35
|
+
const POP_MS = 300
|
|
36
|
+
const RESPAWN_MS = 600
|
|
37
|
+
|
|
38
|
+
const TRANSITION: SpriteTransition = {
|
|
39
|
+
position: { duration: 700, bounce: 0.3 },
|
|
40
|
+
rotation: { duration: 700 },
|
|
41
|
+
scale: { duration: POP_MS, bounce: 0.4, from: [0, 0], exit: { value: [0, 0], curve: "ease-in", duration: POP_MS / 2 } },
|
|
42
|
+
}
|
|
26
43
|
|
|
27
44
|
function App() {
|
|
28
45
|
let atlas = createAtlas(decodeImage(logoBytes), { label: "logo-atlas" })
|
|
@@ -35,12 +52,17 @@ function App() {
|
|
|
35
52
|
|
|
36
53
|
// Sprite k sits at grid slot slots[k]; each shuffle re-deals the slots.
|
|
37
54
|
let slots = Array.from({ length: COUNT }, (_, i) => i)
|
|
38
|
-
let
|
|
39
|
-
addSprite(layer, { x: slotX(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
let spawn = (k: number): SpriteHandle => {
|
|
56
|
+
let sprite = addSprite(layer, { x: slotX(slots[k]!), y: slotY(slots[k]!), w: SPRITE, h: SPRITE, frame: frames[k % 4] })
|
|
57
|
+
// Declared in the adding tick, so the `from` plays: the sprite pops in.
|
|
58
|
+
setSpriteTransition(sprite, TRANSITION)
|
|
59
|
+
sprite.onTap = () => {
|
|
60
|
+
destroySprite(sprite)
|
|
61
|
+
setTimeout(() => (sprites[k] = spawn(k)), RESPAWN_MS)
|
|
62
|
+
}
|
|
63
|
+
return sprite
|
|
43
64
|
}
|
|
65
|
+
let sprites = slots.map((_, k) => spawn(k))
|
|
44
66
|
|
|
45
67
|
let shuffle = () => {
|
|
46
68
|
for (let i = slots.length - 1; i > 0; i--) {
|
|
@@ -58,7 +80,7 @@ function App() {
|
|
|
58
80
|
|
|
59
81
|
return (
|
|
60
82
|
<window alignItems="center" justifyContent="center">
|
|
61
|
-
<texture src={view.texture} width={W} height={H} />
|
|
83
|
+
<texture src={view.texture} width={W} height={H} {...view.handlers} />
|
|
62
84
|
</window>
|
|
63
85
|
)
|
|
64
86
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidrt/2d",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.59",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"funding": "https://github.com/sponsors/wellawaretech",
|
|
6
6
|
"author": "Antoine van Wel",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"AGENTS.md"
|
|
16
16
|
],
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@solidjs/signals": "2.0.0-rc.
|
|
19
|
-
"@solidrt/core": "0.0.
|
|
18
|
+
"@solidjs/signals": "2.0.0-rc.8",
|
|
19
|
+
"@solidrt/core": "0.0.59"
|
|
20
20
|
}
|
|
21
21
|
}
|
package/src/animation.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// playing clip and one frame write per attached sprite per STEP (not per
|
|
4
4
|
// display frame), so an 8fps walk cycle generates 8 publishes a second and
|
|
5
5
|
// a paused clip costs nothing - the demand-gate story unchanged. The clip
|
|
6
|
-
// does not own its sprites (
|
|
6
|
+
// does not own its sprites (destroySprite prunes lazily on the next step),
|
|
7
7
|
// and a sprite belongs to at most one animation. Plain JS over setSprite,
|
|
8
8
|
// so it works on both layer kinds and composes with <Sprite> via ref (leave
|
|
9
9
|
// the frame prop off - the clip owns that field).
|
|
@@ -28,10 +28,10 @@ export type AnimationOptions = {
|
|
|
28
28
|
|
|
29
29
|
export type SpriteAnimation = {
|
|
30
30
|
/** Current frame index into the clip. */
|
|
31
|
-
|
|
31
|
+
frame(): number
|
|
32
32
|
/** True while the clock advances: born playing, false after pause() and
|
|
33
33
|
* after a one-shot ends. */
|
|
34
|
-
|
|
34
|
+
playing(): boolean
|
|
35
35
|
/**
|
|
36
36
|
* Attach a sprite: it shows the clip's current frame immediately and
|
|
37
37
|
* steps with the shared clock (every attached sprite shows the SAME
|
|
@@ -127,12 +127,8 @@ export function createAnimation(frames: Frame[], fps: number, opts?: AnimationOp
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
let handle: SpriteAnimation = {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
},
|
|
133
|
-
get playing() {
|
|
134
|
-
return playing
|
|
135
|
-
},
|
|
130
|
+
frame: () => current,
|
|
131
|
+
playing: () => playing,
|
|
136
132
|
onFinish: undefined,
|
|
137
133
|
add(sprite) {
|
|
138
134
|
if (disposed) throw new Error("createAnimation: add on a disposed animation")
|
package/src/camera2d.ts
CHANGED
|
@@ -53,7 +53,8 @@ import { projectCamera, unprojectCamera } from "./camera.ts"
|
|
|
53
53
|
import type { CameraUpdate } from "./camera.ts"
|
|
54
54
|
|
|
55
55
|
// Glide rate toward a pending zoom or pose, e-foldings per second: high
|
|
56
|
-
// enough that a wheel notch reads as one push, low enough to look smooth
|
|
56
|
+
// enough that a wheel notch reads as one push, low enough to look smooth
|
|
57
|
+
// (the 3d controls' rate, motion.ts there); `damping` scales a notch's.
|
|
57
58
|
const GLIDE_EASE = 9
|
|
58
59
|
// A glide lands when the remaining zoom gap is under this (relative) ...
|
|
59
60
|
const GLIDE_EPSILON = 0.002
|
|
@@ -86,6 +87,7 @@ const ROLL_RATE = 0.5
|
|
|
86
87
|
/** What a 2d camera drives: anything with the layers' `setCamera`. */
|
|
87
88
|
export type Camera2dTarget = { setCamera(update: CameraUpdate): void }
|
|
88
89
|
|
|
90
|
+
/** The control's parameters: what set() takes and pose() returns filled. */
|
|
89
91
|
export type Camera2dPose = {
|
|
90
92
|
x?: number
|
|
91
93
|
y?: number
|
|
@@ -121,6 +123,11 @@ export type Camera2dOptions = Camera2dPose & {
|
|
|
121
123
|
panSpeed?: number
|
|
122
124
|
zoomSpeed?: number
|
|
123
125
|
rollSpeed?: number
|
|
126
|
+
/** How long an unbracketed zoom delta (a wheel notch) takes to ease in,
|
|
127
|
+
* as a multiple of the built-in settle time: 1 (the default) is the
|
|
128
|
+
* built-in ease, 2 coasts twice as long, 0 applies notches at once, as
|
|
129
|
+
* a pinch does. The 3d controls' knob, same meaning. */
|
|
130
|
+
damping?: number
|
|
124
131
|
/** Multiplier over the built-in follow damping. */
|
|
125
132
|
followSpeed?: number
|
|
126
133
|
/** Whether a drag release keeps the view gliding (default true). */
|
|
@@ -133,6 +140,9 @@ export type Camera2d = {
|
|
|
133
140
|
/** The pose as the layers receive it (a fresh object per call): the
|
|
134
141
|
* argument for projectCamera/unprojectCamera. */
|
|
135
142
|
camera(): CameraUpdate
|
|
143
|
+
/** Pose snapshot - the control's own four values, the shape set() takes
|
|
144
|
+
* (camera() adds the pivot the layers are told). */
|
|
145
|
+
pose(): Required<Camera2dPose>
|
|
136
146
|
/** Merge a pose in (clamps apply) and push it. A snap: an x/y/zoom
|
|
137
147
|
* write cancels a glide or fling in flight; rotation alone leaves them
|
|
138
148
|
* running. */
|
|
@@ -222,6 +232,9 @@ function checkOptions(options: Camera2dOptions): void {
|
|
|
222
232
|
}
|
|
223
233
|
finite("pivot.x", options.pivot?.x)
|
|
224
234
|
finite("pivot.y", options.pivot?.y)
|
|
235
|
+
if (options.damping !== undefined && !(Number.isFinite(options.damping) && options.damping >= 0)) {
|
|
236
|
+
throw new Error(`createCamera2d: damping must be a non-negative number, got ${options.damping}`)
|
|
237
|
+
}
|
|
225
238
|
checkFraction("deadZone.width", options.deadZone?.width ?? 0)
|
|
226
239
|
checkFraction("deadZone.height", options.deadZone?.height ?? 0)
|
|
227
240
|
}
|
|
@@ -257,6 +270,7 @@ export function createCamera2d(target: Camera2dTarget | Camera2dTarget[], option
|
|
|
257
270
|
let panSpeed = () => options.panSpeed ?? 1
|
|
258
271
|
let zoomExponent = () => options.zoomSpeed ?? 1
|
|
259
272
|
let rollSpeed = () => options.rollSpeed ?? 1
|
|
273
|
+
let damping = () => options.damping ?? 1
|
|
260
274
|
let followEase = () => FOLLOW_EASE * (options.followSpeed ?? 1)
|
|
261
275
|
let inertia = () => options.inertia ?? true
|
|
262
276
|
|
|
@@ -443,7 +457,7 @@ export function createCamera2d(target: Camera2dTarget | Camera2dTarget[], option
|
|
|
443
457
|
let zoomAt = (sx: number, sy: number, factor: number, ease: boolean) => {
|
|
444
458
|
positive("zoomAt factor", factor)
|
|
445
459
|
readViewport()
|
|
446
|
-
if (!ease) {
|
|
460
|
+
if (!ease || damping() <= 0) {
|
|
447
461
|
interrupt()
|
|
448
462
|
zoomTo(sx, sy, zoom * factor)
|
|
449
463
|
return
|
|
@@ -512,6 +526,7 @@ export function createCamera2d(target: Camera2dTarget | Camera2dTarget[], option
|
|
|
512
526
|
|
|
513
527
|
return {
|
|
514
528
|
camera,
|
|
529
|
+
pose: () => ({ x, y, zoom, rotation }),
|
|
515
530
|
active,
|
|
516
531
|
axes,
|
|
517
532
|
set(pose) {
|
|
@@ -654,7 +669,9 @@ export function createCamera2d(target: Camera2dTarget | Camera2dTarget[], option
|
|
|
654
669
|
touch()
|
|
655
670
|
}
|
|
656
671
|
if (glide !== null && dt > 0) {
|
|
657
|
-
|
|
672
|
+
// A wheel notch's glide coasts as `damping` says; a commanded
|
|
673
|
+
// glide (glideTo, fit) at the built-in rate.
|
|
674
|
+
let k = 1 - Math.exp(-(glide.kind === "anchor" ? GLIDE_EASE / damping() : GLIDE_EASE) * dt)
|
|
658
675
|
if (glide.kind === "anchor") {
|
|
659
676
|
let gap = Math.log(glide.target / zoom)
|
|
660
677
|
zoom = Math.abs(gap) < GLIDE_EPSILON ? glide.target : zoom * Math.exp(gap * k)
|
package/src/components/group.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createEffect, onCleanup, untrack, useContext } from "@solidrt/core"
|
|
2
2
|
import type { ParentComponent } from "@solidrt/core"
|
|
3
|
-
import { addGroup,
|
|
3
|
+
import { addGroup, destroyGroup, setGroup, setGroupTransition } from "../layer.ts"
|
|
4
4
|
import type { SpriteGroup, SpritePointerEvent, SpriteTapEvent, SpriteWheelEvent, TransitionEndEvent } from "../layer.ts"
|
|
5
|
-
import type {
|
|
5
|
+
import type { SpriteTransition } from "../layer.ts"
|
|
6
6
|
import { GroupContext, LayerContext } from "./context.ts"
|
|
7
7
|
|
|
8
8
|
export type GroupProps = {
|
|
@@ -23,9 +23,9 @@ export type GroupProps = {
|
|
|
23
23
|
onPointerUp?: (event: SpritePointerEvent) => void
|
|
24
24
|
onWheel?: (event: SpriteWheelEvent) => void
|
|
25
25
|
onTap?: (event: SpriteTapEvent) => void
|
|
26
|
-
/** How pose-prop changes animate (see setGroupTransition)
|
|
27
|
-
* pose
|
|
28
|
-
transition?:
|
|
26
|
+
/** How pose-prop changes animate (see setGroupTransition). The mount
|
|
27
|
+
* pose snaps, unless a component's `from` animates it in from there. */
|
|
28
|
+
transition?: SpriteTransition | string | null
|
|
29
29
|
/** A declared transition settled on one component. */
|
|
30
30
|
onTransitionEnd?: (event: TransitionEndEvent) => void
|
|
31
31
|
ref?: (group: SpriteGroup) => void
|
|
@@ -63,6 +63,6 @@ export let Group: ParentComponent<GroupProps> = props => {
|
|
|
63
63
|
},
|
|
64
64
|
)
|
|
65
65
|
untrack(() => props.ref)?.(group)
|
|
66
|
-
onCleanup(() =>
|
|
66
|
+
onCleanup(() => destroyGroup(group))
|
|
67
67
|
return <GroupContext value={group}>{props.children}</GroupContext>
|
|
68
68
|
}
|
|
@@ -241,6 +241,14 @@ export let SpriteLayer: ParentComponent<SpriteLayerProps> = props => {
|
|
|
241
241
|
}),
|
|
242
242
|
)
|
|
243
243
|
let events = untrack(() => props.events) !== false
|
|
244
|
+
// A feed on a built-in leaf carrying no handlers listens at a root no
|
|
245
|
+
// event reaches: a contradiction, so it throws (the dev validation
|
|
246
|
+
// policy) instead of feeding nothing.
|
|
247
|
+
if (pointer !== null && !events && !output) {
|
|
248
|
+
throw new Error(
|
|
249
|
+
"SpriteLayer: a pointer feed with events={false} receives nothing - the feed listens at the view's root, which only the leaf's handlers reach; keep events on, or compose the leaf with output and spread useSpriteLayer().viewport.handlers on it",
|
|
250
|
+
)
|
|
251
|
+
}
|
|
244
252
|
let leaf: { id: number } | undefined
|
|
245
253
|
// The view's pixel size: the props in fixed mode, the built-in leaf's
|
|
246
254
|
// laid-out box in fill mode (getLayoutBox, the untransformed read, so a
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createEffect, onCleanup, untrack, useContext } from "@solidrt/core"
|
|
2
2
|
import type { VoidComponent } from "@solidrt/core"
|
|
3
|
-
import { addSprite,
|
|
3
|
+
import { addSprite, destroySprite, setSprite, setSpriteTransition } from "../layer.ts"
|
|
4
4
|
import type { Sprite as SpriteHandle, SpriteOptions, SpritePointerEvent, SpriteTapEvent, SpriteWheelEvent, TransitionEndEvent } from "../layer.ts"
|
|
5
|
-
import type {
|
|
5
|
+
import type { SpriteTransition } from "../layer.ts"
|
|
6
6
|
import { GroupContext, LayerContext } from "./context.ts"
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -29,9 +29,9 @@ export type SpritePointerProps = {
|
|
|
29
29
|
|
|
30
30
|
export type SpriteProps = SpriteOptions &
|
|
31
31
|
SpritePointerProps & {
|
|
32
|
-
/** How pose-prop changes animate (see setSpriteTransition)
|
|
33
|
-
* pose
|
|
34
|
-
transition?:
|
|
32
|
+
/** How pose-prop changes animate (see setSpriteTransition). The mount
|
|
33
|
+
* pose snaps, unless a component's `from` animates it in from there. */
|
|
34
|
+
transition?: SpriteTransition | string | null
|
|
35
35
|
/** A declared transition settled on one component. */
|
|
36
36
|
onTransitionEnd?: (event: TransitionEndEvent) => void
|
|
37
37
|
ref?: (sprite: SpriteHandle) => void
|
|
@@ -67,6 +67,6 @@ export let Sprite: VoidComponent<SpriteProps> = props => {
|
|
|
67
67
|
},
|
|
68
68
|
)
|
|
69
69
|
untrack(() => props.ref)?.(sprite)
|
|
70
|
-
onCleanup(() =>
|
|
70
|
+
onCleanup(() => destroySprite(sprite))
|
|
71
71
|
return null
|
|
72
72
|
}
|
|
@@ -113,6 +113,14 @@ export let View2d: ParentComponent<View2dProps> = props => {
|
|
|
113
113
|
)
|
|
114
114
|
let output = untrack(() => props.output)
|
|
115
115
|
let events = untrack(() => props.events) !== false
|
|
116
|
+
// A feed on a built-in leaf carrying no handlers listens at a root no
|
|
117
|
+
// event reaches: a contradiction, so it throws (the dev validation
|
|
118
|
+
// policy) instead of feeding nothing.
|
|
119
|
+
if (pointer !== null && !events && !output) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
"View2d: a pointer feed with events={false} receives nothing - the feed listens at the view's root, which only the leaf's handlers reach; keep events on, or compose the leaf with output and spread view.handlers on it",
|
|
122
|
+
)
|
|
123
|
+
}
|
|
116
124
|
let leaf: { id: number } | undefined
|
|
117
125
|
// Auto oversample from the built-in leaf's window box, in device pixels,
|
|
118
126
|
// per view pixel: the same pick as SpriteLayer's fixed mode.
|
package/src/dispatch.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import type { PointerEvent as ElementPointerEvent } from "@solidrt/core"
|
|
23
23
|
import { unprojectCamera } from "./camera.ts"
|
|
24
24
|
import type { CameraUpdate } from "./camera.ts"
|
|
25
|
-
import type { LayerPointerListener, Sprite, SpriteGroup,
|
|
25
|
+
import type { LayerPointerListener, Sprite, SpriteGroup, LayerHandlers, SpritePointerEvent } from "./layer.ts"
|
|
26
26
|
import type { ViewHandle } from "./views.ts"
|
|
27
27
|
|
|
28
28
|
// Finger travel from the down point, in window pixels, past which a press
|
|
@@ -88,7 +88,7 @@ type Press = {
|
|
|
88
88
|
alone: boolean
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
export function spriteDispatch(deps: DispatchDeps): (layout: (() => { width: number; height: number }) | null) =>
|
|
91
|
+
export function spriteDispatch(deps: DispatchDeps): (layout: (() => { width: number; height: number }) | null) => LayerHandlers {
|
|
92
92
|
let now = deps.now ?? (() => performance.now())
|
|
93
93
|
let presses = new Map<number, Press>()
|
|
94
94
|
let hover = new Map<number, Sprite>()
|
package/src/index.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// without Solid components) and the components (SpriteLayer/Sprite/Group/
|
|
16
16
|
// View2d/TileLayer) on top. See AGENTS.md for the model and the traps.
|
|
17
17
|
|
|
18
|
-
export { addGroup, addSprite, createSpriteLayer, getSprite,
|
|
18
|
+
export { addGroup, addSprite, createSpriteLayer, getSprite, destroyGroup, destroySprite, setGroup, setGroupTransition, setSprite, setSpriteParent, setSpriteTransition, worldPosition, POSE_FLOATS, STYLE_FLOATS } from "./layer.ts"
|
|
19
19
|
export { createRecordLayer, FLOATS_PER_SPRITE } from "./records.ts"
|
|
20
20
|
export type { RecordLayer as RecordLayerHandle, RecordLayerOptions } from "./records.ts"
|
|
21
21
|
export { pointInSprite } from "./pick.ts"
|
|
@@ -35,7 +35,7 @@ export type {
|
|
|
35
35
|
MoveResult,
|
|
36
36
|
Overlap,
|
|
37
37
|
QueryOptions,
|
|
38
|
-
|
|
38
|
+
Hit,
|
|
39
39
|
Rect,
|
|
40
40
|
LayerPointerEvent,
|
|
41
41
|
LayerPointerListener,
|
|
@@ -43,12 +43,15 @@ export type {
|
|
|
43
43
|
LayerWheelEvent,
|
|
44
44
|
Sprite as SpriteHandle,
|
|
45
45
|
SpriteGroup,
|
|
46
|
-
|
|
46
|
+
LayerHandlers,
|
|
47
47
|
SpriteLayer as SpriteLayerHandle,
|
|
48
48
|
SpriteLayerOptions,
|
|
49
49
|
SpriteOptions,
|
|
50
50
|
SpritePointerEvent,
|
|
51
51
|
SpriteTapEvent,
|
|
52
|
+
SpriteEndpoint,
|
|
53
|
+
SpriteTransition,
|
|
54
|
+
SpriteTransitionSpec,
|
|
52
55
|
SpriteWheelEvent,
|
|
53
56
|
TransitionEndEvent,
|
|
54
57
|
Volume,
|