Skip to content

@carrot/engine-framework-sprites ​

ts

Sprite rendering behaviours for the Carrot engine framework - image loading, texture creation, material setup, and render pipeline integration.

Installation ​

bash
npm install @carrot/engine-framework-sprites

Architecture / How It Works ​

Sprite + SpriteRenderer Pattern ​

Sprites use a two-behaviour pattern:

  1. Sprite - loads an image asset, creates a Texture2D, Material2DSprite, MaterialInstance, and a quad Mesh sized to the image dimensions (or an optional size override). Calls texture.upload() during init. Exposes tint, mainTexture, spriteSize, and a typed materialInstance for convenient runtime control.
  2. SpriteRenderer - a RenderBehaviour that reads mesh/material from a sibling Sprite and exposes them to the render pipeline. Provides submit() to add a DrawCall to the renderer's draw list, and draw(camera) for immediate-mode rendering. Internally uses bindMaterial() and createDrawCall() from the renderer packages.

Both behaviours must be on the same entity. SpriteRenderer finds its Sprite sibling in start().

Inheritance Chain ​

Behaviour
  -> Sprite (image + texture + material + mesh)
     -> SpriteAnimated (frame-based animation - stub)
        -> SpritePacked (texture atlas/packing - stub)

RenderBehaviour
  -> SpriteRenderer (reads from Sprite, exposes to pipeline)

Bundle Registration ​

registerSpriteBehaviours(registry) registers all four types on a BehaviourRegistry, enabling template-based instantiation:

  • 'sprite' - new Sprite(props.image)
  • 'spriteRenderer' - new SpriteRenderer()
  • 'spriteAnimated' - new SpriteAnimated(props.image)
  • 'spritePacked' - new SpritePacked(props.image)

Image Loading ​

Sprite.initialize() resolves the image source (string path or AssetImage instance), loads it, then creates the GPU resources. On failure, falls back to AssetImage.fallback and dispatches onImageFailed.

Dependencies ​

PackageUsed For
@carrot/engine-frameworkBehaviour, RenderBehaviour, BehaviourRegistry
@carrot/engine-materialsMaterial2DSprite, MaterialInstance
@carrot/engine-meshesMesh, meshFromQuad
@carrot/engine-texturesTexture2D
@carrot/engine-renderer-shaders(transitive - shader support)
@carrot/engine-shaders(transitive - shader programs)
@carrot/assetsAssetImage for image loading and fallback
@carrot/signalsSignal for onImageLoaded/onImageFailed

Build ​

bash
npm run build    # runs tsc

Output goes to dist/. Package is ESM ("type": "module").


Usage Guide ​

Sprite rendering behaviours for the Carrot engine framework.

Import ​

ts
import {
  Sprite, SpriteRenderer, SpriteAnimated, SpritePacked,
  registerSpriteBehaviours,
} from '@carrot/engine-framework-sprites';

Common Patterns ​

1. Basic sprite entity ​

ts
import { Entity } from '@carrot/engine-framework';
import { Sprite, SpriteRenderer } from '@carrot/engine-framework-sprites';

const player = Entity.create2d('Player');
player.addBehaviour(new Sprite('player.png'));
player.addBehaviour(new SpriteRenderer());
scene.addEntity(player);

2. Using an AssetImage directly ​

ts
import { AssetImage } from '@carrot/assets';

const image = AssetImage.get('characters/hero.png');
await image.load();

const entity = Entity.create2d('Hero');
entity.addBehaviour(new Sprite(image));
entity.addBehaviour(new SpriteRenderer());

3. Handling load events ​

ts
const sprite = new Sprite('enemy.png');

sprite.onImageLoaded.add((image) => {
  console.log(`Loaded: ${image.width}x${image.height}`);
});

sprite.onImageFailed.add((error) => {
  console.error('Failed to load sprite:', error.message);
});

entity.addBehaviour(sprite);

4. Register sprite behaviours for templates ​

ts
import { registerSpriteBehaviours } from '@carrot/engine-framework-sprites';

registerSpriteBehaviours(game.behaviours);

// Now templates can reference sprite types by name
const prefab: EntityTemplate = {
  name: 'Bullet',
  transform: { type: '2d', x: 0, y: 0 },
  behaviours: [
    { type: 'sprite', properties: { image: 'bullet.png' } },
    { type: 'spriteRenderer', properties: {} },
  ],
};

5. Checking render readiness ​

ts
const renderer = entity.getBehaviour(SpriteRenderer);
if (renderer?.visible) {
  // mesh and material are both available - safe to draw
}

6. Custom sprite size ​

ts
import { Size2 } from '@carrot/maths-geometry';

// Override the mesh size instead of using the image's natural dimensions
const sprite = new Sprite('tile.png', new Size2(64, 64));
entity.addBehaviour(sprite);

7. Tint and texture access ​

ts
const sprite = entity.getBehaviour(Sprite)!;

// Change tint at runtime
sprite.tint = { r: 1, g: 0, b: 0, a: 1 };

// Swap the texture
sprite.mainTexture = anotherTexture;

// Read sprite dimensions
console.log(`Size: ${sprite.spriteSize.width}x${sprite.spriteSize.height}`);

8. Submitting and drawing sprites ​

ts
const renderer = entity.getBehaviour(SpriteRenderer)!;

// Option A: submit a draw call to the renderer's draw list (batched)
renderer.submit();

// Option B: immediate-mode rendering - useful for one-off draws
renderer.draw(camera);

9. Multiple sprites on one entity ​

ts
// Each Sprite creates its own mesh/material, but SpriteRenderer
// finds the first Sprite sibling. For multiple sprites, use
// separate child entities:
const ship = Entity.create2d('Ship');

const hull = Entity.create2d('Hull');
hull.addBehaviour(new Sprite('hull.png'));
hull.addBehaviour(new SpriteRenderer());
ship.addChild(hull);

const turret = Entity.create2d('Turret');
turret.addBehaviour(new Sprite('turret.png'));
turret.addBehaviour(new SpriteRenderer());
ship.addChild(turret);

Carrot