@solidrt/2d 0.0.65 → 0.0.67
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 +2 -2
- package/examples/README.md +1 -1
- package/examples/camera.tsx +1 -1
- package/examples/pick.tsx +1 -1
- package/examples/split-screen.tsx +1 -1
- package/examples/tiles.tsx +1 -1
- package/examples/views.tsx +1 -1
- package/package.json +3 -3
- package/src/animation.ts +1 -1
- package/src/components/group.tsx +4 -2
- package/src/components/sprite-layer.tsx +4 -0
- package/src/components/sprite.tsx +4 -2
- package/src/components/view2d.tsx +2 -0
- package/src/dispatch.ts +13 -2
- package/src/layer.ts +7 -1
- package/src/oversample.ts +1 -1
- package/src/views.ts +1 -0
package/AGENTS.md
CHANGED
|
@@ -453,7 +453,7 @@ it: `createSpriteLayer(texture, { stagger })` / `layer.setStagger(ms)`.
|
|
|
453
453
|
Each natural settle calls the handle's `onTransitionEnd` (plain field,
|
|
454
454
|
or the `<Sprite>`/`<Group>` prop) with `{ component }` - target-only,
|
|
455
455
|
never on a cancel, snap or exit; the raw "spatialTransitionEnd" engine
|
|
456
|
-
event (
|
|
456
|
+
event (sol:events, node = sprite.node) stays for flux:spatial consumers.
|
|
457
457
|
See examples/springs.tsx (tap a sprite: it leaves through its `exit`).
|
|
458
458
|
|
|
459
459
|
### Frame-rate motion
|
|
@@ -469,7 +469,7 @@ re-runs an effect per sprite per frame for nothing.
|
|
|
469
469
|
|
|
470
470
|
Frame animation (animation.ts): `createAnimation(frames, fps, { loop })`
|
|
471
471
|
is a clip with a shared clock on the app's frame time (it freezes with
|
|
472
|
-
the dev clock and plays at its own speed under `
|
|
472
|
+
the dev clock and plays at its own speed under `sol render`) stepping
|
|
473
473
|
every attached sprite
|
|
474
474
|
(`anim.add(sprite)` / `remove`; `play`/`pause`; `frame()`/`playing()`
|
|
475
475
|
read the clock, methods like the 3d mixer's `playing()`; `loop: false`
|
package/examples/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @solidrt/2d examples
|
|
2
2
|
|
|
3
3
|
Single-concept sprite-layer patterns. Each file is a complete, runnable app
|
|
4
|
-
(`bun run
|
|
4
|
+
(`bun run sol run <file>` from the repo root) demonstrating exactly one thing -
|
|
5
5
|
copy one and adapt it.
|
|
6
6
|
|
|
7
7
|
- `sprites.tsx` - the layer at its natural scale: 500 sprites bouncing at
|
package/examples/camera.tsx
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
import { createEffect, createInputMap, createPointerFeed, createSignal, decodeImage, displayScale, gamepad, onFrame, render, Show, windowSize } from "@solidrt/core"
|
|
24
24
|
import { addSprite, camera2dActions, camera2dBindings, createAtlas, createCamera2d, createSpriteLayer, feedPointer, fitOversample, grid, setSprite } from "@solidrt/2d"
|
|
25
25
|
import type { Camera2dHandle, SpriteHandle } from "@solidrt/2d"
|
|
26
|
-
import { registerDebug } from "
|
|
26
|
+
import { registerDebug } from "sol:dev"
|
|
27
27
|
import logoBytes from "./logo.png" with { type: "binary" }
|
|
28
28
|
|
|
29
29
|
const WORLD = { width: 2400, height: 1600 }
|
package/examples/pick.tsx
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
import { createInputMap, createPointerFeed, createSignal, decodeImage, render, For } from "@solidrt/core"
|
|
22
22
|
import { Camera2d, camera2dActions, camera2dBindings, createAtlas, grid, setSprite, Sprite, SpriteLayer, View2d } from "@solidrt/2d"
|
|
23
23
|
import type { Camera2dHandle, Frame, SpriteHandle } from "@solidrt/2d"
|
|
24
|
-
import { registerDebug } from "
|
|
24
|
+
import { registerDebug } from "sol:dev"
|
|
25
25
|
import logoBytes from "./logo.png" with { type: "binary" }
|
|
26
26
|
|
|
27
27
|
const TINTS: [number, number, number, number][] = [
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { createInputMap, createPointerFeed, decodeImage, gamepad, onFrame, render, windowSize, For } from "@solidrt/core"
|
|
13
13
|
import { Camera2d, camera2dActions, camera2dBindings, createAtlas, grid, setSprite, Sprite, SpriteLayer, View2d } from "@solidrt/2d"
|
|
14
14
|
import type { Camera2dHandle, Frame, SpriteHandle } from "@solidrt/2d"
|
|
15
|
-
import { registerDebug } from "
|
|
15
|
+
import { registerDebug } from "sol:dev"
|
|
16
16
|
import logoBytes from "./logo.png" with { type: "binary" }
|
|
17
17
|
|
|
18
18
|
const WORLD = { width: 2400, height: 1600 }
|
package/examples/tiles.tsx
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
import { createSignal, decodeImage, onFrame, pct, render, windowSize } from "@solidrt/core"
|
|
24
24
|
import { createAtlas, grid, TileLayer } from "@solidrt/2d"
|
|
25
25
|
import type { TileCamera, TileLayerHandle } from "@solidrt/2d"
|
|
26
|
-
import { registerDebug } from "
|
|
26
|
+
import { registerDebug } from "sol:dev"
|
|
27
27
|
import logoBytes from "./logo.png" with { type: "binary" }
|
|
28
28
|
|
|
29
29
|
const COLS = 128
|
package/examples/views.tsx
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import { createEffect, createInputMap, createPointerFeed, createSignal, decodeImage, displayScale, gamepad, onFrame, render, windowSize } from "@solidrt/core"
|
|
19
19
|
import { addSprite, camera2dActions, camera2dBindings, createAtlas, createCamera2d, createSpriteLayer, feedPointer, fitOversample, grid, setSprite } from "@solidrt/2d"
|
|
20
20
|
import type { Camera2dHandle, SpriteHandle, ViewHandle } from "@solidrt/2d"
|
|
21
|
-
import { registerDebug } from "
|
|
21
|
+
import { registerDebug } from "sol:dev"
|
|
22
22
|
import logoBytes from "./logo.png" with { type: "binary" }
|
|
23
23
|
|
|
24
24
|
const WORLD = { width: 2400, height: 1600 }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidrt/2d",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.67",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"funding": "https://github.com/sponsors/wellawaretech",
|
|
6
6
|
"author": "Antoine van Wel",
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"AGENTS.md"
|
|
16
16
|
],
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@solidrt/test": "0.0.
|
|
18
|
+
"@solidrt/test": "0.0.67"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
21
|
"@solidjs/signals": "2.0.0-rc.13",
|
|
22
|
-
"@solidrt/core": "0.0.
|
|
22
|
+
"@solidrt/core": "0.0.67"
|
|
23
23
|
}
|
|
24
24
|
}
|
package/src/animation.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// generates 8 publishes and 8 presents a second and a paused clip costs
|
|
6
6
|
// nothing - the demand-gate story unchanged. The clock is the app's frame
|
|
7
7
|
// time: the clip freezes and resumes with the dev tools' clock, plays at
|
|
8
|
-
// its own speed under `
|
|
8
|
+
// its own speed under `sol render`, and a step lands on the frame it is
|
|
9
9
|
// due in. The clip
|
|
10
10
|
// does not own its sprites (destroySprite prunes lazily on the next step),
|
|
11
11
|
// and a sprite belongs to at most one animation. Plain JS over setSprite,
|
package/src/components/group.tsx
CHANGED
|
@@ -21,6 +21,7 @@ export type GroupProps = {
|
|
|
21
21
|
onPointerDown?: (event: SpritePointerEvent) => void
|
|
22
22
|
onPointerMove?: (event: SpritePointerEvent) => void
|
|
23
23
|
onPointerUp?: (event: SpritePointerEvent) => void
|
|
24
|
+
onPointerCancel?: (event: SpritePointerEvent) => void
|
|
24
25
|
onWheel?: (event: SpriteWheelEvent) => void
|
|
25
26
|
onTap?: (event: SpriteTapEvent) => void
|
|
26
27
|
/** How pose-prop changes animate (see setGroupTransition). The mount
|
|
@@ -52,11 +53,12 @@ export let Group: ParentComponent<GroupProps> = props => {
|
|
|
52
53
|
transition => setGroupTransition(group, transition ?? null),
|
|
53
54
|
)
|
|
54
55
|
createEffect(
|
|
55
|
-
() => [props.onPointerDown, props.onPointerMove, props.onPointerUp, props.onWheel, props.onTap, props.onTransitionEnd] as const,
|
|
56
|
-
([down, move, up, wheel, tap, end]) => {
|
|
56
|
+
() => [props.onPointerDown, props.onPointerMove, props.onPointerUp, props.onPointerCancel, props.onWheel, props.onTap, props.onTransitionEnd] as const,
|
|
57
|
+
([down, move, up, cancel, wheel, tap, end]) => {
|
|
57
58
|
group.onPointerDown = down
|
|
58
59
|
group.onPointerMove = move
|
|
59
60
|
group.onPointerUp = up
|
|
61
|
+
group.onPointerCancel = cancel
|
|
60
62
|
group.onWheel = wheel
|
|
61
63
|
group.onTap = tap
|
|
62
64
|
group.onTransitionEnd = end
|
|
@@ -19,6 +19,7 @@ export type LayerPointerProps = {
|
|
|
19
19
|
onPointerDown?: (event: LayerPointerEvent) => void
|
|
20
20
|
onPointerMove?: (event: LayerPointerEvent) => void
|
|
21
21
|
onPointerUp?: (event: LayerPointerEvent) => void
|
|
22
|
+
onPointerCancel?: (event: LayerPointerEvent) => void
|
|
22
23
|
onWheel?: (event: LayerWheelEvent) => void
|
|
23
24
|
onTap?: (event: LayerTapEvent) => void
|
|
24
25
|
}
|
|
@@ -143,6 +144,7 @@ const VIEW_PROPS = [
|
|
|
143
144
|
"onPointerDown",
|
|
144
145
|
"onPointerMove",
|
|
145
146
|
"onPointerUp",
|
|
147
|
+
"onPointerCancel",
|
|
146
148
|
"onWheel",
|
|
147
149
|
"onTap",
|
|
148
150
|
] as const
|
|
@@ -249,6 +251,7 @@ export let SpriteLayer: ParentComponent<SpriteLayerProps> = props => {
|
|
|
249
251
|
onPointerDown: e => props.onPointerDown?.(e),
|
|
250
252
|
onPointerMove: e => props.onPointerMove?.(e),
|
|
251
253
|
onPointerUp: e => props.onPointerUp?.(e),
|
|
254
|
+
onPointerCancel: e => props.onPointerCancel?.(e),
|
|
252
255
|
onWheel: e => props.onWheel?.(e),
|
|
253
256
|
onTap: e => props.onTap?.(e),
|
|
254
257
|
}),
|
|
@@ -321,6 +324,7 @@ export let SpriteLayer: ParentComponent<SpriteLayerProps> = props => {
|
|
|
321
324
|
onPointerDown={events ? viewHandlers.onPointerDown : undefined}
|
|
322
325
|
onPointerMove={events ? viewHandlers.onPointerMove : undefined}
|
|
323
326
|
onPointerUp={events ? viewHandlers.onPointerUp : undefined}
|
|
327
|
+
onPointerCancel={events ? viewHandlers.onPointerCancel : undefined}
|
|
324
328
|
onPointerLeave={events ? viewHandlers.onPointerLeave : undefined}
|
|
325
329
|
onWheel={events ? viewHandlers.onWheel : undefined}
|
|
326
330
|
/>
|
|
@@ -18,6 +18,7 @@ export type SpritePointerProps = {
|
|
|
18
18
|
onPointerDown?: (event: SpritePointerEvent) => void
|
|
19
19
|
onPointerMove?: (event: SpritePointerEvent) => void
|
|
20
20
|
onPointerUp?: (event: SpritePointerEvent) => void
|
|
21
|
+
onPointerCancel?: (event: SpritePointerEvent) => void
|
|
21
22
|
/** Sprites only: a Group never receives enter/leave. */
|
|
22
23
|
onPointerEnter?: (event: SpritePointerEvent) => void
|
|
23
24
|
onPointerLeave?: (event: SpritePointerEvent) => void
|
|
@@ -54,11 +55,12 @@ export let Sprite: VoidComponent<SpriteProps> = props => {
|
|
|
54
55
|
transition => setSpriteTransition(sprite, transition ?? null),
|
|
55
56
|
)
|
|
56
57
|
createEffect(
|
|
57
|
-
() => [props.onPointerDown, props.onPointerMove, props.onPointerUp, props.onPointerEnter, props.onPointerLeave, props.onWheel, props.onTap, props.onTransitionEnd] as const,
|
|
58
|
-
([down, move, up, enter, leave, wheel, tap, end]) => {
|
|
58
|
+
() => [props.onPointerDown, props.onPointerMove, props.onPointerUp, props.onPointerCancel, props.onPointerEnter, props.onPointerLeave, props.onWheel, props.onTap, props.onTransitionEnd] as const,
|
|
59
|
+
([down, move, up, cancel, enter, leave, wheel, tap, end]) => {
|
|
59
60
|
sprite.onPointerDown = down
|
|
60
61
|
sprite.onPointerMove = move
|
|
61
62
|
sprite.onPointerUp = up
|
|
63
|
+
sprite.onPointerCancel = cancel
|
|
62
64
|
sprite.onPointerEnter = enter
|
|
63
65
|
sprite.onPointerLeave = leave
|
|
64
66
|
sprite.onWheel = wheel
|
|
@@ -107,6 +107,7 @@ export let View2d: ParentComponent<View2dProps> = props => {
|
|
|
107
107
|
onPointerDown: e => props.onPointerDown?.(e),
|
|
108
108
|
onPointerMove: e => props.onPointerMove?.(e),
|
|
109
109
|
onPointerUp: e => props.onPointerUp?.(e),
|
|
110
|
+
onPointerCancel: e => props.onPointerCancel?.(e),
|
|
110
111
|
onWheel: e => props.onWheel?.(e),
|
|
111
112
|
onTap: e => props.onTap?.(e),
|
|
112
113
|
}),
|
|
@@ -148,6 +149,7 @@ export let View2d: ParentComponent<View2dProps> = props => {
|
|
|
148
149
|
onPointerDown={events ? view.handlers.onPointerDown : undefined}
|
|
149
150
|
onPointerMove={events ? view.handlers.onPointerMove : undefined}
|
|
150
151
|
onPointerUp={events ? view.handlers.onPointerUp : undefined}
|
|
152
|
+
onPointerCancel={events ? view.handlers.onPointerCancel : undefined}
|
|
151
153
|
onPointerLeave={events ? view.handlers.onPointerLeave : undefined}
|
|
152
154
|
onWheel={events ? view.handlers.onWheel : undefined}
|
|
153
155
|
/>
|
package/src/dispatch.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Pointer dispatch behind view.handlers, shared by both layer kinds: the
|
|
2
2
|
// element event model one tree deeper, with the VIEW as the root of the
|
|
3
|
-
// walk. Down, move, up and wheel dispatch on the topmost hit sprite,
|
|
3
|
+
// walk. Down, move, up, cancel and wheel dispatch on the topmost hit sprite,
|
|
4
4
|
// bubble through its enclosing groups and end at the layer's listeners;
|
|
5
5
|
// over empty space the walk is the layer alone (`sprite` null). Claiming
|
|
6
6
|
// is stopPropagation: a handler that stops an event keeps every later
|
|
@@ -49,7 +49,7 @@ export type DispatchDeps = {
|
|
|
49
49
|
listeners: Set<LayerPointerListener>
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
type HandlerName = "onPointerDown" | "onPointerMove" | "onPointerUp" | "onWheel" | "onTap"
|
|
52
|
+
type HandlerName = "onPointerDown" | "onPointerMove" | "onPointerUp" | "onPointerCancel" | "onWheel" | "onTap"
|
|
53
53
|
|
|
54
54
|
// One runtime event object serves every view (SpritePointerEvent for the
|
|
55
55
|
// sprite chain, LayerPointerEvent at the root, plus the wheel and tap
|
|
@@ -212,6 +212,17 @@ export function spriteDispatch(deps: DispatchDeps): (layout: (() => { width: num
|
|
|
212
212
|
tap.tapCount = count
|
|
213
213
|
walk("onTap", tap, !press.claimed)
|
|
214
214
|
},
|
|
215
|
+
onPointerCancel(e) {
|
|
216
|
+
let [x, y] = toLayer(e)
|
|
217
|
+
let press = presses.get(e.pointerId)
|
|
218
|
+
if (!press) {
|
|
219
|
+
walk("onPointerCancel", makeEvent(topmost(x, y), x, y, e), true)
|
|
220
|
+
return
|
|
221
|
+
}
|
|
222
|
+
// The press ends where it was: the walk it captured, never a tap.
|
|
223
|
+
presses.delete(e.pointerId)
|
|
224
|
+
walk("onPointerCancel", makeEvent(press.target, x, y, e), !press.claimed)
|
|
225
|
+
},
|
|
215
226
|
onWheel(e) {
|
|
216
227
|
let [x, y] = toLayer(e)
|
|
217
228
|
let event = makeEvent(topmost(x, y), x, y, e)
|
package/src/layer.ts
CHANGED
|
@@ -40,7 +40,7 @@ import type {
|
|
|
40
40
|
NodeTransitionSpec,
|
|
41
41
|
QueryFilter,
|
|
42
42
|
} from "flux:spatial"
|
|
43
|
-
import { on } from "
|
|
43
|
+
import { on } from "sol:events"
|
|
44
44
|
import type { CameraState, CameraUpdate } from "./camera.ts"
|
|
45
45
|
import type { Frame } from "./frames.ts"
|
|
46
46
|
import { FULL_FRAME, writeFrame } from "./frames.ts"
|
|
@@ -183,6 +183,9 @@ export type Sprite = {
|
|
|
183
183
|
onPointerDown?: (event: SpritePointerEvent) => void
|
|
184
184
|
onPointerMove?: (event: SpritePointerEvent) => void
|
|
185
185
|
onPointerUp?: (event: SpritePointerEvent) => void
|
|
186
|
+
/** The pointer's other end: the system took it away (see core's
|
|
187
|
+
* onPointerCancel); bubbles like up, and the press it ends never taps. */
|
|
188
|
+
onPointerCancel?: (event: SpritePointerEvent) => void
|
|
186
189
|
onPointerEnter?: (event: SpritePointerEvent) => void
|
|
187
190
|
onPointerLeave?: (event: SpritePointerEvent) => void
|
|
188
191
|
/** A wheel notch over the sprite; bubbles like down/move/up. */
|
|
@@ -343,6 +346,7 @@ export type LayerPointerListener = {
|
|
|
343
346
|
onPointerDown?: (event: LayerPointerEvent) => void
|
|
344
347
|
onPointerMove?: (event: LayerPointerEvent) => void
|
|
345
348
|
onPointerUp?: (event: LayerPointerEvent) => void
|
|
349
|
+
onPointerCancel?: (event: LayerPointerEvent) => void
|
|
346
350
|
onWheel?: (event: LayerWheelEvent) => void
|
|
347
351
|
onTap?: (event: LayerTapEvent) => void
|
|
348
352
|
}
|
|
@@ -353,6 +357,7 @@ export type LayerHandlers = {
|
|
|
353
357
|
onPointerDown: (event: ElementPointerEvent) => void
|
|
354
358
|
onPointerMove: (event: ElementPointerEvent) => void
|
|
355
359
|
onPointerUp: (event: ElementPointerEvent) => void
|
|
360
|
+
onPointerCancel: (event: ElementPointerEvent) => void
|
|
356
361
|
onPointerLeave: (event: ElementPointerEvent) => void
|
|
357
362
|
onWheel: (event: ElementWheelEvent) => void
|
|
358
363
|
}
|
|
@@ -447,6 +452,7 @@ export type SpriteGroup = {
|
|
|
447
452
|
onPointerDown?: (event: SpritePointerEvent) => void
|
|
448
453
|
onPointerMove?: (event: SpritePointerEvent) => void
|
|
449
454
|
onPointerUp?: (event: SpritePointerEvent) => void
|
|
455
|
+
onPointerCancel?: (event: SpritePointerEvent) => void
|
|
450
456
|
onWheel?: (event: SpriteWheelEvent) => void
|
|
451
457
|
onTap?: (event: SpriteTapEvent) => void
|
|
452
458
|
/** See Sprite.onTransitionEnd. */
|
package/src/oversample.ts
CHANGED
|
@@ -39,7 +39,7 @@ export function fitOversample(scale: number, targetW: number, targetH: number, b
|
|
|
39
39
|
const THRASH_CHANGES = 4
|
|
40
40
|
/** The window those changes must land in, ms of the app's frame time: a
|
|
41
41
|
* warning about what happens per frame counts on the clock frames run on,
|
|
42
|
-
* so it means the same under `
|
|
42
|
+
* so it means the same under `sol render` and a paused dev clock. */
|
|
43
43
|
const THRASH_WINDOW_MS = 1000
|
|
44
44
|
|
|
45
45
|
/**
|
package/src/views.ts
CHANGED
|
@@ -289,6 +289,7 @@ export function feedPointer(view: ViewHandle, feed: PointerFeed): () => void {
|
|
|
289
289
|
onPointerDown: e => feed.handlers.onPointerDown(e.native),
|
|
290
290
|
onPointerMove: e => feed.handlers.onPointerMove(e.native),
|
|
291
291
|
onPointerUp: e => feed.handlers.onPointerUp(e.native),
|
|
292
|
+
onPointerCancel: e => feed.handlers.onPointerCancel(e.native),
|
|
292
293
|
onWheel: e => feed.handlers.onWheel(e.native),
|
|
293
294
|
})
|
|
294
295
|
}
|