Skip to content

Running without a window ​

A console program (a thicket.json with no window section) can list willow too:

json5
{
    entry: "app.tks",
    systems: ["willow"],
}

There is no scene, so Scene.main is null and nothing is drawn. The display tree itself still works. This is handy for unit tests of game logic, level tools and servers that share code with the game.

What works ​

Every sample on these pages marked as run without a window was run that way to produce its output:

  • Building trees: new Node, add, remove, children, dispose, names and userData.
  • Transforms and conversions: worldPosition, localToWorld, worldToLocal, distanceTo, setSize.
  • Quad nodes, hit shapes (setHitCircle, hitShapeContains) and emit/on events.
  • NodeIndex lookups, including nodes leaving the index when disposed.
  • Physics roots and bodies, stepped with stepPhysics.
  • Text with Font.system(), and text.measure() and font.measure().
  • TweenGroup stepped by hand with update(dt).

What needs a window ​

Anything that makes or reads GPU pixels raises an error that names the problem, for example AssetError: Texture.fromPixels: texture: renderer not initialised. That includes:

  • Loading or creating textures (Texture.load, Texture.fromPixels), and so sprites from images.
  • Packing images into an atlas with Atlas.add.
  • Render textures and ToTexture.
  • Cached subtrees (setCacheAsTree has no effect).

To test code that uses these, keep the logic in plain classes and nodes, and give the window app the parts that load images.

ts
import { Node, Quad } from "willow";

class LogicTest {
    static main(): void {
        const scene: Scene | null = Scene.main;
        console.log("scene present: " + (scene !== null));

        const board: Node = new Node("board");
        for (let i: int = 0; i < 3; i++) {
            const cell: Quad = new Quad(32, 32, Color.WHITE);
            cell.setPosition(i * 40, 0);
            board.add(cell);
        }
        board.x = 100;
        const last: Vec2 = board.children()[2].worldPosition();
        console.log("cells: " + board.children().length + ", last at x = " + last.x);
    }
}

Output:

text
scene present: false
cells: 3, last at x = 180