import { Container, Graphics } from 'pixi.js'; import { Disposable } from '../utils/Disposable.js'; /** * Bounding rectangle for one reel. what `MaskStrategy` builds the clip * geometry from. Local to ReelViewport (origin = viewport top-left). */ export interface ReelMaskRect { /** Left edge of the reel column (= reel.container.x). */ x: number; /** Top edge of the reel box (= reel.offsetY). */ y: number; /** Width of the reel column. equals one symbol cell wide. */ width: number; /** Height of the reel box. equals reel.reelHeight. */ height: number; } /** * Strategy for building the viewport's clip mask. Public. pass a custom * implementation to `ReelSetBuilder.maskStrategy(...)` to clip the reels * with any shape PixiJS Graphics can express (rounded frames, hex grids, * etc.). v1 ships two strategies: * * - {@link RectMaskStrategy}. one rect per reel (default). Good for * pyramid layouts; symbols never leak buffer rows above/below. * - {@link SharedRectMaskStrategy}. single bounding-box rect spanning * every reel's tallest extent. Big symbols spanning multiple reels * render correctly even when reels have horizontal gaps; cross-reel * overlap (e.g. a 2×2 bonus straddling reel 2 and 3 with `symbolGap.x>0`) * needs this strategy. */ export interface MaskStrategy { /** Build (or rebuild) the mask graphic. Returns the Graphics to use as the mask. */ build(rects: ReelMaskRect[], totalWidth: number, totalHeight: number): Graphics; /** Update the mask when reel boxes resize (e.g. MultiWays reshape). */ update(graphics: Graphics, rects: ReelMaskRect[], totalWidth: number, totalHeight: number): void; } /** * v1 default: a per-reel rectangular mask. Each reel is clipped to its own * `(offsetY, reelHeight)` box so pyramid shapes clip cleanly without * buffer-row peek above or below short reels. * * PixiJS masks support multiple shapes inside a single Graphics. the union * of every filled shape is the visible region. So drawing one rect per reel * gives the engine a jagged-but-rectangular mask without a custom shader. * * **Caveat:** if reels have a horizontal `symbolGap.x > 0`, a symbol that * extends across the gap (e.g. a 2×2 bonus on a non-zero-gap layout) will * be clipped between the columns. Use {@link SharedRectMaskStrategy} in * that case, or set `symbolGap: { x: 0, y: ... }`. * * If `rects` is empty (the builder hasn't supplied per-reel rects yet), * this falls back to a single bounding-box rect. */ export declare class RectMaskStrategy implements MaskStrategy { build(rects: ReelMaskRect[], totalWidth: number, totalHeight: number): Graphics; update(g: Graphics, rects: ReelMaskRect[], totalWidth: number, totalHeight: number): void; private _draw; } /** * Single bounding-box mask covering every reel's tallest extent. Use this * when symbols need to overlap across reel boundaries. typical for slots * with big symbols that span multiple columns (a 2×2 bonus, a 3×3 giant) * AND a non-zero `symbolGap.x`. Per-reel rects would clip those symbols at * the column gaps; a single shared rect keeps them visible. * * Pyramid layouts using this strategy will show buffer rows above/below * short reels (the "pyramid peek". covered by frame art in production). * * @example * builder.maskStrategy(new SharedRectMaskStrategy()) */ export declare class SharedRectMaskStrategy implements MaskStrategy { build(rects: ReelMaskRect[], totalWidth: number, totalHeight: number): Graphics; update(g: Graphics, rects: ReelMaskRect[], totalWidth: number, totalHeight: number): void; private _draw; } /** * The clipping window + layering tricks for a reel set. * * The viewport is the "looking-glass" of the slot: a rectangle the size * of the visible grid with a PixiJS mask so symbols scrolling above or * below the visible rows are hidden. It also provides three stacking * layers so win animations can break out of the mask: * * - `maskedContainer`. the normal place for reels. Clipped to the * visible area so buffer rows never leak. * - `unmaskedContainer`. rendered on top of the mask. Use for a symbol * whose celebration animation expands beyond its cell (a big expanding * wild, a splash frame). * - `spotlightContainer`. above everything else. Win spotlight lifts * winning symbols here temporarily so dim overlay + bounce don't clip. * * `dimOverlay` is a semi-transparent rectangle the spotlight fades in * behind the promoted winners to visually push the losers into the * background. */ export declare class ReelViewport extends Container implements Disposable { readonly maskedContainer: Container; readonly unmaskedContainer: Container; readonly spotlightContainer: Container; readonly dimOverlay: Graphics; private _mask; private _maskStrategy; private _maskWidth; private _maskHeight; private _maskRects; private _isDestroyed; /** * Number of active dim requests. The single overlay is shared by the * spotlight and cascade `destroySymbols({ dim })`; reference-counting it * keeps the dim up until the LAST consumer releases it, so an overlapping * pair can't hide it out from under the other. */ private _dimCount; constructor(width: number, height: number, position?: { x: number; y: number; }, maskStrategy?: MaskStrategy); /** The viewport mask bounding box width (independent of children bounds). */ get maskWidth(): number; /** The viewport mask bounding box height. */ get maskHeight(): number; /** Per-reel mask rects last passed to the strategy. Used by debug overlays. */ get maskRects(): readonly ReelMaskRect[]; /** Internal mask Graphics. Exposed so debug helpers can recolor it. */ get maskGraphics(): Graphics; get isDestroyed(): boolean; /** Show the dim overlay with given opacity. Reference-counted with hideDim. */ showDim(alpha?: number): void; /** Release one dim request; hides the overlay only when the last one clears. */ hideDim(): void; /** Update mask size and per-reel rects. Used after pyramid/MultiWays shape changes. */ updateMaskSize(width: number, height: number, rects?: ReelMaskRect[]): void; destroy(): void; } //# sourceMappingURL=ReelViewport.d.ts.map