Game objects
Back to the reference

Game objects

What a scene is filled with: sprites, texts, models, emitters, lines, materials, and destroying them.

45 symbols

createMaterialvariablenacatamalon

createMaterial: TCreateMaterial

Makes a material: a shader of your own, and for models the surface it is drawn over.

It is a plain value, not a resource. Nothing caches it and nothing looks it up by name, so two things share one by being handed the same one. That is also what makes a shared effect cheap: one material is one compiled shader, however many things are drawn with it, and each of those can still run it with its own numbers by passing uniforms of its own.

What it carries depends on what it is for, and the two are deliberately different. A material for models owns the surface, because a hundred crates want to share one. A material for sprites owns only the effect, because a sprite's picture and colour are its own and travel with it: putting the colour on something shared would mean one material per sprite to vary it.

Example

const Level = () => {
    const texture = useLoadTexture({ src: '/assets/hero.png' });

    const crt = createMaterial({
        fragment: `fn effect(color: vec4<f32>, uv: vec2<f32>) -> vec4<f32> {
            let band = 0.5 + 0.5 * sin(uv.y * mu.lines + mu.time * 6.0);
            return vec4<f32>(color.rgb * band, color.a);
        }`,
        uniforms: { lines: 200 },
    });

    createSprite({ texture, material: crt });

    return createScene();
};
View source · gameobjects/material/create_material.ts:111

createMeshfunctionnacatamalon

createMesh(options: TMeshOptions) => TMesh

Puts a model in the scene: a shape, somewhere, with a surface.

The shape comes from one of the shape hooks and is shared, so making a hundred of these from one shape costs a hundred placements and not a hundred shapes.

It is drawn through the scene's 3D camera, or flat on in the game's pixels when it has none. It shares its draw order with everything else, so a model can sit between two sprites, and on a tie the model is drawn first and the sprite paints over it.

What comes back is the model itself, plain data: move it, turn it, tint it, hide it.

Parameters

optionsTMeshOptions

The shape, and anything else about how it looks.

Example

const Level = () => {
    useCamera3d({ projection: 'perspective', z: 4 });
    const crate = createMesh({ geometry: useCubeGeometry(), tint: getColor('#c08040') });

    useUpdate((delta) => {
        crate.transform.rotationY += delta;
    });

    return createScene();
};
View source · gameobjects/mesh/create_mesh.ts:71

createModelfunctionnacatamalon

createModel(options: TModelOptions) => TModel

Puts a loaded model in the scene.

A model file is usually several pieces, each with its own colour or picture: a vehicle is a body, glass and tyres. All of them are drawn, and one placement moves the lot, however deep the file's own structure went. Where each piece sits inside the model is already worked into it.

The pieces appear when the file does. On the frame you call this the model may still be on the way, so parts is empty and nothing is drawn; a frame or two later it fills in and the model is there. Nothing has to be waited for or wired up.

tint multiplies, so the colours the model was made with survive: white leaves it exactly as it was made, and a darker colour shades all of it at once. To change one piece, reach into parts once the file is here.

Parameters

optionsTModelOptions

The model, and anything else about how it looks.

Example

const Level = () => {
    useCamera3d({ projection: 'perspective', z: 6 });
    useLight({ intensity: 1 });

    const tower = useLoadGltf({ src: '/models/tower.glb' });
    const placed = createModel({ model: tower, transform: { y: -1 } });

    useUpdate((delta) => {
        placed.transform.rotationY += delta * 0.5;
    });

    return createScene();
};
View source · gameobjects/model/create_model.ts:116

createNineSlicefunctionnacatamalon

createNineSlice(options: TNineSliceOptions) => TNineSlice

Puts a picture in the scene that can be any size without deforming: a panel, a button, a dialogue box, a health bar.

The picture is cut into nine parts by four borders (slice), measured in its own pixels. The corners are drawn as they are, the top and bottom edges only grow sideways, the left and right edges only grow downwards, and the middle fills the rest. So a 24x24 frame drawn at 300x80 keeps its corners crisp, which stretching it as a sprite would not.

  • mode decides how the edges and the middle fill their space: stretched (the default), repeated and cut at the end ('tile'), or repeated a whole number of times ('tile-fit'). Repeating draws one sprite per copy, so a small pattern over a large panel is many sprites.
  • Drawn smaller than its borders, the corners shrink in proportion instead of overlapping.
  • transform.scaleX/scaleY stretch the whole of it, corners included. To make it bigger and keep the corners, change width and height.

It is placed by its anchor, its middle unless you say otherwise, like a sprite, and takes the same pointer events (onClick, onPointerOver...), which fire anywhere inside it.

Parameters

optionsTNineSliceOptions

Its picture, borders, size, place and look: see TNineSliceOptions.

Example

export const Menu: TSceneFn = () => {
    useLoadTexture({ src: '/assets/ui/panel.png', key: 'panel' });
    const panel = createNineSlice({
        key: 'panel',
        slice: 8,
        width: 200,
        height: 64,
        transform: { x: 160, y: 120 },
        onClick: () => { panel.width += 16; },
    });

    return createScene();
};
View source · gameobjects/nine_slice/create_nine_slice.ts:79

createPackfunctionnacatamalon

createPack(options: TPackOptions) => TBox

Places one thing a pack offers: a box, or a scene as one part of the scene that creates it.

It appears when the pack does, the way createModel fills in when its file arrives: what comes back is the object at once, empty on the frame you call this, and the pack's box is built inside it the moment the pack has landed. Nothing has to be waited for.

Each call is its own copy, with its own place (transform) and its own settings (props), and what comes back is an ordinary object: move it, hide it, destroy it like any other. The pack's box sits inside it at the place it was made at, so a script that moves its own box keeps doing so relative to wherever you put the copy.

A script the pack's box attaches has to be registered, which is what importing the pack's <name>.pack.ts does. One that is not is named in a warning, and the box is built without it.

Parameters

optionsTPackOptions

Which thing of which pack, where, and with which settings.

Example

const Menu: TSceneFn = () => {
    const ui = useLoadPack({ src: '/packs/ui-kit' });
    createPack({ pack: ui, box: 'Button', transform: { x: 160, y: 120 } });
    createPack({ pack: ui, box: 'Button', transform: { x: 160, y: 160 }, props: { label: 'QUIT' } });
    return createScene();
};
View source · gameobjects/pack/create_pack.ts:114

createParticlesfunctionnacatamalon

createParticles(options: TParticlesOptions) => TParticles

Puts an emitter in the scene: a place that makes particles, following an effect from a file.

The file says what the effect is and is shared, so three torches reading one document are three emitters with their own particles, their own clock and their own stream of chance. What this decides is where it is, what colour it is laid in, and whether it starts lit.

It appears at once and draws nothing until its file lands, which is a working state and not a half-built one: the emitter is already in the right place, so nothing that depends on where it is has to wait for a download.

Parameters

optionsTParticlesOptions

The effect to follow, and what this emitter decides for itself.

Example

const Level = () => {
    const fire = useLoadParticles({ src: '/effects/fire.particles' });

    createParticles({ effect: fire, transform: { x: 150, y: 250 } });

    return createScene();
};
View source · gameobjects/particles/create_particles.ts:72

createParticles3dfunctionnacatamalon

createParticles3d(options: TParticles3dOptions) => TParticles3d

Puts an emitter in a scene in three dimensions, following an effect written for them.

The same thing createParticles is, one dimension up: the file says what the effect is and is shared, and this decides where it is, what colour it is laid in and whether it starts lit. Each particle is drawn as a square that always faces the camera, however the camera turns, and hides behind the models in front of it without hiding the other particles.

Its effect has to be a particles3d file. Handing it a flat one is refused, because every number in that file is a pixel.

Parameters

optionsTParticles3dOptions

The effect to follow, and what this emitter decides for itself.

Example

const Campfire = () => {
    const fire = useLoadParticles({ src: '/effects/campfire3d.particles' });

    createParticles3d({ effect: fire, transform: { y: 0.1 } });

    return createScene();
};
View source · gameobjects/particles/create_particles_3d.ts:44

createSpriteTexturefunctionnacatamalon

createSpriteTexture(options: TSpriteTextureOptions, component?: (args: TArgs) => unknown, args: TArgs) => TTexture

Makes a picture and fills it with a component: whatever component draws, and whatever it creates with useSpawn, ends up in the picture instead of on the screen, every frame. A model then shows the picture the way it shows any image, so the 2D moves with the model and is seen in its perspective: a handheld's screen, a monitor, a sign.

The component is a full part of the scene: it updates, it runs its scripts, it pauses with the scene and destroy takes it away. What it draws is measured in the picture's pixels, from its top-left corner, the way a scene without a camera is. A camera it asks for is the picture's own and leaves the scene's alone, and a lamp it holds lights only the picture.

With sees: 'scene' the picture also shows the models of the world around it, from the component's own 3D camera: a security camera, and the monitor is whatever shows the picture.

Whatever you pass after the component reaches it as its arguments, as with useSpawn.

Parameters

optionsTSpriteTextureOptions

How big the picture is, what is behind it and what it sees.

componentoptional(args: TArgs) => unknown

What is drawn into it. Left out, the picture shows only its background, or the scene when it sees it.

argsTArgs

What component is called with, the way a maker from useSpawn passes them on.

Example

const Screen = () => {
    const pet = createSprite({ key: 'pet', transform: { x: 40, y: 40 } });
    useUpdate((delta) => {
        pet.transform.x += delta * 10;
    });
};

const Level = () => {
    useCamera3d({ projection: 'perspective', z: 3 });
    const screen = createSpriteTexture({ width: 128, height: 128 }, Screen);
    createMesh({ geometry: useCubeGeometry(), texture: screen });
    return createScene();
};
View source · gameobjects/sprite_texture/create_sprite_texture.ts:133

createTextfunctionnacatamalon

createText(options: TTextOptions) => TText

Writes something on screen with a bitmap font: a score, a title, a menu, "PRESS START".

You get the text back and change it by changing its fields: score.text = 'SCORE ' + points shows on the next frame. It draws nothing until its font has loaded, and appears on its own then.

The font is optional: left out, the text uses the one the engine carries (Nacatamal Arcade, 8 px, with lowercase, accents and ñ), which is there from the start. Pass font from useLoadFont for a font of your own.

  • style.fontSize is how tall a line is, in pixels. A pixel font looks crisp at whole multiples of its own height and uneven in between; the console says so if that happens.
  • \n starts a new line, and style.align lines them up.
  • x and y are the top-left corner of the text unless anchor says otherwise: { x: 0.5, y: 0 } centres a title on x.
  • A lowercase letter the font does not have is drawn as its capital, since most arcade fonts only have capitals.

It moves with the camera and obeys zIndex and useScreenSpace like a sprite, and takes the same pointer events (onClick, onPointerOver...), which fire anywhere inside the block.

Parameters

optionsTTextOptions

What it says, how it looks, and optionally with which font.

Example

export const Level: TSceneFn = () => {
    // No font given: the engine's own.
    const score = createText({ text: 'SCORE 0', style: { fontSize: 16 }, transform: { x: 8, y: 8 } });
    // A font of your own, loaded from its two files.
    const font = useLoadFont({ json: '/fonts/arcade/arcade.json', atlas: '/fonts/arcade/arcade.png' });
    createText({ text: 'HI SCORE', font, transform: { x: 8, y: 28 } });
    let points = 0;

    useUpdate(() => {
        points += 1;
        score.text = 'SCORE ' + points;
    });

    return createScene();
};
View source · gameobjects/text/create_text.ts:57

destroyfunctionnacatamalon

destroy(target: TBox | TDrawable, options?: TDestroyOptions) => void

Removes something from the game for good: a sprite, or a whole thing made by a spawner, with its sprites, its per-frame code and its cleanups. It stops being drawn in this same frame, whether it goes at once or at the end of it, and a spawned object stops running the moment you say so.

Destroying twice, or destroying something that was never on screen, does nothing and says nothing: you should not have to find out whether someone else got there first. What is destroyed is gone, not recycled, so keep making new ones rather than reviving old ones.

Images are not freed. Several things can be showing the same one, and the game keeps it for whoever asks next, so destroying a sprite never costs the next one a reload.

Parameters

targetTBox | TDrawable

The sprite or spawned object to remove. A scene is not one of these: it leaves through useScene().stop(), and passing one here warns and does nothing.

optionsoptionalTDestroyOptions

See TDestroyOptions. Leave it out for the usual behaviour.

Example

export const Level: TSceneFn = () => {
    const bullet = createSprite({ key: 'bullet', transform: { x: 160, y: 200 } });

    useUpdate((delta) => {
        bullet.transform.y -= 300 * delta;
        if (bullet.transform.y < 0) {
            destroy(bullet);
        }
    });

    return createScene();
};
View source · destroy/destroy.ts:71

emitParticlesfunctionnacatamalon

emitParticles(emitter: TParticles | TParticles3d, count: number) => void

Asks for count particles to appear, over and above whatever the effect does by itself.

What a game calls when something happens: a hit, a footstep, a jump. It works on an emitter that is switched off, which is the usual way a one-shot is used.

They appear on the next step rather than inside this call, and that is deliberate: a particle is born where its emitter ends up, and that is not known until the tree has been walked later in the same frame. So this works even for the ordinary pattern of moving the emitter and firing it in the same breath, which is exactly where doing it on the spot would use the place it was before.

Parameters

emitterTParticles | TParticles3d

The emitter, as createParticles or createParticles3d gave it back.

countnumber

How many to make now.

Example

const pointer = usePointer();
declare const sparks: TParticles;

pointer.onDown((info) => {
    sparks.transform.x = info.worldX;
    sparks.transform.y = info.worldY;
    emitParticles(sparks, 40);
});
View source · gameobjects/particles/verbs.ts:123

findObjectfunctionnacatamalon

findObject(root: TBox, name: string) => TBox | null

The first thing called name inside root, looking at root itself first and then down through everything in it, or null when there is none.

What a behaviour uses to reach a named part of what it is attached to: the turret of a tank, the hand a sword goes in, the door that has to slide. null is an ordinary answer and has to be handled, because a part can be renamed while the game runs, or come in with another name when a model is exported again. Nothing here throws.

By name and not by id, because a name is what an author can type.

Parameters

rootTBox

Where to look.

namestring

The name to find.

Example

registerScript('turret', (self) => {
    const place = findObject(self, 'Barrel')?.transform;
    if (place === undefined || place === null) return;
    useUpdate((delta) => { place.rotationY += delta; });
});
View source · box/find_object.ts:31

findObjectsfunctionnacatamalon

findObjects(root: TBox, name: string) => TBox[]

Everything called name inside root, root included, in the order findObject would meet them. For names shared on purpose: the four wheels of a car, every spawn point of a level.

An empty list rather than null when nothing matches, so a for ... of over it needs no guard.

Parameters

rootTBox

Where to look.

namestring

The name to find.

View source · box/find_object.ts:58

pauseParticlesfunctionnacatamalon

pauseParticles(emitter: TParticles | TParticles3d, paused: boolean) => void

Freezes it, or lets it go again.

Nothing moves and nothing is born, and it keeps drawing exactly what it last drew. Freezing rather than hiding, because the useful half of this is being able to look at it: a still flame is something you can line something else up against, and a hidden one is a hole where you have to remember an effect was.

Parameters

emitterTParticles | TParticles3d

The emitter, as createParticles or createParticles3d gave it back.

pausedboolean

true to freeze it, false to let it go again.

View source · gameobjects/particles/verbs.ts:58

playParticlesfunctionnacatamalon

playParticles(emitter: TParticles | TParticles3d) => void

Starts the effect from the beginning: new particles appear, and a burst fires again.

The cycle is put back to exactly zero, and that is what re-arms a burst: a one-shot that has already gone off is a one-shot that can be fired again.

Parameters

emitterTParticles | TParticles3d

The emitter, as createParticles or createParticles3d gave it back.

View source · gameobjects/particles/verbs.ts:17

stopParticlesfunctionnacatamalon

stopParticles(emitter: TParticles | TParticles3d) => void

Stops new ones appearing.

Not the same as clearing. Whatever is already in the air goes on living, moving and drawing until its own time runs out, which is what putting a torch out looks like. Use clearParticles for the other thing.

Parameters

emitterTParticles | TParticles3d

The emitter, as createParticles or createParticles3d gave it back.

View source · gameobjects/particles/verbs.ts:39

transformForwardfunctionnacatamalon

transformForward(transform: TTransform3d) => { x, y, z }

Which way something is facing.

Forward is -Z, which is the convention every model format and every camera in this engine already uses: a camera at the origin looks that way, and a model exported facing the viewer faces that way. A light shines along it, so a light is aimed by turning it, exactly like a camera.

A quaternion, when the transform has one, decides the answer, as it decides the turn everywhere else. The lights and cameras of a frame pass theirs as null on purpose and are aimed by their angles. What comes back is always one unit long, and the roll never changes it.

Parameters

transformTTransform3d

Where something is and how it is turned.

View source · render/shared/transform_basis.ts:21

useSelffunctionhooknacatamalon

useSelf() => TBox

The thing being built right now, so it can refer to itself later: almost always to end its own life once it has done its job.

Inside a component made by a spawner, this is that one thing. Inside a scene body it is the scene, which cannot be destroyed this way: a scene leaves through useScene().stop().

Call it while the thing is being built, like every hook, and keep what it returns.

Example

const Spark = () => {
    const self = useSelf();
    let left = 0.4;

    useUpdate((delta) => {
        left -= delta;
        if (left <= 0) {
            destroy(self);
        }
    });
};
View source · hooks/spawn/use_self.ts:34

useSpawnfunctionhooknacatamalon

useSpawn(component: (args: TArgs) => unknown, options: TSpawnOptions) => (args: TArgs) => TBox

Prepares a maker for component, so the scene can create as many of them as it likes, whenever it likes: while it is being built, from a frame, from a timer, from a click.

This is what gives each one a life of its own. Calling Bullet(10) yourself is an ordinary function call, and the useUpdate inside it belongs to whoever called it, mixed in with everything else there. Made through the maker, each bullet gets its own place: its sprites, its per-frame code and its cleanups are its, and destroy can take exactly one of them away.

Whatever you pass to the maker reaches the component as its arguments. What comes back is the thing itself, for later: keep it to destroy it, or let the component end its own life with useSelf.

Call it while the scene is being built, like every hook. It remembers the scene it was called in, so the maker keeps working long after that.

Parameters

component(args: TArgs) => unknown

The function describing one of these things. Whatever it returns is ignored.

optionsTSpawnOptions

Where they are placed: see TSpawnOptions.

Example

declare const gun: TSprite;
declare let firing: boolean;

const Bullet = (x: number) => {
    const self = useSelf();
    const sprite = createSprite({ key: 'bullet', transform: { x, y: 200 } });

    useUpdate((delta) => {
        sprite.transform.y -= 300 * delta;
        if (sprite.transform.y < 0) {
            destroy(self);
        }
    });
};

export const Level: TSceneFn = () => {
    const spawnBullet = useSpawn(Bullet);

    useUpdate(() => {
        if (firing) spawnBullet(gun.transform.x);
    });

    return createScene();
};
View source · hooks/spawn/use_spawn.ts:85

useTransformfunctionhooknacatamalon

useTransform(options: TTransformOptions) => TTransform3d

Gives this object a place of its own, and moves everything inside it.

Without it, each sprite, text or model carries its own position and they are moved one by one. With it, they are placed once, relative to the object, and moving the object moves all of them together: a turret and its barrel, a card and its number, a ship and everything bolted to it. Anything made inside this one is placed relative to it too, however deep it goes.

What comes back is the placement itself, so changing it is all it takes and it takes effect on the next frame drawn. rotation turns it in the plane, which is the only one a 2D game needs; rotationX and rotationY are for three dimensions.

For something free to point anywhere there is quaternion, and setting one puts the three angles aside: Quat.fromEuler starts one off facing the same way they did, and Quat.slerp eases from one facing to another without the wobble that easing three angles gives. Note that it speaks for three dimensions only: pictures and writing inside this one are still turned by rotation.

Asking twice gives back the same placement, so a later call never quietly throws away where something already was.

Parameters

optionsTTransformOptions

Where to start. Anything left out starts at the origin, unturned and unscaled.

Example

const Turret = (x: number) => {
    const place = useTransform({ x, y: 200 });

    // Both are placed relative to the turret, so turning it turns them together.
    createSprite({ key: 'base', transform: { x: 0, y: 0 } });
    createSprite({ key: 'barrel', transform: { x: 0, y: -12 } });

    useUpdate((delta) => {
        place.rotation += delta;
    });
};
View source · hooks/transform/use_transform.ts:60

TDestroyOptionstypenacatamalon

How destroy should go about it.

Properties

immediateoptionalboolean

Ask for it to be gone the instant you say so, instead of at the end of the frame. It is a request and not an order: asked for while the game is running its updates, it is queued anyway, so the call is never the wrong one to write.

View source · destroy/destroy.ts:17

TDrawabletypenacatamalon

TDrawable: TSprite | TText | TNineSlice | TTilemapLayer | TMesh | TParticles | TParticles3d | TLines

Anything drawn in a scene: a sprite, a text, a nine-slice, a map layer, a model, particles or lines. It grows by adding members (TSprite | TText | TTilemap), and every member carries a type, so a switch on it knows which one it holds.

A union and not a shared base type: a base would need a cast to reach any field of its own, and could never tell a backend that it forgot a kind.

View source · gameobjects/types/t_drawable.ts:21

TLinestypenacatamalon

A set of lines in space: plain, unlit, one colour per corner. What the debug helpers draw (an axis gizmo, a floor grid, an outline), and anything else that is best said with a line.

The corners are not here. A record is plain data and a run of numbers the card reads is not, so they live beside it: useHelperLines hands back the function that writes them. What is here is what an ordinary drawable has, where it is and whether it is drawn, and changing those is all it takes for the next frame to show it.

Lines are hidden by the models in front of them, and hide what is behind them, the same as a model: a line that ignored the scene would read as a wireframe floating over it. They are one pixel wide on both backends, which is all the cards promise.

Properties

idstring
type'lines'
nameoptionalstring

A name to find it by, like any other drawable.

transformTTransform3d

Where the lines are drawn from: their corners are measured from here, turned and scaled by it.

worldMatrixoptionalFloat32Array

Where it ends up once everything above it has moved it. Set each frame; never authored.

zIndexoptionalnumber

Draw order within its scene. On a tie, lines and models are drawn in the order they were made.

visibleoptionalboolean

Whether they are drawn at all. Omitted is drawn.

destroyedboolean

Set by destroy and never cleared.

View source · gameobjects/lines/types/t_lines.ts:20

TMeshtypenacatamalon

A model: a shape, put somewhere, with a surface.

The shape is shared and the placement is its own, which is the whole split: a hundred crates are one shape and a hundred of these. Plain data, like every other drawable, so changing a field is all it takes and the next frame shows it.

The surface is a material, and a shared one: a hundred crates are one shape, one surface and a hundred of these. A sprite is the other way round and keeps its own picture and colour, because in two dimensions those vary per sprite and travel with it in the instance buffer.

So the question this used to leave open, of what a material is and what sharing one would mean, turned out to have two answers rather than one, which is exactly why it was worth leaving open.

Properties

idstring
type'mesh'
geometryTGeometry | null

What shape it is. null draws nothing, which is what a model waiting on a file does.

transformTTransform3d

Where it is, how it is turned and how big.

worldMatrixoptionalFloat32Array

Where it ends up once everything above it has moved it. Set each frame; never authored.

skeletonTSkeleton | null

The bones that move it, or null for something that does not bend.

It comes from a model that was rigged, and it is what decides how this is drawn: with bones, every corner is carried by up to four of them; without, it sits where its placement puts it.

materialTMeshMaterial

What it looks like: its picture, its colours, its shine, and any shader of its own.

Never null. A model built without being handed one gets a private material of its own, made from the very same fields it used to carry, so createMesh({ tint }) still reads the way it always did. Handing two models the same material is how they come to share a surface, and with a shader on it, a single compiled pipeline.

zIndexoptionalnumber

Draw order within its scene, the same one sprites use. On a tie, models are drawn first.

visibleoptionalboolean

Whether it is drawn at all. Omitted is drawn.

castShadowoptionalboolean

Whether it is drawn into the shadow map. Omitted casts, which is what nearly everything should do; false is for a floor, a decal or a blob shadow's own disc.

destroyedboolean

Set by destroy and never cleared.

View source · gameobjects/mesh/types/t_mesh.ts:24

TMeshOptionstypenacatamalon

What createMesh is asked for. Only the shape is needed.

Properties

geometryTGeometry

The shape it is, from one of the shape hooks.

materialoptionalTMeshMaterial

A surface to draw it with, from createMaterial, shared with anything else handed the same one.

Given one, the loose surface fields below are not read: the material already says all of that, and two places saying it would be two places to disagree.

transformoptionalPartial<TTransform3d>

Where it is. Anything left out is at the origin, unturned and unscaled.

textureoptionalTTexture

A picture for its surface, from useLoadTexture.

keyoptionalstring

The key a texture was loaded under, for a model built where the picture is not at hand.

tintoptionalTColor

Multiplies the picture, and is the whole colour without one. Default white.

emissiveoptionalTColor

Light it gives off by itself. Default none.

specularoptionalTColor

The colour of its shine. Default none, which is a matt surface: a shine is the thing that makes something read as wet, polished or metal, and everything else looks better without it.

shininessoptionalnumber

How tight that shine is. Default 32. Higher is smaller and harder.

vertexSnapoptionalboolean | number

Its corners land on a coarse grid of the screen, the way the PlayStation drew them: a model shivers as it moves and its edges crawl as the camera turns. A number is how many rows the grid has (120 is the classic look, smaller is wilder); true uses the game's own rows, which is subtle. Default false.

affineoptionalboolean

Its picture is stretched straight across the screen without correcting for depth, the way the PlayStation drew it: big flat surfaces bend and swim as the camera comes close. Default false.

alphaoptionalnumber

How solid it is, 0 to 1. Default 1.

transparentoptionalboolean

Drawn as see-through even at full alpha: for a shader that works out its own alpha, or a picture with see-through parts. Omitted, it is see-through when alpha or its tint's own is below 1. A see-through model is drawn after the solid ones, furthest first, and hides nothing.

smoothoptionalboolean

Overrides the game's smooth for this model alone.

wrapoptionalTTextureWrap | { u, v }

What its picture does past its edge. Default 'repeat', as for any model.

zIndexoptionalnumber

Draw order within its scene. Default 0, and on a tie a model goes under a sprite.

visibleoptionalboolean

Whether it is drawn. Default true.

castShadowoptionalboolean

Whether it is drawn into the shadow map. Default true.

false is for the things a shadow of would be wrong rather than expensive: the ground the shadows land on, a decal, a pane of glass, the soft disc of a blob shadow. None of it costs anything unless some light in the scene asked to cast in the first place.

There is no matching receiveShadow. Everything drawn in three dimensions receives, including a model wearing a shader you wrote yourself, because a surface that silently stopped taking shadows the moment you gave it an effect is a surprise with nothing to explain it.

View source · gameobjects/mesh/types/t_mesh_options.ts:15

TModeltypenacatamalon

A loaded model placed in the scene: one placement, and the pieces it is made of.

Move the placement and all of it moves, however many pieces the file turned out to hold. The pieces are ordinary models of their own, so anything you can do to one you can do to a wheel: tint it, hide it, give it its own draw order.

parts fills in when the file arrives, so it is empty on the frame you make this and has what the file held on a later one. Look a piece up by the name it had in the file when you need one in particular.

Properties

idstring
type'model'
transformTTransform3d

Where the whole thing is. Shared by every piece, which is what moves them together.

partsTMesh[]

The pieces, in the order the file lists them. Empty until it arrives.

View source · gameobjects/model/types/t_model.ts:19

TModelOptionstypenacatamalon

What createModel is asked for. Only the model is needed.

Properties

modelTGltfModel

The loaded model, from useLoadGltf.

transformoptionalPartial<TTransform3d>

Where it is. Anything left out is at the origin, unturned and unscaled.

tintoptionalTColor

Multiplies the colour of every piece, so the file's own colours are kept and shaded: white, the default, leaves it exactly as it was made.

alphaoptionalnumber

How solid it is, 0 to 1. Default 1.

transparentoptionalboolean

Drawn as see-through even at full alpha. Omitted, each piece is see-through when the file says so (alphaMode: 'BLEND') or when its alpha is below 1.

specularoptionalTColor

The colour of its shine. Default none, which is a matt surface.

shininessoptionalnumber

How tight that shine is. Default 32. Higher is smaller and harder.

vertexSnapoptionalboolean | number

Its corners land on a coarse grid of the screen, the way the PlayStation drew them: a model shivers as it moves and its edges crawl as the camera turns. A number is how many rows the grid has (120 is the classic look, smaller is wilder); true uses the game's own rows, which is subtle. Default false.

affineoptionalboolean

Its picture is stretched straight across the screen without correcting for depth, the way the PlayStation drew it: big flat surfaces bend and swim as the camera comes close. Default false.

smoothoptionalboolean

Overrides the game's smooth for this model alone.

wrapoptionalTTextureWrap | { u, v }

What every picture on it does past its edge, over what the file says. Omitted, each piece does what its file asked, which is almost always to repeat.

zIndexoptionalnumber

Draw order within its scene. Default 0, and on a tie a model goes under a sprite.

visibleoptionalboolean

Whether it is drawn. Default true.

View source · gameobjects/model/types/t_model_options.ts:13

TNineSlicetypenacatamalon

A picture cut into nine parts so it can be any size without deforming its corners, as createNineSlice gives it back: the panels, buttons, dialogue boxes and health bars of a UI. Plain data: change any field (width above all) and the next frame shows it.

Properties

idstring
type'nine-slice'
widthnumber

Width in pixels, before scale. Change it and the corners stay as they are.

heightnumber

Height in pixels, before scale.

transformTTransform2d

Where it is, how it is turned and how big. Scale stretches the whole of it, corners included.

worldTransformoptionalTTransform2d

Where it ends up once everything above it has moved it, worked out once a frame while the tree is walked. Left off when nothing above it has a placement of its own, which is the ordinary case: then its own transform is already where it is.

Set by the engine every frame and never authored or saved. Ask worldOf rather than reading either field by hand.

textureTTexture

The picture it is cut from.

tintTColor
sliceTNineSliceBorders

How wide each border is, in pixels of the picture.

modeTNineSliceMode | { x, y }

How the edges and the middle fill their space, the same both ways or one per direction: { x: 'tile', y: 'stretch' } repeats along the width and stretches along the height.

atlasoptionalTSpriteAtlas

The sheet its picture came from, if it came from one.

frameoptionalnumber

Which frame of atlas it is cut from. Change it and the next frame is cut from that one.

uvOffsetoptional{ x, y }

Where the window into the texture starts, in 0-1. Wins over atlas and frame.

uvScaleoptional{ x, y }

How big that window is, in 0-1. Wins over atlas and frame.

anchoroptional{ x, y }

Which point of it sits on its transform, in 0-1. Omitted is its middle, as for a sprite.

zIndexoptionalnumber

Draw order within its scene, as for a sprite. All nine parts move as one.

smoothoptionalboolean

Crisp or blended when it does not land on whole pixels. Omitted, the game's smooth decides.

visibleoptionalboolean

Whether it is drawn at all. Omitted is drawn.

materialoptionalTSpriteMaterial

An effect of its own, from createMaterial, carried by every part. Omitted is the built-in shader.

uniformsoptionalTUniformValues

Its own values for that material's knobs, laid over the material's own.

destroyedboolean

Set by destroy and never cleared.

View source · gameobjects/nine_slice/types/t_nine_slice.ts:43

TNineSliceBorderstypenacatamalon

How wide each border of a nine-slice is, in pixels of its picture (of its frame, with a sheet). Those borders are what is never stretched: the corners stay as drawn, and the edges only grow along their length.

Properties

leftnumber
topnumber
rightnumber
bottomnumber
View source · gameobjects/nine_slice/types/t_nine_slice.ts:32

TNineSliceModetypenacatamalon

TNineSliceMode: 'stretch' | 'tile' | 'tile-fit'

How the parts of a nine-slice between its corners fill the space they are given.

  • 'stretch': the part is drawn once, stretched to fit. The default, and what a plain panel wants.
  • 'tile': the part is repeated at its own size from the corner onwards, and the last copy is cut where the space ends. For a frame with a pattern along it (rivets, a rope, bricks) that must not be deformed.
  • 'tile-fit': repeated as many whole times as fit best, each copy stretched a little so none is cut. The pattern stays whole at the cost of being slightly wider or narrower than drawn.
View source · gameobjects/nine_slice/types/t_nine_slice.ts:21

TNineSliceOptionstypenacatamalon

What createNineSlice is asked for: a picture, how wide its borders are, and the size to draw it at.

Properties

textureoptionalTTexture

A texture from useLoadTexture. Wins over key and atlas.

keyoptionalstring

The key a texture was loaded under.

atlasoptionalTSpriteAtlas

A sheet from createSpriteAtlas, with frame saying which part of it is the picture.

frameoptionalnumber

Which frame of atlas, numbered from 0. Default 0.

uvOffsetoptional{ x, y }

Where the picture starts inside the texture, in 0-1, for a picture that is not a whole frame.

uvScaleoptional{ x, y }

How big the picture is inside the texture, in 0-1.

slicenumber | TNineSliceBorders

How wide each border is, in pixels of the picture: one number for all four, or each one. The borders are the part that is never stretched, so they are usually the size of the corners as drawn.

modeoptionalTNineSliceMode | { x, y }

How the edges and the middle fill their space: 'stretch' (the default), 'tile' or 'tile-fit', the same both ways or { x, y } one per direction.

widthnumber

How wide to draw it, in pixels. Required: drawn at the size of its picture it would cut nothing, and a sprite already does that.

heightnumber

How tall to draw it, in pixels.

transformoptionalPartial<TTransform2d>

Where it is, how it is turned and how big. Only what is given: the rest is no turn and a scale of 1, so { x, y } is enough.

tintoptionalTColor

Its colour, multiplied over the picture. Default white, the picture as drawn.

anchoroptional{ x, y }

Which point of it sits on x, y, in 0-1. Default its middle: { x: 0, y: 0 } is its top-left corner.

zIndexoptionalnumber

Draw order within its scene, as for a sprite.

smoothoptionalboolean

Crisp (false) or blended (true) when scaled. Default: the game's smooth.

visibleoptionalboolean

Whether it is drawn. Default true.

materialoptionalTSpriteMaterial

An effect of its own, from createMaterial. Omitted is the built-in shader.

uniformsoptionalTUniformValues

Its own values for that material's knobs.

onPointerOveroptionalTPointerListener

Called when the mouse or a finger comes over it. The whole rectangle counts.

onPointerOutoptionalTPointerListener

Called when the pointer stops being over it, or leaves the game.

onPointerMoveoptionalTPointerListener

Called when the pointer moves while over it.

onPointerDownoptionalTPointerListener

Called when a button is pressed, or a finger touches, over it.

onPointerUpoptionalTPointerListener

Called when a button is released, or a finger lifts, over it.

onClickoptionalTPointerListener

Called when it is pressed and released without leaving it. The cursor turns into a hand over it.

View source · gameobjects/nine_slice/types/t_nine_slice_options.ts:16

TPackOptionstypenacatamalon

What createPack is asked for: which thing of which pack, where, and with which settings.

Properties

packTLoadedPack

The pack, from useLoadPack.

boxoptionalstring

Which of the boxes it offers. Left out, and with scene left out too, the pack's only offer is taken, which is what a pack of one thing wants.

sceneoptionalstring

Which of the scenes it offers, placed as one part of the scene that creates it.

transformoptionalTTransformOptions

Where this copy goes, measured from what creates it. The pack has no place of its own.

propsoptionalTScriptProps

This copy's own settings for the scripts on the thing itself (not its children), laid over the ones the pack was made with. What a door's destination or a patrol's speed is for.

onoptionalRecord<string, TObjectEventHandler>

What to do when the copy tells its parent something: the events its behaviours send with useEvent (a button's 'pressed'), by name. The same as onEvent on the copy, connected before the pack has even landed.

View source · gameobjects/pack/types/t_pack_options.ts:13

TParticlestypenacatamalon

An emitter: a place in the world that makes particles, following an effect written in a file.

Plain data from end to end, like every other record here. Its living particles, its own stream of chance and the numbers bound for the card are not any of those things, so they are kept beside it rather than in it, and found by it. That is what lets an emitter be written to a scene file at all: what would be written is what is here, and all of it is JSON.

Properties

type'particles'
idstring
namestring

What a warning about it will call it. Defaults to the file it came from.

fileTParticlesFile

The effect it follows. Filled in when the file lands; until then it draws nothing.

transformTTransform2d

Where the emitter is. Particles are born here, turned by whatever is above it.

worldTransformoptionalTTransform2d

Where it ended up once everything above it has moved it, when something did.

Set by the engine every frame and never authored or saved. Ask worldOf rather than reading either field by hand. It matters more here than for a sprite: this is the point particles are born at, so reading the wrong one puts a whole cloud in the wrong place.

tintTColor

Multiplied into every particle, over the colour the effect's own curve gives it.

alphanumber

Multiplied into every particle's opacity, the same way.

smoothoptionalboolean

Crisp or blended. Default: the game's own setting.

overridesoptionalTParticleOverrides

What this one disagrees with its file about, or nothing.

emittingboolean

Whether new ones are appearing.

Turning this off is not the same as clearing: the ones already alive go on living and drawing, which is what putting out a torch looks like. Runtime state, and deliberately not what gets written to a file.

pausedboolean

Frozen. Nothing moves and nothing is born, and it keeps drawing exactly what it last drew.

Freezing rather than hiding, because the useful half of this is for a host showing the game while somebody works: a still flame is something you can line a box up against, and a hidden one is a hole where you have to remember an effect was.

autoplayboolean

Whether it starts emitting the moment its file lands.

The authored intention, and the only one of these three that belongs in a file. A torch a script put out is still a torch that starts lit, and saving the running state would write "out" into the level.

seednumber | null

The seed for this emitter's own chance, or null for one taken from the clock.

Set it and the effect replays exactly, which is what a screenshot test and an editor preview want. Leave it and every run looks a little different, which is what a game wants.

zIndexoptionalnumber
visibleboolean
destroyedboolean

Set by destroy and never cleared. True means it is on its way out and nothing should treat it as part of the game any more, even in the gap before the frame sweeps it away.

View source · gameobjects/particles/types/t_particles.ts:49

TParticlesOptionstypenacatamalon

What createParticles is asked for.

Almost everything about the effect itself lives in its file, and that is the point: three torches are one document. What is here is the handful of things this emitter decides for itself.

Properties

effectTParticlesFile | string

The effect, from useLoadParticles, or the name one was loaded under.

nameoptionalstring

What a warning about it will call it. Defaults to the file.

transformoptionalPartial<TTransform2d>

Where it is. Particles are born here, turned and scaled by whatever is above it.

tintoptionalTColor

Multiplied into every particle, over the colour the effect's own curve gives it.

alphaoptionalnumber

Multiplied into every particle's opacity, the same way. Default 1.

smoothoptionalboolean

Crisp or blended. Default: the game's own setting.

overridesoptionalTParticleOverrides

What this emitter disagrees with its file about: a smaller explosion, a slower fountain.

autoplayoptionalboolean

Start as soon as the file lands. true by default, because a torch put in a scene should be burning. false for something an event fires.

seedoptionalnumber

Its own seed, so it replays exactly. Omitted, every run looks a little different.

zIndexoptionalnumber

Draw order, as everywhere else.

visibleoptionalboolean

Whether it is drawn at all. Default true.

View source · gameobjects/particles/types/t_particles_options.ts:16

TSpawnOptionstypenacatamalon

Where the things a maker makes are placed.

Left out, each one hangs under whoever is making it: a tank that makes its own turret carries it along. 'scene' puts it at the top of the scene instead, which is what a shot fired from a cannon wants, since it must not swing round with the barrel once it has left. Or any thing already in the scene, to hang under that one.

Properties

parentoptional'scene' | TGameObject
View source · hooks/spawn/use_spawn.ts:27

TSpritetypenacatamalon

A picture in the scene, as createSprite gives it back. Plain data: change any field (transform.x, tint, visible...) and the next frame shows it.

Properties

idstring
type'sprite'
widthoptionalnumber

Width in pixels, before scale. Omitted: the texture's width once it has loaded.

heightoptionalnumber

Height in pixels, before scale. Omitted: the texture's height once it has loaded.

transformTTransform2d
worldTransformoptionalTTransform2d

Where it ends up once everything above it has moved it, worked out once a frame while the tree is walked. Left off when nothing above it has a placement of its own, which is the ordinary case: then its own transform is already where it is.

Set by the engine every frame and never authored or saved. Ask worldOf rather than reading either field by hand.

textureTTexture | null

The image it shows, or null for a plain rectangle of its tint.

tintTColor
atlasoptionalTSpriteAtlas

The sheet its picture came from, if it came from one. Kept so anything that changes which frame it shows, an animation above all, does not have to be handed the sheet again.

frameoptionalnumber

Which frame of atlas it shows, kept in step by whatever changes it, an animation above all, so a scene saved halfway through a run keeps the picture that was on screen.

animationoptionalTSpriteAnimationDoc

The run a scene document asked it to play, and how fast: what it plays, not how far it has got. Written back when the scene is saved, which is all it is for. The player itself is behaviour and lives in the scene, never in the record.

anchoroptional{ x, y }

Which point of the sprite sits on its transform, in 0-1. Omitted is its middle.

uvOffsetoptional{ x, y }

Where the window into the texture starts, in 0-1. Omitted is the top-left corner.

uvScaleoptional{ x, y }

How big that window is, in 0-1. Omitted is the whole image.

flipXoptionalboolean

Shows its picture mirrored left to right: a character facing the other way, with one drawing instead of two. Omitted is not mirrored.

It mirrors the picture, never the place: a mirrored sprite sits exactly where it sat, and is touched in the same place. That is what tells it apart from a negative scale.

flipYoptionalboolean

The same top to bottom.

visibleoptionalboolean

Whether it is drawn at all. Omitted is drawn.

For something that exists and is not on screen: the coins of a level made once and shown as they are needed, the second picture of a character who is facing the other way. Cheaper than making it and destroying it over and over, and it keeps whatever it was carrying.

Hidden is not gone: it is still in the scene, its box still runs every frame, and it is not touched by the pointer while it cannot be seen.

smoothoptionalboolean

How its image is read when it does not land on whole pixels: false keeps it crisp and blocky, true blends. Omitted, the game's smooth decides.

materialoptionalTSpriteMaterial

An effect of its own, from createMaterial. Omitted is the built-in shader, which is what nearly every sprite wants.

It carries the effect and nothing else: the picture and the colour above stay the sprite's, because those vary per sprite and travel with it. Two sprites handed the same material share one compiled shader, and still draw in one call as long as they also share a sheet.

uniformsoptionalTUniformValues

This sprite's own values for its material's knobs, laid over the material's every frame.

What it buys: fifteen sprites, one compiled effect, fifteen different settings of it. Without it, varying one number would mean a material apiece, and a material apiece is a compile of the identical shader apiece.

The cost is a draw of its own: its numbers are written per run, so a sprite with its own set cannot share one. Fifteen is nothing; a thousand would be worth knowing about.

zIndexoptionalnumber

Draw order within its scene: higher on top, ties in creation order. Omitted counts as 0, and a scene where no sprite says it is not sorted at all.

destroyedboolean

Set by destroy and never cleared. True means it is on its way out and nothing should treat it as part of the game any more, even in the gap before the frame sweeps it away.

View source · gameobjects/sprite/types/t_sprite.ts:9

TTexttypenacatamalon

A text in the scene, as createText gives it back: a string drawn with a bitmap font. Plain data; change any field (text above all) and the next frame shows it.

Properties

idstring
type'text'
textstring

What it says. \n starts a new line.

fontTFont
styleTTextStyle

Size, alignment and spacing. Held by reference, so a shared style changes every text using it.

tintTColor
transform{ x, y, rotation, scaleX, scaleY }

Where the block is. Scale and rotation apply to the whole block, around its anchor.

worldTransformoptional{ x, y, rotation, scaleX, scaleY }

Where it ends up once everything above it has moved it, worked out once a frame while the tree is walked. Left off when nothing above it has a placement of its own, which is the ordinary case: then its own transform is already where it is.

Set by the engine every frame and never authored or saved. Ask worldOf rather than reading either field by hand.

anchoroptional{ x, y }

Which point of the block sits on its transform, in 0-1. Omitted is its top-left corner.

zIndexoptionalnumber

Draw order within its scene, as for a sprite. The whole text moves as one.

smoothoptionalboolean

Crisp or blended when scaled. Omitted, the game's smooth decides.

visibleoptionalboolean

Whether it is drawn at all. Omitted is drawn. Hidden, it keeps what it says and costs nothing to show again, which is what a label that comes and goes wants.

materialoptionalTSpriteMaterial

An effect of its own, from createMaterial. Omitted is the built-in shader.

It is carried by every letter, and every letter carries the same one, so a title with an effect on it is still one draw rather than one draw per character.

uniformsoptionalTUniformValues

This text's own values for that material's knobs, laid over the material's own.

destroyedboolean

Set by destroy and never cleared.

View source · gameobjects/text/types/t_text.ts:13

TTextOptionstypenacatamalon

What createText is asked for.

Properties

materialoptionalTSpriteMaterial

An effect of its own, from createMaterial. Omitted is the built-in shader.

uniformsoptionalTUniformValues

This text's own values for that material's knobs.

textstring

What it says. \n starts a new line.

fontoptionalTFont

A font from useLoadFont. Left out, the engine's own: Nacatamal Arcade, an 8 px arcade font with lowercase, accents and the Spanish ñ, ¿ and ¡, carried inside the engine so nothing has to be loaded.

styleoptionalTTextStyle

Size, alignment and spacing. Kept as given, not copied: pass the same object to several texts and changing it changes all of them. For one text of its own, spread it: { ...heading, fontSize: 24 }.

tintoptionalTColor

Its colour. Default white, the font as drawn.

transformoptionalPartial<{ x, y, rotation, scaleX, scaleY }>

Where it is. x and y are its top-left corner unless anchor says otherwise. Only what is given: the rest is no turn and a scale of 1, so { x, y } is enough.

anchoroptional{ x, y }

Which point of the block sits on x, y, in 0-1: { x: 0.5, y: 0 } centres a title. Default top-left.

zIndexoptionalnumber

Draw order within its scene, as for a sprite.

smoothoptionalboolean

Crisp (false) or blended (true) when scaled. Default: the game's smooth.

visibleoptionalboolean

Whether it is drawn. Default true.

onPointerOveroptionalTPointerListener

Called when the mouse or a finger comes over the text. The whole block counts, gaps between letters and spaces included, so a menu option does not flicker as the pointer crosses it.

onPointerOutoptionalTPointerListener

Called when the pointer stops being over the text, or leaves the game.

onPointerMoveoptionalTPointerListener

Called when the pointer moves while over the text.

onPointerDownoptionalTPointerListener

Called when a button is pressed, or a finger touches, over the text.

onPointerUpoptionalTPointerListener

Called when a button is released, or a finger lifts, over the text.

onClickoptionalTPointerListener

Called when the text is pressed and released without leaving it. The cursor turns into a hand over it.

View source · gameobjects/text/types/t_text_options.ts:13

TTextStyletypenacatamalon

How a text is set: size, alignment and spacing. Kept apart from the rest of a text so it can be shared: several texts given the same style change together when it changes.

Properties

fontSizeoptionalnumber

How tall one line is, in pixels. Default: the font's own height, so the font as drawn. A pixel font looks crisp at whole multiples of its height (16 or 24 for an 8 pixel font) and uneven in between.

alignoptional'left' | 'center' | 'right'

Where each line sits inside the width of the longest one. Default 'left'.

letterSpacingoptionalnumber

Extra pixels between two characters. Default 0.

lineSpacingoptionalnumber

Extra pixels between two lines. Default 0.

View source · gameobjects/text/types/t_text_style.ts:9

TTransform2dtypenacatamalon

Where a game object is, how it is turned and how big it is drawn.

Every field is required and written out, rotation: 0, scaleX: 1, scaleY: 1 included. Spelled out rather than filled in from a default, so a transform read from a file, one built by hand and one the editor wrote are the same five numbers, and moving one never depends on which of the three it came from.

That is the object once made. Making one takes only the fields that differ from the defaults (createSprite({ transform: { x: 40, y: 112 } })), and the rest are filled in there.

Properties

xnumber
ynumber
rotationnumber
scaleXnumber
scaleYnumber
View source · gameobjects/types/t_transform_2d.ts:16

TTransform3dtypenacatamalon

TTransform3d: TTransform2d & { z, rotationX, rotationY, scaleZ, quaternion }

Where something is in three dimensions, how it is turned and how big it is drawn.

The 2D transform is exactly its flat half, with the same names: x, y, rotation (the turn in the plane, around Z) and scaleX/scaleY mean here what they mean there. That is what lets one box hold a 2D game, a 3D one, or both, without a second kind of placement to learn.

Rotations are in radians and applied Y, then X, then Z, and the whole is move, then turn, then scale. Written out rather than filled in from defaults, for the reason TTransform2d gives.

A quaternion is the other way to say which way something is turned, and when one is set it is the one that counts. Three angles cannot express every turn on their way to it: at certain facings two of the three end up turning around the same line and one of them stops doing anything, which is why a ship that is free to point anywhere, or a turn being eased from one facing to another, is stored this way instead.

View source · gameobjects/types/t_transform_3d.ts:24