Skip to content

Rendering

YAGE uses PixiJS v8 under the hood for all rendering. The @yagejs/renderer package provides components and systems that keep PixiJS in sync with the ECS world automatically — you work with components and the display system handles the rest.

Register the renderer when creating your engine:

import { RendererPlugin } from "@yagejs/renderer";
engine.use(
new RendererPlugin({
width: 1280,
height: 720,
backgroundColor: 0x1a1a2e,
container: document.getElementById("game")!,
}),
);

The plugin creates the PixiJS application, sets up the render loop, and registers all rendering systems.

If you’re shipping pixel art, set pixelArtPreset: true. One flag flips the three settings that otherwise need to be tracked down individually:

  • TextureStyle.defaultOptions.scaleMode = "nearest" — freshly loaded textures sample without bilinear blur.
  • roundPixels: true on the Pixi Application — subpixel transforms don’t smear sprite edges.
  • image-rendering: pixelated (with a -webkit-optimize-contrast Safari fallback) on the canvas element — the browser scales the backing store with nearest-neighbor instead of bicubic.
engine.use(
new RendererPlugin({
width: 320,
height: 240,
container: host,
pixelArtPreset: true,
}),
);

The preset composes with pixi: {...} — explicit options win, so pixi: { roundPixels: false } overrides the preset’s default. Per-texture overrides (source.scaleMode = "linear") keep working too — the preset only changes the default sampling mode.

  • Responsive Canvas — fit modes (letterbox, expand, cover, stretch), drawing into the bars, DOM-overlay positioning, HUD anchoring under cover.
  • Sprites & AnimationSpriteComponent, AnimatedSpriteComponent + AnimationController, asset factories for textures and spritesheets.
  • GraphicsGraphicsComponent for procedural shapes, plus the linearGradient / radialGradient fill helpers.
  • TextTextComponent for free-positioned strings on a layer. (For laid-out text widgets — HUD cards, nameplates, dialog boxes — use UIText + UISurface instead.)
  • CameraCameraEntity (follow, shake, zoom, bounds), camera bindings for parallax / minimaps / billboards, ScreenFollow for entity-anchored UI, and the DisplaySystem.
  • Layers & Draw Order — declaring render layers, depth sorting (Y-sort) so a top-down game paints entities in the right order, and SortGroupComponent for multi-part entities.

The renderer’s components are thin shells around their PixiJS counterparts. You’ll see two patterns called out in each section:

  • Escape hatch — the wrapper exposes the underlying pixi display object (.sprite on SpriteComponent, .graphics on GraphicsComponent, .text on TextComponent, etc.). When you need to reach for a pixi feature the wrapper doesn’t surface, drop down to the pixi handle directly.
  • Thin wrapper / re-export — config options forward to pixi as-is (TextComponent’s style is a pixi TextStyleOptions; GradientFill IS pixi FillGradient). When in doubt about an option, the upstream pixi docs are the source of truth.
  • Type aliases, not raw pixi types — every exported field, parameter, and return type (SpriteComponent.sprite, RenderLayer.container, …) is typed through @yagejs/renderer’s own alias names (DisplaySprite, DisplayContainer, GraphicsContext, ColorValue, …) rather than a direct pixi.js import, so your code never has to import pixi.js just to name a type. The aliases are transparent — DisplaySprite IS pixi’s Sprite — so every pixi method still works on the value; only the type you write down to describe it changes.

Each section links to the relevant pixi v8 docs.