Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/sanchedev/tiny-engine/llms.txt

Use this file to discover all available pages before exploring further.

Sprites in tiny-engine support a set of CSS-inspired visual filters applied directly as props on the <sprite> node. Each filter maps to a canvas rendering operation executed every frame during the sprite’s draw call — no extra nodes or post-processing passes required.

Filter props

PropTypeRangeDescription
brightnessnumber02+0 renders the sprite black, 1 is the original appearance, 2 approaches white.
grayscalenumber010 leaves colours unchanged, 1 converts the sprite fully to grayscale.
modulateColorRGBA 0–1Tints the sprite using canvas globalCompositeOperation: 'multiply'. See modulate behaviour below.
contrastnumber02+0 removes all contrast (flat grey), 1 is the original.
saturatenumber02+0 is fully desaturated (greyscale), 1 is the original saturation.
hueRotatenumberdegreesRotates all hues by the given number of degrees (e.g. 180 inverts hues).
invertnumber010 is the original colours, 1 fully inverts them.
opacitynumber010 is fully transparent, 1 is fully opaque.

Applying multiple filters

Any combination of props can be set on the same sprite:
import type { Color } from 'tiny-engine'

const DAMAGE_TINT: Color = [1, 0.2, 0.2, 1] // red tint

function Enemy() {
  return (
    <sprite
      textureId={ENEMY_TEXTURE}
      sourceSize={new Vector2(16, 16)}
      brightness={1.1}
      contrast={1.2}
      saturate={0.8}
      modulate={DAMAGE_TINT}
      opacity={0.9}
    />
  )
}

Reactive filters

Every filter prop accepts a SignalGetter<number> (or SignalGetter<Color> for modulate) in place of a plain value. The sprite re-renders automatically whenever the signal changes — no extra effect or manual update needed.
import { useSignal } from 'tiny-engine/hooks'

function FlashingSprite() {
  const [brightness, setBrightness] = useSignal(1)

  // Example: pulse brightness from a script
  return (
    <sprite
      textureId={TEXTURE}
      sourceSize={new Vector2(16, 16)}
      brightness={brightness}
    />
  )
}
Pass the signal getter (brightness, not brightness()) directly as the prop value. tiny-engine tracks the dependency and schedules a re-draw on change.

The Color type

Color is a fixed-length RGBA tuple where every channel is a number in the 01 range:
type Color = [number, number, number, number]
//            red     green   blue    alpha
Import it from tiny-engine:
import type { Color } from 'tiny-engine'

const red: Color           = [1,   0,   0,   1  ]
const orange: Color        = [1,   0.5, 0,   1  ]
const transparentBlue: Color = [0, 0,   1,   0.5]
Channels map to CSS rgba() but normalised to 01 rather than 0255. An alpha of 1 is fully opaque; 0 is fully transparent. Color is also used by Rectangle.fillColor and Rectangle.strokeColor.

Modulate tinting

The modulate filter differs from the other numeric filters. Instead of using ctx.filter, it:
  1. Draws the sprite normally.
  2. Sets ctx.globalCompositeOperation = 'multiply'.
  3. Fills the sprite bounds with a rectangle of the given RGBA colour.
Multiply blending darkens the sprite by the tint colour — a modulate of [1, 1, 1, 1] (white) leaves the sprite unchanged, while [1, 0, 0, 1] (red) keeps only the red channel, tinting the sprite red.
// Damage flash: briefly tint the sprite red
const DAMAGE_COLOR: Color = [1, 0.3, 0.3, 1]

<sprite textureId={HERO_TEXTURE} modulate={DAMAGE_COLOR} />
Numeric filters (brightness, grayscale, contrast, saturate, hueRotate, invert, opacity) are combined into a single ctx.filter string and applied together before drawing. When multiple filters are set, they stack — for example, setting both brightness={0.5} and contrast={2} applies both adjustments in a single pass. modulate is applied as a separate compositing step after the main draw.

Build docs developers (and LLMs) love