# packages/core/src/features/sprites/sprite.ts
This is the source snapshot used to build these API details. [View this revision on GitHub](https://github.com/benlesh/pibbl/blob/272a94aaf62e0bd6ad8726a4c607a76a9ec44ca1/packages/core/src/features/sprites/sprite.ts#L18).

[Back to reference](/reference/components/sprite/)

<pre class="api-source"><code><span id="L1"><a href="#L1" aria-label="Line 1">1</a> import { definePrimitive } from '../../lib/define-primitive.js';</span>
<span id="L2"><a href="#L2" aria-label="Line 2">2</a> import { useRectPath } from '../../lib/hooks/use-rect-path.js';</span>
<span id="L3"><a href="#L3" aria-label="Line 3">3</a> import { wireCommonEvents } from '../../lib/util/wire-common-events.js';</span>
<span id="L4"><a href="#L4" aria-label="Line 4">4</a> import type { ImageProps } from '../../lib/components/img.js';</span>
<span id="L5"><a href="#L5" aria-label="Line 5">5</a> import type { SystemStyle } from '../../lib/types.js';</span>
<span id="L6"><a href="#L6" aria-label="Line 6">6</a> import { frameRecord, type SpriteFrame } from './model.js';</span>
<span id="L7"><a href="#L7" aria-label="Line 7">7</a> /** Drawing inputs; frame also accepts a signal through Pibbl's declared primitive inputs. See {@link SpriteFrame}. */</span>
<span id="L8"><a href="#L8" aria-label="Line 8">8</a> export interface SpriteProps extends ImageProps {</span>
<span id="L9"><a href="#L9" aria-label="Line 9">9</a>   /** Atlas frame to draw; its sheet must remain undisposed. */ readonly frame: SpriteFrame;</span>
<span id="L10"><a href="#L10" aria-label="Line 10">10</a>   /** Image interpolation; defaults to linear. */ readonly sampling?: 'nearest' | 'linear';</span>
<span id="L11"><a href="#L11" aria-label="Line 11">11</a>   /** Normalized origin within the original frame, defaulting to the top-left. */ readonly anchor?: Readonly&lt;{ /** Horizontal anchor fraction. */ x: number; /** Vertical anchor fraction. */ y: number }&gt;;</span>
<span id="L12"><a href="#L12" aria-label="Line 12">12</a>   /** Mirror the frame horizontally. */ readonly flipX?: boolean;</span>
<span id="L13"><a href="#L13" aria-label="Line 13">13</a>   /** Mirror the frame vertically. */ readonly flipY?: boolean;</span>
<span id="L14"><a href="#L14" aria-label="Line 14">14</a> }</span>
<span id="L15"><a href="#L15" aria-label="Line 15">15</a> /** Logical size overrides; omitted dimensions use the original untrimmed frame size. See {@link SpriteFrame}. */</span>
<span id="L16"><a href="#L16" aria-label="Line 16">16</a> 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 }</span>
<span id="L17"><a href="#L17" aria-label="Line 17">17</a> /** Draw a shared atlas frame, preserving its logical geometry across frame changes. See {@link SpriteFrame}. */</span>
<span id="L18"><a href="#L18" aria-label="Line 18">18</a> export const Sprite = definePrimitive&lt;SpriteProps, SpriteStyle&gt;((props, style, ctx) =&gt; {</span>
<span id="L19"><a href="#L19" aria-label="Line 19">19</a>   const record = frameRecord(props.frame);</span>
<span id="L20"><a href="#L20" aria-label="Line 20">20</a>   const width = style.width ?? props.frame.width, height = style.height ?? props.frame.height;</span>
<span id="L21"><a href="#L21" aria-label="Line 21">21</a>   const x = -(props.anchor?.x ?? 0) * width, y = -(props.anchor?.y ?? 0) * height;</span>
<span id="L22"><a href="#L22" aria-label="Line 22">22</a>   const path = useRectPath(x, y, width, height);</span>
<span id="L23"><a href="#L23" aria-label="Line 23">23</a>   const r = record.rect;</span>
<span id="L24"><a href="#L24" aria-label="Line 24">24</a>   ctx.save();</span>
<span id="L25"><a href="#L25" aria-label="Line 25">25</a>   try {</span>
<span id="L26"><a href="#L26" aria-label="Line 26">26</a>     ctx.globalAlpha *= style.opacity ?? 1;</span>
<span id="L27"><a href="#L27" aria-label="Line 27">27</a>     ctx.imageSmoothingEnabled = props.sampling !== 'nearest';</span>
<span id="L28"><a href="#L28" aria-label="Line 28">28</a>     ctx.translate(x + (props.flipX ? width : 0), y + (props.flipY ? height : 0));</span>
<span id="L29"><a href="#L29" aria-label="Line 29">29</a>     ctx.scale((props.flipX ? -1 : 1) * width / props.frame.width, (props.flipY ? -1 : 1) * height / props.frame.height);</span>
<span id="L30"><a href="#L30" aria-label="Line 30">30</a>     ctx.translate(record.trim?.x ?? 0, record.trim?.y ?? 0);</span>
<span id="L31"><a href="#L31" aria-label="Line 31">31</a>     if (record.rotated) { ctx.translate(0, r.width); ctx.rotate(-Math.PI / 2); }</span>
<span id="L32"><a href="#L32" aria-label="Line 32">32</a>     ctx.drawImage(record.image, r.x, r.y, r.width, r.height, 0, 0, r.width, r.height);</span>
<span id="L33"><a href="#L33" aria-label="Line 33">33</a>   } finally { ctx.restore(); }</span>
<span id="L34"><a href="#L34" aria-label="Line 34">34</a>   wireCommonEvents(props, path, true, 0, undefined, { x, y, width, height });</span>
<span id="L35"><a href="#L35" aria-label="Line 35">35</a> });</span>
<span id="L36"><a href="#L36" aria-label="Line 36">36</a> </span></code></pre>

## Documentation version

Documentation built with @pibbl/core 0.0.2, revision 272a94a. ALPHA — NOT FOR PRODUCTION USE.
