packages/core/src/features/sprites/sprite.ts
This is the source snapshot used to build these API details. View this revision on GitHub.
1 import { definePrimitive } from '../../lib/define-primitive.js';
2 import { useRectPath } from '../../lib/hooks/use-rect-path.js';
3 import { wireCommonEvents } from '../../lib/util/wire-common-events.js';
4 import type { ImageProps } from '../../lib/components/img.js';
5 import type { SystemStyle } from '../../lib/types.js';
6 import { frameRecord, type SpriteFrame } from './model.js';
7 /** Drawing inputs; frame also accepts a signal through Pibbl's declared primitive inputs. See {@link SpriteFrame}. */
8 export interface SpriteProps extends ImageProps {
9 /** Atlas frame to draw; its sheet must remain undisposed. */ readonly frame: SpriteFrame;
10 /** Image interpolation; defaults to linear. */ readonly sampling?: 'nearest' | 'linear';
11 /** Normalized origin within the original frame, defaulting to the top-left. */ readonly anchor?: Readonly<{ /** Horizontal anchor fraction. */ x: number; /** Vertical anchor fraction. */ y: number }>;
12 /** Mirror the frame horizontally. */ readonly flipX?: boolean;
13 /** Mirror the frame vertically. */ readonly flipY?: boolean;
14 }
15 /** Logical size overrides; omitted dimensions use the original untrimmed frame size. See {@link SpriteFrame}. */
16 export interface SpriteStyle extends SystemStyle { /** Logical width; defaults to the original frame width. */ readonly width?: number; /** Logical height; defaults to the original frame height. */ readonly height?: number; /** Opacity multiplier applied to the frame. */ readonly opacity?: number }
17 /** Draw a shared atlas frame, preserving its logical geometry across frame changes. See {@link SpriteFrame}. */
18 export const Sprite = definePrimitive<SpriteProps, SpriteStyle>((props, style, ctx) => {
19 const record = frameRecord(props.frame);
20 const width = style.width ?? props.frame.width, height = style.height ?? props.frame.height;
21 const x = -(props.anchor?.x ?? 0) * width, y = -(props.anchor?.y ?? 0) * height;
22 const path = useRectPath(x, y, width, height);
23 const r = record.rect;
24 ctx.save();
25 try {
26 ctx.globalAlpha *= style.opacity ?? 1;
27 ctx.imageSmoothingEnabled = props.sampling !== 'nearest';
28 ctx.translate(x + (props.flipX ? width : 0), y + (props.flipY ? height : 0));
29 ctx.scale((props.flipX ? -1 : 1) * width / props.frame.width, (props.flipY ? -1 : 1) * height / props.frame.height);
30 ctx.translate(record.trim?.x ?? 0, record.trim?.y ?? 0);
31 if (record.rotated) { ctx.translate(0, r.width); ctx.rotate(-Math.PI / 2); }
32 ctx.drawImage(record.image, r.x, r.y, r.width, r.height, 0, 0, r.width, r.height);
33 } finally { ctx.restore(); }
34 wireCommonEvents(props, path, true, 0, undefined, { x, y, width, height });
35 });
36
Documentation version
Section titled “Documentation version”Documentation built with @pibbl/core 0.0.2, revision 272a94a. ALPHA — NOT FOR PRODUCTION USE.