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.

useSpawn returns a function that appends new nodes to a container at runtime. Call the returned spawn function with any JSX expression to create and attach the node as a child of the target container. This is the recommended pattern for dynamically creating enemies, projectiles, particles, or any node that does not exist at scene-load time.

useSpawn

Signature

useSpawn<T extends PrimaryNode>(node: NodeReference<T>): (jsx: Tiny.Node) => void

Parameters

node
NodeReference<T>
required
A NodeReference to the container node that will receive spawned children. Create this with useRefNode and attach it to a JSX node via the ref prop.

Return value

(jsx: Tiny.Node) => void — a spawn function. Pass any JSX expression to it; the resulting node tree is rendered and added as a child of the container.

Example — spawner that creates enemies on click

Spawner.tsx
import { useRefNode, useSpawn, useSignal } from 'tiny-engine/hooks'
import { PrimaryNode } from 'tiny-engine'

function Enemy({ x }: { x: number }) {
  return (
    <transform position={[x, 0]}>
      <sprite textureId={ENEMY_TEXTURE} />
    </transform>
  )
}

function Spawner() {
  const container = useRefNode(PrimaryNode.Transform)
  const spawn = useSpawn(container)
  const [count, setCount] = useSignal(0)

  const handleClick = () => {
    const x = (count() % 5) * 32
    spawn(<Enemy x={x} />)
    setCount(count() + 1)
  }

  return (
    <transform ref={container}>
      <clickable size={[64, 32]} onClick={handleClick}>
        <sprite textureId={SPAWN_BUTTON_TEXTURE} />
      </clickable>
    </transform>
  )
}

Example — spawning projectiles

Player.tsx
import { useRefNode, useSpawn } from 'tiny-engine/hooks'
import { PrimaryNode } from 'tiny-engine'

function Projectile({ y }: { y: number }) {
  return (
    <transform position={[0, y]}>
      <sprite textureId={BULLET_TEXTURE} />
      <collider shape={shapes.circle(4)} group={['projectile']} collidesWith={['enemy']} />
    </transform>
  )
}

function Player() {
  const root = useRefNode(PrimaryNode.Transform)
  const spawn = useSpawn(root)

  const shoot = () => spawn(<Projectile y={-8} />)

  return (
    <transform ref={root}>
      <sprite textureId={PLAYER_TEXTURE} />
      <clickable size={[32, 32]} onClick={shoot} />
    </transform>
  )
}
useSpawn captures the current hook context at the time the component function runs. This ensures that hooks used inside the spawned JSX component — such as useSignal or useEffect — are associated with the spawned node, not the parent. Always call spawn from event handlers or useMount, not during component setup.

useMount

useMount runs a callback when the component’s root node starts, and runs it again when the node is destroyed. If the callback returns a cleanup function, that cleanup is invoked first — immediately before the second call on destroy. Use useMount for setup and teardown code that should not re-run when signals change.

Signature

useMount(fn: () => void | (() => void)): void

Parameters

fn
() => void | (() => void)
required
The function to run when the node starts. It can optionally return a cleanup function that is invoked before fn is called again on node destroy.

Return value

void

Example

AudioPlayer.tsx
import { useMount } from 'tiny-engine/hooks'

function BackgroundMusic() {
  useMount(() => {
    const audio = new Audio('/assets/music/theme.mp3')
    audio.loop = true
    audio.play()

    // Cleanup: stop the audio when this node is removed from the scene
    return () => {
      audio.pause()
      audio.currentTime = 0
    }
  })

  return <transform />
}
Unlike useEffect, useMount does not track signals. It is ideal for imperative setup code — connecting to external systems, starting audio, registering DOM listeners — where you do not want reactive re-runs.

useGame

useGame returns the GameControls object, giving a component direct access to the global game loop and scene manager.

Signature

useGame(): GameControls

Return value

interface GameControls {
  play: () => void
  pause: () => void
  changeScene: (name: string) => Promise<void>
  preloadScene: (name: string) => Promise<() => void>
  getSize: () => Vector2
}
PropertyDescription
play()Resumes the game loop if it was paused.
pause()Pauses the game loop.
changeScene(name)Unloads the current scene and loads the named scene. Returns a promise that resolves when the transition is complete.
preloadScene(name)Loads the named scene in the background while the current scene remains active. Returns a promise that resolves to a setter function; call the setter to perform the instant scene swap.
getSize()Returns the canvas dimensions as a Vector2.

Example

PauseMenu.tsx
import { useGame, useRefNode, useEvent } from 'tiny-engine/hooks'
import { PrimaryNode } from 'tiny-engine'

function PauseMenu() {
  const game = useGame()
  const resumeBtn = useRefNode(PrimaryNode.Clickable)
  const menuBtn = useRefNode(PrimaryNode.Clickable)

  useEvent(resumeBtn, 'clicked', () => {
    game.play()
  })

  useEvent(menuBtn, 'clicked', async () => {
    await game.changeScene('MainMenu')
  })

  return (
    <transform>
      <clickable ref={resumeBtn} size={[100, 32]}>
        <sprite textureId={RESUME_TEXTURE} />
      </clickable>
      <clickable ref={menuBtn} size={[100, 32]}>
        <sprite textureId={MENU_TEXTURE} />
      </clickable>
    </transform>
  )
}

Build docs developers (and LLMs) love