Skip to content

Drawing with willow ​

The willow family connects your simulation to willow nodes without letting the two mix. Your systems change plain records. Once per tick, adapter.present() copies each record's state onto its node. Nothing else touches the nodes.

Import it from its folder; the package root never loads it:

ts
import { WillowPresentationAdapter, WillowPresentationState } from "gamekit/src/willow";

The adapter ​

new WillowPresentationAdapter<T>(createNode, readState, syncNode?) takes your functions:

FunctionCalled withReturns
createNode(record)A record that has no node yet.The willow Node to show it, for example a Quad or a sprite.
readState(record)Each bound record, during present().A WillowPresentationState: parent, x, y, rotation, scaleX, scaleY, pivotX, pivotY, skewX, skewY, alpha, visible, zOrder.
syncNode(record, node)Optional, after the state is copied.Nothing. Update node content here, such as a label's text or a sprite frame.

adapter.bind(record) returns a WillowBinding<T>. The node is created at the next present(). Call present() from a present phase so it runs after the simulation. Getting started has a complete window example.

If your simulation uses Transform2D from core, have readState copy it into the state. Simulation data never holds a node.

Bindings ​

CallWhat it does
binding.ticket()Takes a ticket for async work (see below).
binding.detach()Removes the node from the scene but keeps it, for moving to another parent.
binding.pool()Takes the record and parent away but keeps the node for reuse.
binding.reuse(record)Gives a pooled binding a new record.
binding.replace(record)Disposes the old node; a new one is created at the next present().
binding.dispose()Disposes the node and ends the binding.

Async work and tickets ​

Each lifecycle change starts a new binding generation. Before async work (loading a texture, say), take a WillowBindingTicket<T>; when the work finishes, ticket.apply(callback) runs the callback only if the binding is still on the same generation and its node is alive. A detach, pool, reuse, replace or dispose in between makes the old ticket do nothing, so late work never lands on a recycled or disposed node.

As a component ​

WillowPresentation<T> wraps a binding as a component. Add it to an entity under your own ComponentKey and it follows the entity: attach, detach, reparent and dispose are forwarded to the binding. The record's readState still chooses the scene parent, so the entity hierarchy and the willow hierarchy stay independent.

Ownership ​

The adapter owns only the nodes createNode returned. Call adapter.dispose() before you dispose scene roots that contain them. It never disposes the parent you chose or any other node.

Reference: WillowPresentationAdapter, WillowPresentationState, WillowBinding, WillowBindingTicket, WillowPresentation.