pixi-reels 1.6.0 → 2.0.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.
- package/CHANGELOG.md +337 -0
- package/CONTRIBUTING.md +1 -2
- package/README.md +53 -15
- package/dist/{ReelSymbol-C2iANPJM.js → ReelSymbol-Da6FHDO-.js} +29 -24
- package/dist/ReelSymbol-Da6FHDO-.js.map +1 -0
- package/dist/ReelSymbol-DldUQdRR.cjs +2 -0
- package/dist/ReelSymbol-DldUQdRR.cjs.map +1 -0
- package/dist/{SpineSymbol-CjGE8sL6.cjs → SpineSymbol-1c5vjgQu.cjs} +2 -2
- package/dist/SpineSymbol-1c5vjgQu.cjs.map +1 -0
- package/dist/{SpineSymbol-CPyjFDpT.js → SpineSymbol-CzcEUfsp.js} +2 -2
- package/dist/SpineSymbol-CzcEUfsp.js.map +1 -0
- package/dist/board/BoardGrid.d.ts +18 -8
- package/dist/board/BoardGrid.d.ts.map +1 -1
- package/dist/board/HoldAndWinBoard.d.ts +13 -9
- package/dist/board/HoldAndWinBoard.d.ts.map +1 -1
- package/dist/board/HoldAndWinBuilder.d.ts +13 -4
- package/dist/board/HoldAndWinBuilder.d.ts.map +1 -1
- package/dist/board/HoldAndWinState.d.ts +4 -4
- package/dist/board/HwTypes.d.ts +8 -8
- package/dist/board/HwTypes.d.ts.map +1 -1
- package/dist/cascade/TumbleConfig.d.ts +83 -29
- package/dist/cascade/TumbleConfig.d.ts.map +1 -1
- package/dist/cascade/tumbleAlgorithm.d.ts +34 -35
- package/dist/cascade/tumbleAlgorithm.d.ts.map +1 -1
- package/dist/config/types.d.ts +67 -45
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/v1Renames.d.ts +31 -0
- package/dist/config/v1Renames.d.ts.map +1 -0
- package/dist/core/Reel.d.ts +180 -102
- package/dist/core/Reel.d.ts.map +1 -1
- package/dist/core/ReelAxis.d.ts +57 -0
- package/dist/core/ReelAxis.d.ts.map +1 -0
- package/dist/core/ReelMotion.d.ts +38 -37
- package/dist/core/ReelMotion.d.ts.map +1 -1
- package/dist/core/ReelSet.d.ts +114 -80
- package/dist/core/ReelSet.d.ts.map +1 -1
- package/dist/core/ReelSetBuilder.d.ts +123 -54
- package/dist/core/ReelSetBuilder.d.ts.map +1 -1
- package/dist/core/ReelViewport.d.ts +82 -32
- package/dist/core/ReelViewport.d.ts.map +1 -1
- package/dist/core/StopSequencer.d.ts +21 -3
- package/dist/core/StopSequencer.d.ts.map +1 -1
- package/dist/debug/debug.d.ts +15 -5
- package/dist/debug/debug.d.ts.map +1 -1
- package/dist/debug/debugOverlay.d.ts +115 -0
- package/dist/debug/debugOverlay.d.ts.map +1 -0
- package/dist/debug-DFdorSrM.cjs +4 -0
- package/dist/debug-DFdorSrM.cjs.map +1 -0
- package/dist/{debug-BnXsgCkg.js → debug-DLQkFWGB.js} +1426 -853
- package/dist/debug-DLQkFWGB.js.map +1 -0
- package/dist/events/EventEmitter.d.ts +1 -1
- package/dist/events/ReelEvents.d.ts +40 -40
- package/dist/events/ReelEvents.d.ts.map +1 -1
- package/dist/frame/ColumnTarget.d.ts +62 -25
- package/dist/frame/ColumnTarget.d.ts.map +1 -1
- package/dist/frame/FrameBuilder.d.ts +13 -9
- package/dist/frame/FrameBuilder.d.ts.map +1 -1
- package/dist/frame/OffsetCalculator.d.ts +5 -5
- package/dist/frame/OffsetCalculator.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +15 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +220 -420
- package/dist/index.js.map +1 -1
- package/dist/pins/CellPin.d.ts +37 -37
- package/dist/pins/CellPin.d.ts.map +1 -1
- package/dist/snapshot/SpinTextureCache.d.ts +6 -4
- package/dist/snapshot/SpinTextureCache.d.ts.map +1 -1
- package/dist/snapshot/StaticSpinSymbol.d.ts +17 -6
- package/dist/snapshot/StaticSpinSymbol.d.ts.map +1 -1
- package/dist/spin/SpinController.d.ts +18 -19
- package/dist/spin/SpinController.d.ts.map +1 -1
- package/dist/spin/modes/CascadeMode.d.ts +1 -1
- package/dist/spin/modes/CascadeMode.d.ts.map +1 -1
- package/dist/spin/modes/ImmediateMode.d.ts +1 -1
- package/dist/spin/modes/ImmediateMode.d.ts.map +1 -1
- package/dist/spin/modes/SpinningMode.d.ts +5 -4
- package/dist/spin/modes/SpinningMode.d.ts.map +1 -1
- package/dist/spin/modes/StandardMode.d.ts +1 -1
- package/dist/spin/modes/StandardMode.d.ts.map +1 -1
- package/dist/spin/phases/AdjustPhase.d.ts +2 -2
- package/dist/spin/phases/AdjustPhase.d.ts.map +1 -1
- package/dist/spin/phases/AnticipationPhase.d.ts.map +1 -1
- package/dist/spin/phases/CascadeDropInPhase.d.ts +12 -9
- package/dist/spin/phases/CascadeDropInPhase.d.ts.map +1 -1
- package/dist/spin/phases/CascadeFallPhase.d.ts +5 -2
- package/dist/spin/phases/CascadeFallPhase.d.ts.map +1 -1
- package/dist/spin/phases/CascadePlacePhase.d.ts +16 -12
- package/dist/spin/phases/CascadePlacePhase.d.ts.map +1 -1
- package/dist/spin/phases/PhaseFactory.d.ts +2 -3
- package/dist/spin/phases/PhaseFactory.d.ts.map +1 -1
- package/dist/spin/phases/StartPhase.d.ts.map +1 -1
- package/dist/spin/phases/StopPhase.d.ts.map +1 -1
- package/dist/spine.cjs +1 -1
- package/dist/spine.js +2 -2
- package/dist/spotlight/SymbolSpotlight.d.ts +5 -3
- package/dist/spotlight/SymbolSpotlight.d.ts.map +1 -1
- package/dist/symbols/AnimatedSpriteSymbol.d.ts.map +1 -1
- package/dist/symbols/CardSymbol.d.ts +71 -0
- package/dist/symbols/CardSymbol.d.ts.map +1 -0
- package/dist/symbols/EmptySymbol.d.ts +1 -1
- package/dist/symbols/ReelSymbol.d.ts +34 -17
- package/dist/symbols/ReelSymbol.d.ts.map +1 -1
- package/dist/symbols/SpineSymbol.d.ts.map +1 -1
- package/dist/symbols/SymbolFactory.d.ts +2 -1
- package/dist/symbols/SymbolFactory.d.ts.map +1 -1
- package/dist/testing/testHarness.d.ts +43 -33
- package/dist/testing/testHarness.d.ts.map +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.js +18 -18
- package/dist/testing.js.map +1 -1
- package/dist/utils/TickerRef.d.ts +1 -2
- package/dist/utils/TickerRef.d.ts.map +1 -1
- package/dist/utils/gsap.d.ts +23 -0
- package/dist/utils/gsap.d.ts.map +1 -0
- package/dist/utils/gsapTicker.d.ts +11 -4
- package/dist/utils/gsapTicker.d.ts.map +1 -1
- package/dist/wins/WinPresenter.d.ts +1 -1
- package/package.json +5 -3
- package/dist/ReelSymbol-C2iANPJM.js.map +0 -1
- package/dist/ReelSymbol-qM2jxsy7.cjs +0 -2
- package/dist/ReelSymbol-qM2jxsy7.cjs.map +0 -1
- package/dist/SpineSymbol-CPyjFDpT.js.map +0 -1
- package/dist/SpineSymbol-CjGE8sL6.cjs.map +0 -1
- package/dist/debug-BnXsgCkg.js.map +0 -1
- package/dist/debug-DR2WYF66.cjs +0 -4
- package/dist/debug-DR2WYF66.cjs.map +0 -1
- package/dist/horizontal/HorizontalReel.d.ts +0 -146
- package/dist/horizontal/HorizontalReel.d.ts.map +0 -1
- package/dist/horizontal/HorizontalReelBuilder.d.ts +0 -63
- package/dist/horizontal/HorizontalReelBuilder.d.ts.map +0 -1
- package/dist/horizontal/HorizontalReelTypes.d.ts +0 -46
- package/dist/horizontal/HorizontalReelTypes.d.ts.map +0 -1
- package/dist/utils/gsapRef.d.ts +0 -14
- package/dist/utils/gsapRef.d.ts.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,342 @@
|
|
|
1
1
|
# pixi-reels
|
|
2
2
|
|
|
3
|
+
## 2.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: three public members no longer re-expose classes the package deliberately hides, and `HoldAndWinBoardConfig` is now exported.
|
|
8
|
+
|
|
9
|
+
`RandomSymbolProvider`, `StopSequencer` and `ReelMotion` were hidden from the package entry in 1.0.0 (PR [#140](https://github.com/schmooky/pixi-reels/issues/140)). Three public members were still typed with them -- `Reel.motion`, `Reel.stopSequencer`, `FrameBuilder.randomProvider` -- which put those classes back into `dist/core/Reel.d.ts` and would have semver-locked them into all of 2.x. All three are now `@internal`, so `stripInternal` keeps them out of the published types. Nothing is lost: reel geometry is on `ReelSet.getCellBounds()` / `getBlockBounds()` and `Reel.cellMain` / `.extent` / `.mainOffset`, landing is driven by `setResult()` / `slamStop()`, and symbol weights are configured via `builder.weights({...})`.
|
|
10
|
+
|
|
11
|
+
`HoldAndWinBoardConfig` is now exported. The board's own export block promises that a fork can "copy HoldAndWinBoard + HoldAndWinState, repoint their imports at `pixi-reels`, and everything they reach for is public" -- but the config the constructor takes was not, so the first line of a forked board could not be typed.
|
|
12
|
+
|
|
13
|
+
A new `check:api-surface` guard fails the build on any public member typed with a `src/` type no entry point exports, so this cannot silently regress. Constructor parameters are reported separately and waived by name: tagging a constructor `@internal` strips the whole signature and leaves consumers an implicit zero-arg `new Reel()` that typechecks and then throws, which is worse than the leak.
|
|
14
|
+
|
|
15
|
+
Fix: `destroySymbols()` now names the reel and cell when a visible cell has no symbol. The coordinate range check already passed at that point, so a miss means the strip is short or holed -- a reel torn down or reshaped while a cascade was in flight. It previously surfaced as `Cannot read properties of undefined (reading 'view')` from inside an `Array.map`, naming neither the cell nor the reel.
|
|
16
|
+
|
|
17
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: cascade grids are validated, the debug snapshot follows the travel axis, and `Gsap` is exportable.
|
|
18
|
+
|
|
19
|
+
**`refill()` and `runCascade()`'s `nextGrid` now validate their grid**, the same way `setResult()` always has: shape, v1 option keys, and buffer counts that fit the reels. They previously validated nothing, so a cascade grid still carrying a v1 `bufferAbove` reached `columnTargetToStrip`, came back `undefined`, and was silently random-filled on every stage of the chain -- the exact silent divergence the fail-loud guards exist to prevent. A `string[][]` grid threw a bare `TypeError` deep in the pipeline instead of naming the call. Errors name their own entry point, so a bad `nextGrid` says `runCascade(): nextGrid` rather than surfacing as a `refill()` failure two frames later.
|
|
20
|
+
|
|
21
|
+
The buffer-overflow message now reads `setResult()` rather than `setResult`, matching every other message from that call.
|
|
22
|
+
|
|
23
|
+
**`DebugReelSnapshot.allSymbols[].y` is now `.main`**, the coordinate along that reel's travel axis, and each reel reports its `orientation` and `direction`. The old field was hard-coded to `view.y`, so on a horizontal set every symbol reported a constant `0` -- no positional information at all, in the one orientation 2.0 exists to add. This is the surface agents are pointed at precisely because the canvas is opaque to them.
|
|
24
|
+
|
|
25
|
+
**`Gsap` is exported.** It is the second parameter of `driveGsapWithTicker`, the type of `ReelConfig.gsap`, and the return type of the `Reel.gsap` accessor, but it could not be named by a consumer.
|
|
26
|
+
|
|
27
|
+
**The v1 rename tables are no longer exported.** `CODEMOD_HINT`, `V1_BUILDER_METHODS`, `V1_OPTION_KEYS` and `V1_OPTION_VALUES` were public, which would have semver-locked 1.x migration scaffolding into all of 2.x. The guards still read them internally and every throw still names the replacement; nothing a consumer writes needs the table.
|
|
28
|
+
|
|
29
|
+
Fix: a `nudge()` on a jagged layout no longer displaces symbols that render above the mask. `ReelMotion.advance()` derives positions from the array index and writes them absolutely (it accumulated with `+=` in 1.x), which dropped the reel offset baked into any view lifted into `viewport.unmaskedContainer`. A nudge is the one path that moves the strip while the reel is at rest, so an `unmask: true` symbol on a pyramid reel jumped a full cell out of its column for the whole tween and snapped back at the end.
|
|
30
|
+
|
|
31
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Remove: the `examples/` directory. The standalone demo apps now live in a separate repo.
|
|
32
|
+
|
|
33
|
+
Nothing in the published package changes -- `examples/` was never part of the tarball. This matters only if you cloned the repo to run a demo. Runnable demos live on the docs site under `/recipes`, about 130 of them, each with its source alongside; `pnpm site:dev` serves the whole set.
|
|
34
|
+
|
|
35
|
+
Keeping two parallel demo surfaces in one repo meant every API change had to be made twice, and the example half kept losing: two of the six apps were still passing `string[][]` to `runCascade`'s `nextGrid`, which throws on the first cascade, and nothing caught it because `vite build` only transpiles.
|
|
36
|
+
|
|
37
|
+
What survived the move, for anyone following a path from an older doc:
|
|
38
|
+
|
|
39
|
+
- `examples/shared/` symbol classes and asset loaders are now `apps/site/src/runtime/`
|
|
40
|
+
- `CheatEngine` and `SeededRng` are the private `@pixi-reels/cheats` package (still outside the library, per ADR 009)
|
|
41
|
+
- the prototype sprite atlas is `apps/site/public/prototype-symbols/`
|
|
42
|
+
- `examples/orientation-matrix` is `tests/e2e/fixtures/orientation-matrix`, unchanged in what it proves: browser coverage of all four orientation x direction combinations
|
|
43
|
+
|
|
44
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Remove: `ReelAxis.withDirection()`, and with it the last trace of a per-spin direction override that never shipped.
|
|
45
|
+
|
|
46
|
+
The method had **zero call sites in `src`**. It existed only to serve ADR 016 section 3.5's `spin({ direction })` / `spin({ directionPerReel })`, which is not implemented and is absent from `SpinOptions`. Shipping it would have frozen a method into all of 2.x whose only justification was an unbuilt feature -- the same trap as exporting the v1 rename tables.
|
|
47
|
+
|
|
48
|
+
Direction is fixed at `build()`: `.direction(d)` and `.directionPerReel([...])`. Nothing else changes. The engine constructs one axis per reel via `reelAxis(orientation, direction)` and has never needed a sibling; if you were calling `withDirection` yourself, call `reelAxis(axis.orientation, d)` instead.
|
|
49
|
+
|
|
50
|
+
Implementing the per-spin override is a feature PR after 2.0, not a freeze rider: `Reel._axis` is `readonly` and is handed to `ReelMotion`, `ReelViewport`, and every phase at construction, so a per-spin flip needs a re-injection path through all of them, plus the mid-spin-throw guard and the section 3.4 "both buffers >= 1" validation that only per-spin overrides force. Re-adding the method then is additive -- consumers receive axes, they do not implement the interface. ADR 016 records this as decision 4 under Status, so it does not get re-proposed from the design doc.
|
|
51
|
+
|
|
52
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Change: `string[][]` is no longer accepted anywhere as a grid input. `runCascade`'s `nextGrid` must return `ColumnTarget[]`, and the `pixi-reels/testing` helper `spinAndLand` takes `ColumnTarget[]` too -- its `string[][]` convenience form is gone. Wrap with `grid.map((visible) => ({ visible }))`.
|
|
53
|
+
|
|
54
|
+
One accepted shape means a grid read out of the engine can be handed back to it without a conversion step, and a wrong shape now names itself at the call site instead of failing later inside the frame pipeline.
|
|
55
|
+
|
|
56
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: an `unmask: true` symbol now travels with the reel through the stop bounce instead of hanging still for it.
|
|
57
|
+
|
|
58
|
+
`StopPhase` lifts landed unmask views into `viewport.unmaskedContainer` in `notifyLanded()` and only then tweens `reel.container` through the two-leg overshoot. A lifted view carries the reel offset in its own coordinate rather than inheriting it from a parent, so it did not follow that tween: on the default profile a landed scatter or wild sat motionless for the full 600 ms while the rest of the reel bounced underneath it. The bounce now keeps lifted views pinned to the reel for every frame, and settles them on the exact resting position rather than the last tween sample.
|
|
59
|
+
|
|
60
|
+
Skipping mid-bounce had the same fault from the other side. `onSkip()` snapped to grid _before_ resting the container, so `snapToGrid` baked the current overshoot position into every lifted view and the container then moved out from under it -- leaving the view off by however far the bounce had travelled. The container is rested first now.
|
|
61
|
+
|
|
62
|
+
Fix: `nudge({ startDelay })` no longer leaks an `abort` listener per call. The listener was registered with `{ once: true }`, which only self-removes when the event actually fires, so every nudge that completed normally left one behind. The documented staggered pattern -- one long-lived `AbortController` across `Promise.all(reels.map(...))` -- accumulated them for the life of the controller. It is now removed on both paths.
|
|
63
|
+
|
|
64
|
+
Fix: `StopSequencer.next()` throws when the frame is exhausted instead of returning `_frame[0]`, or `''` after a `reset()`. Both fallbacks handed back a symbol id that resolves to nothing, so an over-consuming caller landed a silently wrong frame rather than failing where the bug was. Every caller already gates on `hasRemaining`. `reset()` also restores the feed cursor and step, not just the frame and count.
|
|
65
|
+
|
|
66
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Rename: the row/column vocabulary becomes orientation-neutral. A reel's strip is made of **cells**, and the off-window slots either side are **start** and **end** (start = the smaller main coordinate: above for vertical, left for horizontal), independent of which way the reel travels.
|
|
67
|
+
|
|
68
|
+
Run the `v1-to-v2` codemod over your sources. `build()` throws a named error if it still sees a v1 key. The codemod is not on npm yet -- the migration guide has the from-a-clone invocation.
|
|
69
|
+
|
|
70
|
+
Core geometry:
|
|
71
|
+
|
|
72
|
+
| v1 | v2 |
|
|
73
|
+
| ------------------------------------------- | ------------------------------------- |
|
|
74
|
+
| `visibleRows`, `visibleRowsPerReel` | `visibleCells`, `visibleCellsPerReel` |
|
|
75
|
+
| `bufferSymbols({ above, below })` | `bufferSymbols({ start, end })` |
|
|
76
|
+
| `ColumnTarget.bufferAbove` / `.bufferBelow` | `.bufferStart` / `.bufferEnd` |
|
|
77
|
+
| `Reel.bufferAbove` / `.bufferBelow` | `.bufferStart` / `.bufferEnd` |
|
|
78
|
+
| `reelPixelHeights` | `reelExtents` |
|
|
79
|
+
| `Reel.spinSymbolHeight` | `Reel.spinCellSize` |
|
|
80
|
+
|
|
81
|
+
Motion:
|
|
82
|
+
|
|
83
|
+
| v1 | v2 |
|
|
84
|
+
| ----------------------------- | ----------------------- |
|
|
85
|
+
| `ReelMotion.displace(deltaY)` | `.advance(travelDelta)` |
|
|
86
|
+
| `ReelMotion.slotHeight` | `.slotPitch` |
|
|
87
|
+
| `ReelMotion.getRowY(row)` | `.getCellMain(cell)` |
|
|
88
|
+
|
|
89
|
+
Grid coordinates and payloads:
|
|
90
|
+
|
|
91
|
+
| v1 | v2 |
|
|
92
|
+
| ------------------------------------------ | --------------------------------------- |
|
|
93
|
+
| `SymbolPosition.rowIndex` | `.cellIndex` |
|
|
94
|
+
| `cascade:*` `winnerRows`, `offsetRows` | `winnerCells`, `offsetCells` |
|
|
95
|
+
| `DropOffset.originalRow` | `.originalCell` |
|
|
96
|
+
| `TumbleConfig.rowStagger` / `.rowOrder` | `.cellStagger` / `.cellOrder` |
|
|
97
|
+
| `rowOrder: 'bottomToTop' \| 'topToBottom'` | `cellOrder: 'endFirst' \| 'startFirst'` |
|
|
98
|
+
| `pin:migrated { fromRow, toRow }` | `{ fromCell, toCell }` |
|
|
99
|
+
| `CellPin.originRow` | `.originCell` |
|
|
100
|
+
|
|
101
|
+
Offsets:
|
|
102
|
+
|
|
103
|
+
| v1 | v2 |
|
|
104
|
+
| ------------------------------------------------------- | ----------------------------- |
|
|
105
|
+
| `OffsetXMode` | `CrossOffsetMode` |
|
|
106
|
+
| `TrapezoidConfig.topWidthFactor` / `.bottomWidthFactor` | `.startFactor` / `.endFactor` |
|
|
107
|
+
|
|
108
|
+
Semantics, not just names:
|
|
109
|
+
|
|
110
|
+
| v1 | v2 |
|
|
111
|
+
| ------------------------------------------- | ------------------------------------------------------------------------------ |
|
|
112
|
+
| `bufferSymbols({ above, below })` | `bufferSymbols({ start, end })` |
|
|
113
|
+
| `reelAnchor: 'top' \| 'center' \| 'bottom'` | `'start' \| 'center' \| 'end'` |
|
|
114
|
+
| `SymbolData.size { w, h }` | `{ reels, cells }` (and `getSymbolFootprint`'s `size`) |
|
|
115
|
+
| `NudgeOptions.direction: 'up' \| 'down'` | `'forward' \| 'reverse'`, relative to the reel's own axis |
|
|
116
|
+
| `'symbol:created': [symbolId, row]` | `[symbolId, stripIndex]` -- it was always the strip index, never a visible row |
|
|
117
|
+
|
|
118
|
+
`nudge()` is now genuinely direction-relative: which edge feeds the reel is derived from the axis polarity, so a reel built with `direction('reverse')` nudges upward on `'forward'`. A vertical/forward reel behaves exactly as `'down'` did.
|
|
119
|
+
|
|
120
|
+
New:
|
|
121
|
+
|
|
122
|
+
- `builder.cellStacking(order)` / `builder.reelStacking(order)` expose render order explicitly (`'ascending'` default = today's behaviour: the cell/reel at the larger coordinate draws in front). Deliberately geometric -- `direction('reverse')` does NOT flip stacking, so art lit from above keeps overlapping the way it was drawn.
|
|
123
|
+
- `SymbolPosition.setId?` for games composing more than one reel set. The engine never reads it.
|
|
124
|
+
- `build()` throws when a cross-reel big symbol (`size.reels > 1`) meets a mixed `directionPerReel([...])`. The coordinator assumes one shared feed edge across the reels a block covers.
|
|
125
|
+
- `ReelMotion`'s wrap callback drops its dead `arrayIndex` / `direction` arguments.
|
|
126
|
+
|
|
127
|
+
Fail-loud, no silent aliases: `visibleRows()`, `visibleRowsPerReel()` and `reelPixelHeights()` are gone but still present as throwing stubs, and every renamed option key or string value throws from the builder method that received it (`bufferSymbols({ above })`, `multiways({ minRows })`, `symbolData({ size: { w } })`, `tumble({ fall: { rowStagger } })`, `offsetConfig({ topWidthFactor })`, `reelAnchor('top')`, `initialFrame`/`setResult` columns with `bufferAbove`). Each message names the v2 replacement and the codemod. The table itself stays internal: it is 1.x migration scaffolding, and exporting it would semver-lock it into all of 2.x.
|
|
128
|
+
|
|
129
|
+
Codemod: the `v1-to-v2` transform rewrites the API surface (AST-based, so it never touches your own `row` / `col` locals or your comments). Verified end-to-end against this repo's 112 site recipes at their pre-rename revision: zero v1 API names left in code. It ships in the repo rather than on npm for now; see the migration guide for how to run it from a clone.
|
|
130
|
+
|
|
131
|
+
Docs: a new "Migrating to 2.0" guide covers every rename with a before/after, including the three things the codemod deliberately leaves alone. ADRs, CHANGELOGs and the 1.0 migration guide keep their v1 vocabulary. they are records of what was true then.
|
|
132
|
+
|
|
133
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Remove: the standalone HorizontalReel / HorizontalReelBuilder subtree - use orientation('horizontal') on ReelSetBuilder instead.
|
|
134
|
+
|
|
135
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Internal: the motion contract (ADR 018) now runs in CI against the shipping engine, in all four orientation x direction combinations, and the `createTestReelSet` default symbol size is non-square (120x100) so a test can tell width from height.
|
|
136
|
+
|
|
137
|
+
No engine API change, but `createTestReelSet`'s default geometry is a breaking change to anyone writing tests against `pixi-reels/testing`: pass `symbolSize` explicitly if you were relying on 100x100. Filed as major so it lands under Breaking Changes in the changelog, where a reader whose geometry assertions just started failing will actually look.
|
|
138
|
+
|
|
139
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Remove: the internal negative-index buffer encoding. `ColumnTarget` is now carried unchanged from `setResult()` / `initialFrame()` all the way down to the reel, so no stage of the pipeline materializes `arr[-1]` string properties on an array any more.
|
|
140
|
+
|
|
141
|
+
What this changes for consumers:
|
|
142
|
+
|
|
143
|
+
- `Reel.placeSymbols(target)` takes a `ColumnTarget` instead of a `string[]`. Wrap a visible-only array as `{ visible: ids }`.
|
|
144
|
+
- `Reel.placeStrip(frame)` is new: it lands a full strip frame (index `0` = furthest buffer-above cell), which is the shape `FrameBuilder.build` returns. Custom stop/cascade phases should use this.
|
|
145
|
+
- `FrameContext.targetSymbols?: string[]` becomes `FrameContext.target?: ColumnTarget`. Middleware reads it with the new `getTargetSlot(target, cell)` helper, or materializes it with `columnTargetToStrip(target, bufferStart)`.
|
|
146
|
+
- `FrameBuilder.build` / `.buildAll` take `ColumnTarget` / `ColumnTarget[]` in the target position.
|
|
147
|
+
- `columnTargetToArray` is gone. `getTargetSlot`, `setTargetSlot`, `columnTargetToStrip` and `cloneColumnTarget` are exported in its place.
|
|
148
|
+
- `refill()` now validates a column against `visible.length` rather than the materialized array length, so a refill grid may carry `bufferStart` / `bufferEnd` entries. Previously a buffer-end entry made the column look too long and threw.
|
|
149
|
+
|
|
150
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Change: gsap is held per reel set instead of in a module global.
|
|
151
|
+
|
|
152
|
+
v1's `utils/gsapRef.ts` stored one instance process-wide, and its own docstring admitted "the last `setGsap` call wins" - so building a second `ReelSet` silently moved the first one's tweens onto a different timeline. Harmless for a single-set game; a real footgun for a composed stage. `builder.gsap(instance)` now binds that set only, captured at `build()`.
|
|
153
|
+
|
|
154
|
+
- `driveGsapWithTicker(ticker)` takes the instance as a second argument: `driveGsapWithTicker(ticker, myGsap)`. Pass the same one you gave the builder; omit it only if you never called `.gsap(...)`.
|
|
155
|
+
- Custom `ReelSymbol` subclasses should animate on the new protected `this.gsap`, which `SymbolFactory` binds to the owning set. An imported `gsap` still works when your app and the engine resolve to the same module; `this.gsap` is correct either way.
|
|
156
|
+
- `Reel.gsap` is exposed for custom phases (`this._reel.gsap`).
|
|
157
|
+
- The internal `setGsap` / `getGsap` helpers are gone, replaced by `DEFAULT_GSAP` and the `Gsap` type.
|
|
158
|
+
|
|
159
|
+
Nothing changes for a single-set game that never calls `.gsap(...)`.
|
|
160
|
+
|
|
161
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: `StaticSpinSymbol`'s motion blur now smears along the strip on a horizontal set.
|
|
162
|
+
|
|
163
|
+
`MotionBlurOptions.axis` defaulted to `'y'` and its docs told you to pass `{ axis: 'x' }` "for a `HorizontalReel`" - a class 2.0.0 deletes. So a horizontal set using `StaticSpinSymbol` smeared vertically, across the direction of travel, with no type error and no throw. The axis now defaults to the owning set's orientation (ADR 016 section 5); an explicit `blur.axis` still wins, for art that wants a deliberate cross-smear.
|
|
164
|
+
|
|
165
|
+
`ReelSymbol` gains a protected `this.mainAxis` (`'x'` or `'y'`), bound by `SymbolFactory` at create time, for the few effects that genuinely follow travel. `resize(width, height)` stays screen-space.
|
|
166
|
+
|
|
167
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: `orientation('horizontal')` now supports pyramids, MultiWays, and big symbols. The uniform-only guard at `build()` is gone, so every layout the engine offers works on either axis.
|
|
168
|
+
|
|
169
|
+
`Reel` stores its cell size axis-relative (`cellMain` along the strip, `cellCross` across it) and projects back to screen `(width, height)` whenever art is resized. A jagged horizontal set therefore varies cell WIDTH where a vertical one varies height, from the same arithmetic. New accessors: `Reel.cellMain`, `.cellCross`, `.mainGap`, `.crossGap`.
|
|
170
|
+
|
|
171
|
+
Breaking, beyond the v2 rename already listed:
|
|
172
|
+
|
|
173
|
+
- `reelExtents([...])` and `multiways({ reelExtent })` are MAIN-axis extents (pixel height for vertical, pixel width for horizontal). They were always the vertical reading; the name now means the same thing on both axes.
|
|
174
|
+
- `getBlockBounds` projects through the axis. `size.reels` spans the cross axis and `size.cells` the main axis in every orientation, so the screen width and height a block maps to invert under horizontal. The method name and return shape do not move.
|
|
175
|
+
- `PinOverlayTween` (part of `AdjustPhaseConfig`) is axis-relative: `cellWidth`/`oldCellHeight`/`newCellHeight`/`fromY`/`toY`/`x` become `cellCross`/`oldCellMain`/`newCellMain`/`fromMain`/`toMain`/`cross`.
|
|
176
|
+
|
|
177
|
+
Fixed along the way: MultiWays reshape derived its new cell size and its pin-overlay slot pitch from `symbolGap.y` unconditionally. On a horizontal set that is the CROSS gap, so reshaped reels came out the wrong length. Both now read the reel's own main gap (ADR 016 section 6.6).
|
|
178
|
+
|
|
179
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Change: `MaskStrategy.build` / `.update` take a single `MaskContext` (`{ rects, width, height, axis }`) instead of positional arguments, and every strategy must declare `readonly version = MASK_STRATEGY_VERSION`.
|
|
180
|
+
|
|
181
|
+
Only affects custom strategies; `RectMaskStrategy` and `SharedRectMaskStrategy` are unchanged to use.
|
|
182
|
+
|
|
183
|
+
A `ReelMaskRect` is screen-space, so which of its four numbers runs along the strip depends on the orientation: a vertical set puts the strip on `y`/`height`, a horizontal one on `x`/`width`. A strategy written for v1 receives an identically-shaped struct with transposed meaning and no compile error - and handed a `MaskContext` it would read `rects` as an object, find no `.length`, and quietly draw a full-bleed rect that clips nothing. `maskStrategy()` now throws by name on any strategy that does not declare version 2. `MaskContext` and `MASK_STRATEGY_VERSION` are exported.
|
|
184
|
+
|
|
185
|
+
### Minor Changes
|
|
186
|
+
|
|
187
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: `BoardGrid` and `HoldAndWinBuilder` take a travel axis, so a board's cells can fill sideways or upward.
|
|
188
|
+
|
|
189
|
+
ADR 016 section 7 listed sideways Hold & Win cells as unlocked by the axis work, but `BoardGrid` built every cell with a bare `ReelSetBuilder` and neither it nor `HoldAndWinBuilder` exposed an orientation, so a coin always scrolled in from above.
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
new HoldAndWinBuilder().grid(5, 3).axis("horizontal", "reverse");
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Cells are 1x1 reel sets, so this picks the edge a symbol scrolls in from. It does not touch the board layout: `cols` and `rows` stay board dimensions, and `BoardGrid`/`HoldAndWinBoard` keep that vocabulary deliberately. Defaults to vertical / forward, unchanged.
|
|
196
|
+
|
|
197
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: `CardSymbol`, `CARD_DECK` and `WILD_CARD` ship from the package. A playing-card tile drawn with `Graphics` -- coloured body, glyph fitted to the cell, glyph-only win pulse -- so a prototype runs with no art at all: `import { CardSymbol, CARD_DECK, WILD_CARD } from 'pixi-reels'`. It previously lived in `examples/shared` and could only be copy-pasted.
|
|
198
|
+
|
|
199
|
+
It uses the reel set's own gsap instance rather than importing gsap, so it is safe under a symlinked workspace.
|
|
200
|
+
|
|
201
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: the tumble cell stagger now follows gravity, so a reel that drains upward peels and refills from the top instead of the bottom.
|
|
202
|
+
|
|
203
|
+
`tumble({ fall, dropIn })`'s `cellOrder` resolved against the raw cell index and nothing else. Under the usual downward gravity that reads correctly -- the bottom cell, the one at the exit edge, goes first -- but on a reel draining the other way it staggered from the cell FURTHEST from the drain, so the cell about to leave first waited for the whole column to clear ahead of it. The geometry was already gravity-correct (symbols travelled and entered through the right edges); only the timing read backwards, which is why nothing caught it. `.direction('reverse')` with the default `gravity: 'auto'` was the visible case.
|
|
204
|
+
|
|
205
|
+
`cellOrder` now accepts `'auto'` and defaults to it. `'auto'` starts at the gravity-EXIT end -- the edge symbols are settling against -- so the canonical "bottom-left first, top-right last" feel is unchanged for every downward-gravity reel, and inverts by itself when gravity does. Nothing changes for a set that does not override gravity or direction.
|
|
206
|
+
|
|
207
|
+
`'endFirst'` and `'startFirst'` keep their meaning and are now explicitly geometric, like the buffers (ADR 016 section 3.4): they name an end of the strip and ignore gravity. Pass one to pin a screen edge regardless of which way the board drains.
|
|
208
|
+
|
|
209
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: `tumble({ gravity })` so cascades work on reverse and horizontal reels (ADR 016 section 3.6).
|
|
210
|
+
|
|
211
|
+
Cascade refills used to be hard-coded to settle toward the larger cell index. On a reel built with `.direction('reverse')` that meant the board drained one way and refilled through the edge it had just emptied, with survivors sliding against the reel's own travel. The two halves disagreed internally too: `distance: 'auto'` applied the reel polarity while the default `'perHole'` did not, so changing one animation-tuning field flipped which edge symbols entered from.
|
|
212
|
+
|
|
213
|
+
`gravity` defaults to `'auto'`, which follows each reel's own direction, so a reverse or horizontal set now cascades correctly with no extra configuration:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
builder.direction("reverse").tumble({}); // drains upward, refills from below
|
|
217
|
+
builder.orientation("horizontal").tumble({}); // drains right, refills from the left
|
|
218
|
+
builder.tumble({ gravity: "reverse" }); // spin one way, drop the other
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Whichever edge gravity exits by is the edge your server must pack survivors against in the grids it sends -- the engine animates the result, it does not reorder it.
|
|
222
|
+
|
|
223
|
+
`DropOffset` gains an `isNew` field. Branch on that rather than `originalCell < 0`, which only discriminates under forward gravity. `computeDropOffsets` takes an optional `gravity` and still defaults to `'forward'`.
|
|
224
|
+
|
|
225
|
+
`createTestReelSet` gains a `tumble` option so a cascade test can pick an orientation and direction without hand-rolling a builder.
|
|
226
|
+
|
|
227
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: `PhaseConstructor`, `PhaseCreatorFn`, `PinOverlayTween` and `TickerCallback` are now exported as types. Each appears in the signature of something already exported (`PhaseFactory.register`, `AdjustPhaseConfig.pinOverlays`, `TickerRef.add`), so a consumer could hold the value but never name it.
|
|
228
|
+
|
|
229
|
+
Fix: `ReelSymbol.onReelSpinStart`'s documented parameter name matches the signature again, and the `SymbolSpotlight` ADR link no longer points at a path that does not exist.
|
|
230
|
+
|
|
231
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: `ReelSet.getTargets(): ColumnTarget[]` and `Reel.getTarget()`. The whole board as the same shape `setResult` takes -- buffers included, big-symbol anchors at their true positions -- so `reelSet.setResult(reelSet.getTargets())` reproduces what is on screen.
|
|
232
|
+
|
|
233
|
+
`getVisibleGrid()` is unchanged and still returns `string[][]`. It reports the visible window only, so it cannot be replayed: a block anchored in `bufferStart` with just its tail showing reads as that id at visible cell 0, and feeding that back re-anchors the block there. Use `getVisibleGrid()` to read the board for win logic, and `getTargets()` to capture and replay one.
|
|
234
|
+
|
|
235
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: `debugOverlay` gains the axis-aware layers.
|
|
236
|
+
|
|
237
|
+
- `axis` draws one arrow per reel along the travel axis, pointing the way it goes.
|
|
238
|
+
- `feed` marks the strip edge new symbols arrive at.
|
|
239
|
+
- `thresholds` draws the two wrap lines, so contract laws L7 and L9 are watchable: drive a spin and no symbol should ever be drawn past one.
|
|
240
|
+
- `hud` now reports orientation, direction and feed edge per reel (`r0 VF feed=start spd=... cells=...`).
|
|
241
|
+
|
|
242
|
+
Add: `overlay.describe()` returns a plain-JSON summary of what those layers represent, per reel - orientation, direction, feed edge, the arrow's signed main-axis span, the feed marker and both thresholds. PixiJS renders to a canvas that CI and AI agents cannot see; this is the same information in a form `expect` can read. A mirrored arrow has identical bounds, so the signed span is the only thing that can tell a reverse reel from a forward one.
|
|
243
|
+
|
|
244
|
+
Fixed: the `buffers` and `hud` layers positioned themselves off `container.x` / `mainOffset` directly, so they drew in the wrong place on a horizontal set. Both now project through the reel's axis, as does every new layer. Each layer's `Graphics` carries a `label` (`pixi-reels:debugOverlay:<layer>`) for the Pixi devtools and for tests.
|
|
245
|
+
|
|
246
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: reverse and mixed per-reel travel direction now spin and land correctly on a vertical set. `StopSequencer` feeds the target frame from the direction-appropriate edge (head-first for reverse reels, tail-first for forward), so `direction('reverse')` (roll-up) and `directionPerReel([...])` (alternating columns) land the exact requested grid. Forward reels are unchanged. Horizontal orientation still fails loud until its set geometry lands.
|
|
247
|
+
|
|
248
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: `orientation('horizontal')` for uniform grids. A single horizontal reel is the banner - cells march along X, the strip travels on X, and it spins and lands through the same lifecycle as a vertical set. The builder projects viewport extents, cross-marching pitch and mask rects through the set axis, `Reel` derives its motion cell size / cross pitch from the axis (symbol art still sizes to screen width x height), and `ReelSet.getCellBounds` projects to screen. Pyramid / MultiWays horizontal fail loud for now.
|
|
249
|
+
|
|
250
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: `ReelSetBuilder.orientation()` / `direction()` / `directionPerReel()` and per-reel `ReelAxis` threading (plus a `reel.axis` accessor). The axis is wired through the motion + phase layers. Vertical forward is fully supported. `orientation('horizontal')` and any reverse direction fail loud at `build()` for now - their set-level geometry and the StopSequencer feed edge (ADR 016 section 6.1) land in a later commit, so failing loud beats a mis-laid or non-landing spin.
|
|
251
|
+
|
|
252
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: fire the declared-but-unfired `spotlight:start` (with the highlighted positions) and `spotlight:end` events. `SymbolSpotlight` now receives the ReelSet emitter and brackets each spotlight presentation; a teardown with nothing active stays silent.
|
|
253
|
+
|
|
254
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: `debugOverlay(reelSet, { layers, live, ticker })` - a layered visual debug overlay for the static / at-rest layers (`mask`, `cells`, `buffers`, `bounds`, `blocks`, `pins`, `hud`). It draws into a `Container` added to the `ReelSet` itself, so it renders above the viewport (including the spotlight container) rather than under it like `showMask`. The handle exposes `setLayers(...)`, `redraw()` and `destroy()`, implements `Disposable`, pools its `Graphics`/`Text` (never recreated per frame), and when `live: true` drives per-frame redraw of the live layers through `TickerRef` (default `Ticker.shared`, override via `ticker`). Static layers only redraw on `shape:changed` / `adjust:complete`. Also reachable as `__PIXI_REELS_DEBUG.overlay(...)`. Dev-only, same caveat as `enableDebug`: it reads internals, is not semver-protected, and must not reach a production bundle. The axis / feed / thresholds layers arrive with A11b once `ReelAxis` is wired through `Reel`.
|
|
255
|
+
|
|
256
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Add: `ReelAxis` projection value object (`reelAxis()`, `VERTICAL_FORWARD`) plus `Orientation`/`Direction` types. Unused for now - the foundation for orientation-generalized motion (ADR 016). No behavior change.
|
|
257
|
+
|
|
258
|
+
### Patch Changes
|
|
259
|
+
|
|
260
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Docs: document `anticipation:reel`, `anticipation:reelEnd` and `cascade:gravity:error`, which the engine emitted but no page mentioned.
|
|
261
|
+
|
|
262
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Perf: `build()` no longer constructs and discards an `OffsetCalculator`.
|
|
263
|
+
|
|
264
|
+
The instance was never read, but its constructor runs `_compute()`, so every
|
|
265
|
+
`ReelSetBuilder.build()` was laying out a full per-reel/per-cell offset table
|
|
266
|
+
and throwing it away. Confirmed it contains no `throw`, so it was not doubling
|
|
267
|
+
as a validator. Also drops an unused local in `StartPhase`. No behaviour change.
|
|
268
|
+
|
|
269
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: the big-symbol weight error said random fill "never enters random fill in v1", which reads as a v1-only restriction on a v2 build. It is not version-scoped.
|
|
270
|
+
|
|
271
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: an empty `bufferStart` / `bufferEnd` no longer trips the buffer-range check.
|
|
272
|
+
|
|
273
|
+
`assertBufferCountsInRange` compared `highestDefinedIndex(entries) >= capacity`, and that helper returns `-1` for "no entries at all". When a reel reports a NEGATIVE capacity -- which happens transiently during a cascade, where the strip is briefly shorter than `bufferStart + visibleCells` -- the test became `-1 >= -4` and threw on a column that specified no buffer entries at all:
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
runCascade(): nextGrid column 0: bufferEnd has a symbol at index -1,
|
|
277
|
+
beyond engine bufferSymbols=-4
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
The check only ever ran on `setResult`, where reels are settled and capacity is never negative, so it stayed latent until `refill()` and `runCascade()` began validating their grids in this release. A column that specifies nothing can never have an entry dropped, so it is always in range.
|
|
281
|
+
|
|
282
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: a horizontal reel set laid out its initial strip with no gap between cells. `Reel._setupSymbolPositions` stepped by `spinCellSize + symbolGapY` -- the screen VERTICAL gap -- instead of the travel-axis gap. On a vertical set the two are the same value, so this was invisible; on a horizontal one the main gap is `symbolGapX`, so symbols touched until the first spin handed positions to `ReelMotion` (which projects correctly) and they silently snapped apart.
|
|
283
|
+
|
|
284
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Docs: the 2.0 migration guide subscribed with `reelSet.on(...)`, which does not exist. Corrected to `reelSet.events.on(...)`.
|
|
285
|
+
|
|
286
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: `movePin()` flew the symbol to the wrong place on a horizontal reel set. It read `_pinOverlayCellMain` (a travel-axis coordinate, which is `x` when `orientation('horizontal')`) straight into `.y`, and the reel's main offset into `.x`. Both are numbers, so nothing threw. Now routed through `axis.toScreen`, like every other pin-overlay site.
|
|
287
|
+
|
|
288
|
+
Fix: `setShape()`'s parameter and the `shape:changed` payload label are `cellsPerReel`, not the v1 `rowsPerReel`. The old name shipped in the `.d.ts` and in two runtime error messages.
|
|
289
|
+
|
|
290
|
+
Fix: the big-symbol split error printed `anchor + h + distance` while the predicate tested `anchor + h - 1 + distance`, so the number in the message was one off from the one that failed.
|
|
291
|
+
|
|
292
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: `debugOverlay`'s `hud` layer is readable. It stacks its lines instead of overprinting them, and sits on a backing plate.
|
|
293
|
+
|
|
294
|
+
Each line was anchored at its own reel's top-left corner, which assumes a line fits inside a reel. It does not: roughly 40 characters at 11px monospace is ~230px against a cell that is typically ~100px wide. On any set past two reels every line ran across its neighbours into an unreadable smear, and it got worse the more reels you had -- which is exactly when the hud is worth reading.
|
|
295
|
+
|
|
296
|
+
The lines are now one left-aligned column anchored inside the mask's top-left, one per reel, so they read at any reel count and in either orientation. Stacking them _outside_ the mask would keep the reels clear, but a host that framed its camera on the reel set before the overlay existed then renders the whole block off-screen, and an invisible hud is worse than a cluttered one. Drop `hud` from `layers` if it covers art you need to see.
|
|
297
|
+
|
|
298
|
+
Also: 10px on an 11px leading rather than 11/13, a translucent black plate behind the column so white text survives bright symbols, and `resolution = 1` on the lines so small glyphs rasterize blocky instead of grey-smeared.
|
|
299
|
+
|
|
300
|
+
The `r<n>` prefix still ties a line to its reel, and the `cells` layer still labels each cell `reel,cell`. Nothing about the reported fields changed.
|
|
301
|
+
|
|
302
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: `reelSet.destroy()` left every in-flight spin-phase tween running. `SpinController.destroy()` dropped its active-phase map without skipping the phases first, and `onSkip()` is the only thing that kills the gsap timelines they own (start ramp, anticipation, stop bounce, cascade fall/drop-in). Those timelines outlived the set and kept writing reel speed and symbol view positions to display objects `destroy()` had already freed. It bites hardest in the setup the docs recommend — gsap driven off a PixiJS ticker — because the orphaned tweens do not stop when the set's own app goes away: any other live ticker keeps advancing the shared root timeline. Destroying a reel set mid-spin now force-completes its active phases first, and bumps the spin generation so no already-awaiting phase chain starts a fresh phase on the way down.
|
|
303
|
+
|
|
304
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: the auto-picked mask strategy's console notice names the gap it actually keyed on. The auto-pick has read the CROSS-axis gap since `orientation()` landed, but the message still said `symbolGap.x > 0` verbatim -- so on a horizontal set it pointed at the main-axis knob, and turning that one did nothing to the behaviour being explained. It now reads `symbolGap.x` on a vertical set and `symbolGap.y` on a horizontal one.
|
|
305
|
+
|
|
306
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: `setResult()` and `initialFrame()` now reject a plain `string[][]` with a message that names the fix. Previously the value reached a spread of `target.visible` deep in the frame pipeline and threw `TypeError: target.visible is not iterable` -- after the reels were already moving, so the spin promise never settled and the reel spun forever with no usable clue.
|
|
307
|
+
|
|
308
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: the published tarball now actually contains `README.md` and `LICENSE`. Both were listed in `package.json`'s `files` but neither existed inside the package, and npm drops a `files` entry that matches nothing without warning -- so the npm page would have been blank and an MIT-licensed package would have shipped no licence text.
|
|
309
|
+
|
|
310
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Internal (docs site): recipes can return a `stage` container so a multi-set composition scales and centres as one. No library change.
|
|
311
|
+
|
|
312
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: `movePin` placed the flight symbol at the source cell's bare reel-local Y, dropping the reel's container offset and mixing the masked (reel-local) vs unmasked (viewport-space) coordinate conventions. Route flight placement through `_pinOverlayCellY` so it agrees with pin overlays on any layout with a nonzero reel offset. No API change.
|
|
313
|
+
|
|
314
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Docs: ADRs 016 / 017 / 018 move off Proposed and record where the implementation diverged from the plan; `ROADMAP.md` and `TODO.md` are reconciled (horizontal reels, mixed direction per reel and roll-up all close in 2.0.0). No code change.
|
|
315
|
+
|
|
316
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Refactor: `ReelMotion` now projects through a `ReelAxis` and derives symbol positions from array index (and rotation count from total travel) instead of accumulating deltas. Behavior is unchanged for the default vertical/forward axis; the derive model also fixes a latent float-residue wrap-skip at exact N-slot travel (motion contract L7). Internal - the axis defaults to vertical/forward, so callers are unaffected.
|
|
317
|
+
|
|
318
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Refactor: `Reel` routes its own position writes through the injected `ReelAxis` - container placement (cross marches reels, main carries the offset), `_placeSymbolView`, the unmasked re-sync (absolute cross, incremental main), and every reel-local conversion. Behavior is unchanged for the default vertical/forward axis. Internal; `ReelConfig` gains an optional `axis`.
|
|
319
|
+
|
|
320
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Refactor: rename `SpinningMode.computeDeltaY(symbolHeight, ...)` to `computeDelta(slotPitch, ...)`. The parameter was always the slot pitch (the caller passes `motion.slotHeight`); the name now matches. Returns signed travel along the reel's axis. The full-slot wrap-skip risk the old cap guarded (contract L7) is gone with the derive-from-index motion, so the cap is now only smoothing.
|
|
321
|
+
|
|
322
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Refactor: route the non-cascade spin phases' GSAP position tweens through `reel.axis` instead of a hardcoded `.y`. StopPhase's landing bounce now overshoots in the direction of travel via `base + axis.polarity * bounceDistance` on `axis.mainProp`, and reads/restores the reel container's base position through `axis.getMain`/`setMain`. AdjustPhase's MultiWays pin-overlay squash and slide now write `scale[axis.mainProp]` and position via `axis.setMain`/`setCross`. StartPhase's step-back is a speed tween (already direction-relative through the motion layer) and is unchanged. Vertical/forward is byte-identical.
|
|
323
|
+
|
|
324
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Refactor: the tumble cascade phases position symbols through the injected `ReelAxis`. `CascadeFallPhase` and `CascadeDropInPhase` read start positions via `axis.getMain`, write via `axis.setMain`, and build their GSAP tweens with a computed `axis.mainProp` key; fall/drop distances now carry `axis.polarity` so gravity follows the reel's travel axis. Grid origins (`originalRow * cellHeight`) stay direction-agnostic. Behavior is unchanged for the default vertical/forward axis (`mainProp: 'y'`, `polarity: 1`). `CascadePlacePhase` and `tumbleAlgorithm` were unaffected (visibility/identity swap and cell-index math, no position writes). Internal only.
|
|
325
|
+
|
|
326
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: `ReelViewport.updateMaskSize` now resizes the dim overlay. A viewport resize (e.g. a MultiWays reshape growing the tallest reel) no longer leaves the spotlight dimming a stale rectangle.
|
|
327
|
+
|
|
328
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Docs: a guide for orientation and direction (the headline of 2.0.0), the new builder methods in the API reference, and the debug overlay's axis layers plus `describe()` in the debugging guide. No code change.
|
|
329
|
+
|
|
330
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Internal: browser coverage for all four orientation x direction combinations, via a new `tests/e2e/fixtures/orientation-matrix` fixture and a Playwright spec wired into CI. No library change.
|
|
331
|
+
|
|
332
|
+
- [#197](https://github.com/schmooky/pixi-reels/pull/197) [`847d9cd`](https://github.com/schmooky/pixi-reels/commit/847d9cde6c3757fc6f83360c49764c55a0f98dcc) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Internal: cover the natural (non-slam) stop on reverse and mixed-direction reels. No API change - this closes a test gap, it does not change behaviour.
|
|
333
|
+
|
|
334
|
+
## 1.6.1
|
|
335
|
+
|
|
336
|
+
### Patch Changes
|
|
337
|
+
|
|
338
|
+
- [#194](https://github.com/schmooky/pixi-reels/pull/194) [`1a9e258`](https://github.com/schmooky/pixi-reels/commit/1a9e25844536a4d2fc7c770392812ca078b5c173) Thanks [@igaming-bulochka](https://github.com/igaming-bulochka)! - Fix: commit a MultiWays reshape BEFORE the fall in cascade (classic-tumble) mode when the target shape is known at spin time. `CascadeFallPhase` drops a reel's current visible rows, and the reshape used to run only after the fall (between SPIN and STOP, where standard mode's spin blur hides it), so in cascade mode a reel that changed height dropped its old, differently-sized board and then snapped to the new shape. a reel visibly changing height mid-tumble. Now, if `setShape()` is called BEFORE `spin({ mode: 'cascade' })`, the reshape commits before the fall so the reel falls at its target height. The legacy `spin()` then `setShape()` ordering is unchanged (the reshape still lands after SPIN). For a clean per-spin reshape in a classic tumble, call `setShape()` before `spin({ mode: 'cascade' })`.
|
|
339
|
+
|
|
3
340
|
## 1.6.0
|
|
4
341
|
|
|
5
342
|
### Minor Changes
|
package/CONTRIBUTING.md
CHANGED
|
@@ -10,7 +10,6 @@ cd pixi-reels
|
|
|
10
10
|
pnpm install
|
|
11
11
|
pnpm --filter pixi-reels test # vitest + typecheck
|
|
12
12
|
pnpm site:dev # docs site at http://localhost:4321
|
|
13
|
-
pnpm --filter classic-spin dev # classic 5×3 example
|
|
14
13
|
```
|
|
15
14
|
|
|
16
15
|
Node 20+ is required. The repo uses pnpm workspaces.
|
|
@@ -29,7 +28,7 @@ Node 20+ is required. The repo uses pnpm workspaces.
|
|
|
29
28
|
pnpm changeset
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
Pick the affected packages and the bump kind (`patch` / `minor` / `major`) and commit the resulting `.changeset/*.md` file. Changes to private
|
|
31
|
+
Pick the affected packages and the bump kind (`patch` / `minor` / `major`) and commit the resulting `.changeset/*.md` file. Changes to private packages (`@pixi-reels/site`, `@pixi-reels/cheats`, e2e fixtures) don't need a changeset — those are deployed, not published.
|
|
33
32
|
|
|
34
33
|
5. **Open a PR.** The template asks for a summary, a test plan, and confirmation that a changeset was added.
|
|
35
34
|
|
package/README.md
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
[](https://bundlephobia.com/package/pixi-reels)
|
|
6
6
|
[](https://github.com/schmooky/pixi-reels/actions/workflows/ci.yml)
|
|
7
7
|
[](https://github.com/schmooky/pixi-reels/actions/workflows/npm-publish.yml)
|
|
8
|
-
[](
|
|
8
|
+
[](https://github.com/schmooky/pixi-reels/blob/main/LICENSE)
|
|
9
9
|
[](https://pixijs.com/)
|
|
10
10
|
[](https://www.typescriptlang.org/)
|
|
11
11
|
|
|
12
|
-
`pixi-reels`
|
|
12
|
+
`pixi-reels` is a reel engine for [PixiJS v8](https://pixijs.com/). It ships reel-only primitives: spin lifecycle, symbols, speed profiles, pins, cascades, win presenter. Win math, paytable math, RNG, and audio live in consumer code.
|
|
13
13
|
|
|
14
14
|
Install:
|
|
15
15
|
|
|
@@ -17,7 +17,7 @@ Install:
|
|
|
17
17
|
pnpm add pixi-reels pixi.js gsap
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
Docs and recipes at [pixi-reels.schmooky.dev](https://pixi-reels.schmooky.dev). Agent-facing instructions are in [AGENTS.md](
|
|
20
|
+
Docs and recipes at [pixi-reels.schmooky.dev](https://pixi-reels.schmooky.dev). Agent-facing instructions are in [AGENTS.md](https://github.com/schmooky/pixi-reels/blob/main/AGENTS.md).
|
|
21
21
|
|
|
22
22
|
## Quick start
|
|
23
23
|
|
|
@@ -30,7 +30,7 @@ await app.init({ width: 900, height: 540, background: '#0a0d14' });
|
|
|
30
30
|
document.body.appendChild(app.canvas);
|
|
31
31
|
|
|
32
32
|
const reelSet = new ReelSetBuilder()
|
|
33
|
-
.reels(5).
|
|
33
|
+
.reels(5).visibleCells(3).symbolSize(140, 140)
|
|
34
34
|
.symbols((r) => {
|
|
35
35
|
r.register('cherry', SpriteSymbol, { textures: { cherry: cherryTex } });
|
|
36
36
|
r.register('seven', SpriteSymbol, { textures: { seven: sevenTex } });
|
|
@@ -50,6 +50,34 @@ reelSet.setResult(result.map((visible) => ({ visible })));
|
|
|
50
50
|
await spin;
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
## Any orientation, any direction
|
|
54
|
+
|
|
55
|
+
One engine runs four layouts. Anticipation, cascades, spotlight, pins, big
|
|
56
|
+
symbols, pyramids and MultiWays all work in every one of them.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
new ReelSetBuilder()
|
|
60
|
+
.orientation('horizontal') // strip travels on X, reels march down Y
|
|
61
|
+
.direction('reverse') // ...and travels right-to-left
|
|
62
|
+
.directionPerReel(['forward', 'reverse', 'forward']) // or mix per reel
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
| | `direction('forward')` | `direction('reverse')` |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| `orientation('vertical')` | symbols fall (the default) | a roll-up |
|
|
68
|
+
| `orientation('horizontal')` | a sideways banner | ...running the other way |
|
|
69
|
+
|
|
70
|
+
Screen-space inputs stay screen-space: `symbolSize(width, height)`,
|
|
71
|
+
`ReelSymbol.resize(width, height)` and `getCellBounds` never change meaning,
|
|
72
|
+
so a horizontal set is the vertical one transposed and your own symbol
|
|
73
|
+
classes need no changes. Grid indices do not move either -- cell
|
|
74
|
+
`(reel, cell)` means the same thing whichever way the strip runs.
|
|
75
|
+
|
|
76
|
+
Travel changes motion; facing changes art; they never change each other. A
|
|
77
|
+
reel spinning sideways still renders every symbol upright.
|
|
78
|
+
|
|
79
|
+
See [the guide](https://pixi-reels.schmooky.dev/guides/orientation-and-direction/).
|
|
80
|
+
|
|
53
81
|
## Core API at a glance
|
|
54
82
|
|
|
55
83
|
```ts
|
|
@@ -66,7 +94,17 @@ reelSet.events.on('spin:reelLanded', (i, s) => {/* ... */})
|
|
|
66
94
|
reelSet.destroy() // Full teardown
|
|
67
95
|
```
|
|
68
96
|
|
|
69
|
-
See [/api/](https://pixi-reels.schmooky.dev/api/) for the full TypeDoc reference
|
|
97
|
+
See [/api/](https://pixi-reels.schmooky.dev/api/) for the full TypeDoc reference.
|
|
98
|
+
Upgrading? [Migrating to 2.0](https://pixi-reels.schmooky.dev/docs/migrating-to-2-0/)
|
|
99
|
+
lists every breaking change and starts with the codemod.
|
|
100
|
+
|
|
101
|
+
The codemod is not on npm yet, so run it from a clone:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
git clone https://github.com/schmooky/pixi-reels
|
|
105
|
+
cd pixi-reels && pnpm install
|
|
106
|
+
node packages/pixi-reels-codemod/bin/cli.js v1-to-v2 /path/to/your/src
|
|
107
|
+
```
|
|
70
108
|
|
|
71
109
|
## Spine symbols (optional subpath)
|
|
72
110
|
|
|
@@ -94,24 +132,24 @@ In the browser console (or via Playwright / agent eval):
|
|
|
94
132
|
```
|
|
95
133
|
__PIXI_REELS_DEBUG.log() // ASCII grid + state snapshot
|
|
96
134
|
__PIXI_REELS_DEBUG.snapshot() // Full JSON state
|
|
97
|
-
__PIXI_REELS_DEBUG.trace() // Log
|
|
135
|
+
__PIXI_REELS_DEBUG.trace() // Log spin, skip, speed, spotlight, shape, pin events
|
|
98
136
|
```
|
|
99
137
|
|
|
100
138
|
## Examples
|
|
101
139
|
|
|
102
|
-
Runnable
|
|
140
|
+
Runnable demos live on the docs site under [`/recipes`](https://pixi-reels.pages.dev/recipes/) -- about 130 of them, each with its full source next to it, covering line pays, cascades, hold and win, big symbols, nudge, anticipation and every mechanic that used to have its own example app. They run in the page, so there is nothing to clone or start.
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
pnpm site:dev # the whole recipe set, locally
|
|
144
|
+
```
|
|
103
145
|
|
|
104
|
-
|
|
105
|
-
|------------------|------------------------------------------------------------|----------------------------------------|
|
|
106
|
-
| `classic-spin` | 5x3 line-pay slot with sprite symbols and speed toggle | `pnpm --filter classic-spin dev` |
|
|
107
|
-
| `cascade-tumble` | 6x5 tumble mechanic with win spotlight between stages | `pnpm --filter cascade-tumble dev` |
|
|
108
|
-
| `sandbox` | Single editable TS file, HMR rebuild | `pnpm --filter sandbox dev` |
|
|
146
|
+
The standalone `examples/` apps moved to their own repo in 2.0. Keeping two parallel demo surfaces in one repo meant every API change had to be made twice, and the example half kept losing.
|
|
109
147
|
|
|
110
148
|
## Peer dependencies
|
|
111
149
|
|
|
112
|
-
- `pixi.js` ^8.
|
|
113
|
-
- `gsap` ^3.
|
|
114
|
-
- `@esotericsoftware/spine-pixi-v8`
|
|
150
|
+
- `pixi.js` ^8.18.1
|
|
151
|
+
- `gsap` ^3.15.0
|
|
152
|
+
- `@esotericsoftware/spine-pixi-v8` ~4.2.110 (optional, only if you use `SpineReelSymbol`)
|
|
115
153
|
|
|
116
154
|
## Contributing
|
|
117
155
|
|