v0.5.0

Each entity can have multiple renderables. A renderable is created by passing a RenderDescriptor object to Entity.createRenderable() or included in the renderable array at spawn time. The type field determines which properties are used.

Render descriptors describe world renderables. To see them in a window, the board containing the entities must be attached to that window with Board.attach(...) or Board.attachOffset(...).

Shared fields #

RenderDescriptor (base)
Fields common to all renderable types.
  • type string — One of "sprite", "tiles", "panel", "box", "circle", "text", "mesh", "particles".
  • layer number — Draw order. Higher layers render on top.
  • texture string optional — Asset path to the texture (e.g. /rom/sprites/atlas.png).
  • textureSemantic TextureSemantic optional — Texture load semantic. Default 'color-srgb-premul'; use 'data-linear-no-premul' for normals/height/data textures. Alias: textureLoad.
  • font string optional — Asset path to a TTF font (text type only).
  • shader { vert: string, frag: string, blend?: BlendMode } optional — Optional SPIR-V shader override. blend may also be provided as blendMode; default is 'premultiplied-alpha'.
  • scale Point optional — Render scale { x, y }. Defaults to { x: 1, y: 1 }.

Shader blend semantics #

shader.blend selects the Vulkan colour blend state for that shader pipeline. It only applies when a custom shader object is supplied. Omit it to use the engine default, 'premultiplied-alpha'.

  • 'premultiplied-alpha' — default Koya/Helix behaviour. Fragment output is expected to be premultiplied: RGB has already been multiplied by A.
  • 'alpha' — straight alpha blending. Use this when your shader outputs ordinary non-premultiplied RGB plus alpha.
  • 'additive' — additive colour accumulation. Useful for glow, fire, particles, and light contribution style passes.
  • 'opaque' — disables colour blending. Alpha does not make the fragment transparent.
{
    type: 'mesh',
    layer: 10,
    shader: {
        vert: '/rom/shaders/vertex_color.vert.spv',
        frag: '/rom/shaders/vertex_color.frag.spv',
        blend: 'additive'
    },
    geometry: {
        vertex: [
            { pos: [-1, -1, 0], color: [0.8, 0.1, 0.0, 0.6], uv: [0, 0] },
            { pos: [ 1, -1, 0], color: [0.8, 0.1, 0.0, 0.6], uv: [1, 0] },
            { pos: [ 1,  1, 0], color: [0.8, 0.1, 0.0, 0.6], uv: [1, 1] },
            { pos: [-1,  1, 0], color: [0.8, 0.1, 0.0, 0.6], uv: [0, 1] }
        ],
        indices: [0, 1, 2, 2, 3, 0]
    }
}

Texture load semantics #

textureSemantic controls how an image asset is uploaded when a render descriptor loads texture. It is a load-time semantic, not a sampler or shader switch. If the same texture path has already been loaded in the window texture pool, the existing texture is reused.

  • 'color-srgb-premul' — default. Uploads as SRGB colour and premultiplies RGBA pixels for the default renderer blend path.
  • 'data-linear-no-premul' — uploads as linear UNORM data and does not premultiply. Use this for normal maps, height maps, masks, lookup tables, and other non-colour data.
{
    type: 'sprite',
    texture: '/rom/textures/normal.png',
    textureSemantic: 'data-linear-no-premul',
    frames: [{
        size: { x: 2, y: 2 },
        origin: { x: 1, y: 1 },
        aabb: { min: { x: 0, y: 0 }, max: { x: 64, y: 64 } }
    }]
}
Note

If you need the same asset path with different texture semantics in one window, load it under distinct virtual paths or keys so the texture pool does not reuse the first upload.

Sprite #

A textured quad with one or more frames for animation. Each frame defines a sub-rectangle of the texture atlas.

SpriteDescriptor
Fields for type: "sprite".
  • frames SpriteFrame[] — Array of frames defining the sprite sheet.
SpriteFrame
A single frame in a sprite sheet.
  • size Point — Display size in world units. Negative width flips horizontally.
  • origin Point — Anchor point relative to the frame (pixels from top-left of the source rect).
  • aabb AABB — Source rectangle in the texture: { min: { x, y }, max: { x, y } } in pixels.
  • colour Colour optional — Tint colour { r, g, b, a } (0-255). Defaults to white.
{
    type: 'sprite',
    texture: '/rom/sprites/hero.png',
    textureSemantic: 'color-srgb-premul',
    layer: 100,
    shader: {
        vert: '/rom/shaders/sprite.vert.spv',
        frag: '/rom/shaders/sprite.frag.spv',
        blend: 'premultiplied-alpha'
    },
    frames: [
        {
            size: { x: 16, y: 16 },
            origin: { x: 8, y: 16 },
            aabb: { min: { x: 0, y: 0 }, max: { x: 16, y: 16 } }
        },
        {
            size: { x: 16, y: 16 },
            origin: { x: 8, y: 16 },
            aabb: { min: { x: 16, y: 0 }, max: { x: 32, y: 16 } }
        }
    ]
}

Tiles #

A grid of tiles rendered from a tileset texture. Tile IDs are 1-based (0 = empty). The tile at ID n maps to position (n-1) in the tileset, laid out left-to-right, top-to-bottom.

TilesDescriptor
Fields for type: "tiles".
  • size Point — Display size of each tile in world units { x, y }.
  • textureSize Point — Size of each cell in the tileset texture (pixels) { x, y }.
  • mapSize Point — Grid dimensions { x: columns, y: rows }.
  • tileData number[] — Row-major array of uint16 tile IDs.
{
    type: 'tiles',
    texture: '/rom/tilesets/overworld.png',
    layer: 0,
    size: { x: 16, y: 16 },
    textureSize: { x: 16, y: 16 },
    mapSize: { x: 32, y: 32 },
    tileData: [1, 2, 3, 0, 0, ...]
}

Panel #

A 9-slice or stretch-mode textured panel. Uses the same frames format as sprites for the source rectangle, plus optional mode and edge properties.

PanelDescriptor
Fields for type: "panel".
  • frames SpriteFrame[] — Source frames (same format as sprite frames).
  • mode string optional — Panel rendering mode string.
  • edge number[] optional — Four-element array [top, right, bottom, left] defining 9-slice insets in pixels.

Box #

A solid-colour rectangle, optionally with rounded corners.

BoxDescriptor
Fields for type: "box".
  • aabb AABB — Rectangle bounds { min: { x, y }, max: { x, y } } in world units.
  • colour Colour — Fill colour { r, g, b, a } (0-255).
  • cornerRadius number optional — Radius for rounded corners.
  • cornerResolution number optional — Number of segments per rounded corner.
  • inset number optional — Inner inset for rendering a rectangular border instead of a filled rectangle.
{
    type: 'box',
    layer: 50,
    aabb: { min: { x: -8, y: -8 }, max: { x: 8, y: 8 } },
    colour: { r: 255, g: 0, b: 0, a: 200 },
    cornerRadius: 2,
    cornerResolution: 4
}

Circle #

A solid-colour circle, ellipse, ring, or arc fitted to an AABB.

CircleDescriptor
Fields for type: "circle".
  • aabb AABB — Ellipse bounds { min: { x, y }, max: { x, y } } in world units.
  • colour Colour optional — Fill colour { r, g, b, a } (0-255). Defaults to white.
  • resolution number optional — Number of sides used to approximate the shape. Defaults to 32; minimum is 3.
  • inset number optional — Inner inset for rendering a ring instead of a filled circle or ellipse.
  • start number optional — Start angle in degrees. Defaults to 0.
  • end number optional — End angle in degrees. Defaults to 360.
{
    type: 'circle',
    layer: 60,
    aabb: { min: { x: -8, y: -8 }, max: { x: 8, y: 8 } },
    colour: { r: 80, g: 190, b: 255, a: 220 },
    resolution: 48,
    inset: 2,
    start: 0,
    end: 270
}

Text #

A rendered text string using a TTF font.

TextDescriptor
Fields for type: "text".
  • string string — The text to render.
  • size number optional — Font size.
  • colour Colour optional — Text colour { r, g, b, a } (0-255).
  • style string optional — Font style string.
  • justify string optional "left" (default), "centre", or "right".
{
    type: 'text',
    font: '/rom/fonts/mono.ttf',
    layer: 200,
    string: 'Score: 0',
    size: 12,
    colour: { r: 255, g: 255, b: 255, a: 255 },
    justify: 'left'
}

Particles #

A modular GPU-simulated world-space emitter. main, emission, shape, motion, and appearance modules live under config; available shapes include point, line, box/edge, and ellipse/ring/arc. Emitters start immediately, particles detach from the entity at spawn, and all world particles draw at the scene/UI boundary. See GPU Particles for curves, gradients, coherent noise, runtime controls, ordering, lifecycle, capacity, and limitations.

ParticleDescriptor
Fields for type: "particles".
  • config ParticleEmitterConfig optional — Complete emitter configuration. See GPU Particles.

Mesh #

A custom mesh rendered from explicit vertices and indices. Useful for debug overlays, procedural shapes, and line-strip style geometry.

MeshDescriptor
Fields for type: "mesh".
  • geometry MeshGeometry — Vertex/index data for the mesh.
  • texture string optional — Optional texture path.
MeshGeometry
Geometry payload accepted by mesh renderables.
  • vertex MeshVertex[] | number[] — Either an array of vertex objects or a flat number array in groups of 9: [x, y, z, r, g, b, a, u, v].
  • indices number[] optional — Triangle index list (uint16). Omit for non-indexed geometry.
MeshVertex
Object form for one mesh vertex.
  • pos number[] optional — Position [x, y, z?]. You can also use x, y, z fields.
  • color number[] optional — Colour [r, g, b, a?] in normalized 0-1 values. Alias: colour.
  • uv number[] optional — Texture UV [u, v].
{
    type: 'mesh',
    layer: 120,
    geometry: {
        vertex: [
            { pos: [0, 0, 0], color: [0.0, 1.0, 0.0, 1.0], uv: [0, 0] },
            { pos: [1, 0, 0], color: [0.0, 1.0, 0.0, 1.0], uv: [1, 0] },
            { pos: [0, 1, 0], color: [0.0, 1.0, 0.0, 1.0], uv: [0, 1] }
        ],
        indices: [0, 1, 2]
    }
}