Skip to content

packages/core/src/features/sprites/sprite.ts

Read as Markdown

This is the source snapshot used to build these API details. View this revision on GitHub.

Back to reference

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 built with @pibbl/core 0.0.2, revision 272a94a. ALPHA — NOT FOR PRODUCTION USE.