ludic/api.html
2026-09-17 22:10:03 +00:00

146 lines
No EOL
258 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ludic — API Reference</title>
<meta name="description" content="The complete Ludic API Reference: every keyword, type, builtin, namespace, annotation and color, each on its own page, with fuzzy search.">
<link rel="stylesheet" href="base.css">
<link rel="stylesheet" href="docs.css">
</head>
<body>
<header class="nav"><div class="wrap nav-in"><a class="brand" href="index.html"><span class="logo">L</span> Ludic</a><button class="nav-toggle" aria-label="Toggle menu" aria-expanded="false">☰</button><nav class="nav-links"><a href="index.html">Home</a><a href="api.html">API Reference</a><a class="nav-cta" href="https://git.workshopsoft.io/workshopsoft/ludic">Source ↗</a></nav></div></header>
<main class="wrap ref">
<div class="ref-intro">
<div class="kicker">Reference</div>
<h1>API Reference</h1>
<p>Every keyword, type, phase, builtin, namespace method, annotation and color in Ludic — each on its own page. Search, or browse by section. In any code sample across this site, hover a token for a summary and click to jump to its page.</p>
<input id="search" class="search" type="search" placeholder="Search symbols… (e.g. handler, fill_rectangle, @Sync)" autocomplete="off" autofocus>
<div id="noresults" class="noresults" hidden>No symbols match.</div>
</div>
<section class="idx-sec" data-sec="structure"><h2 id="structure">Program structure</h2><p class="sec-blurb">The shape of a Ludic program: one <code>program</code> block holding declarations.</p><div class="idx-grid"><a class="idx-item" href="kw-program.html" data-name="program" data-tip="The top-level unit — one program compiles to one native game."><code>program</code><span>The top-level unit — one program compiles to one native game.</span></a><a class="idx-item" href="kw-property.html" data-name="property" data-tip="A named record of typed fields — a per-model component, or a plain heap record."><code>property</code><span>A named record of typed fields — a per-model component, or a plain heap record.</span></a><a class="idx-item" href="kw-model.html" data-name="model" data-tip="A named kind of thing — a fixed bundle of properties you spawn by one name."><code>model</code><span>A named kind of thing — a fixed bundle of properties you spawn by one name.</span></a><a class="idx-item" href="kw-handler.html" data-name="handler" data-tip="A named block the engine runs each frame during phase P."><code>handler</code><span>A named block the engine runs each frame during phase P.</span></a><a class="idx-item" href="kw-phase.html" data-name="phase" data-tip="Names which stage of the frame a handler runs in."><code>phase</code><span>Names which stage of the frame a handler runs in.</span></a><a class="idx-item" href="kw-const.html" data-name="const" data-tip="A compile-time constant, folded into the code with no storage."><code>const</code><span>A compile-time constant, folded into the code with no storage.</span></a><a class="idx-item" href="kw-var.html" data-name="var" data-tip="A mutable binding — at program scope, your game&#x27;s persistent named state."><code>var</code><span>A mutable binding — at program scope, your game's persistent named state.</span></a><a class="idx-item" href="kw-let.html" data-name="let" data-tip="An immutable binding — the default choice for a value that never changes."><code>let</code><span>An immutable binding — the default choice for a value that never changes.</span></a><a class="idx-item" href="kw-function.html" data-name="function" data-tip="A function — reusable logic called positionally or with named arguments."><code>function</code><span>A function — reusable logic called positionally or with named arguments.</span></a><a class="idx-item" href="kw-fn.html" data-name="fn" data-tip="A top-level function named as a value - the entry point handed to Job.parallel_for."><code>fn</code><span>A top-level function named as a value - the entry point handed to Job.parallel_for.</span></a><a class="idx-item" href="kw-prefab.html" data-name="prefab" data-tip="A model with preset component fields — spawn it, override what varies."><code>prefab</code><span>A model with preset component fields — spawn it, override what varies.</span></a><a class="idx-item" href="kw-return.html" data-name="return" data-tip="Hand a value back from a function and stop running it."><code>return</code><span>Hand a value back from a function and stop running it.</span></a><a class="idx-item" href="kw-entry.html" data-name="entry" data-tip="The program&#x27;s main block — runs once, top to bottom."><code>entry</code><span>The program's main block — runs once, top to bottom.</span></a><a class="idx-item" href="kw-import.html" data-name="import" data-tip="Splice another Ludic file&#x27;s declarations into this program."><code>import</code><span>Splice another Ludic file's declarations into this program.</span></a><a class="idx-item" href="kw-public.html" data-name="public" data-tip="Expose a declaration&#x27;s lifecycle on the public event bus."><code>public</code><span>Expose a declaration's lifecycle on the public event bus.</span></a><a class="idx-item" href="kw-extern.html" data-name="extern" data-tip="Bind a name to an external native symbol — the seam for platform and library calls."><code>extern</code><span>Bind a name to an external native symbol — the seam for platform and library calls.</span></a><a class="idx-item" href="kw-new.html" data-name="new" data-tip="Allocate a property record or an empty slice on the heap."><code>new</code><span>Allocate a property record or an empty slice on the heap.</span></a><a class="idx-item" href="kw-namespace.html" data-name="namespace" data-tip="Group functions into a Name.* namespace and control its public surface."><code>namespace</code><span>Group functions into a Name.* namespace and control its public surface.</span></a><a class="idx-item" href="kw-enum.html" data-name="enum" data-tip="A named set of integer constants — names for a magic-number space."><code>enum</code><span>A named set of integer constants — names for a magic-number space.</span></a><a class="idx-item" href="kw-ui.html" data-name="ui" data-tip="Declare a retained widget tree as data; the engine lays it out and draws it."><code>ui</code><span>Declare a retained widget tree as data; the engine lays it out and draws it.</span></a></div></section><section class="idx-sec" data-sec="ecs"><h2 id="ecs">Entities &amp; the ECS</h2><p class="sec-blurb">Entities are ids; properties are their data; queries walk them.</p><div class="idx-grid"><a class="idx-item" href="kw-spawn.html" data-name="spawn" data-tip="Create a model instance carrying the listed properties, seeding their fields."><code>spawn</code><span>Create a model instance carrying the listed properties, seeding their fields.</span></a><a class="idx-item" href="kw-despawn.html" data-name="despawn" data-tip="Remove a model instance from the world, firing any @OnDespawn hooks."><code>despawn</code><span>Remove a model instance from the world, firing any @OnDespawn hooks.</span></a><a class="idx-item" href="kw-query.html" data-name="query" data-tip="Match every model instance carrying all the listed properties."><code>query</code><span>Match every model instance carrying all the listed properties.</span></a><a class="idx-item" href="kw-self.html" data-name="self" data-tip="The model instance currently bound by the enclosing query loop."><code>self</code><span>The model instance currently bound by the enclosing query loop.</span></a><a class="idx-item" href="kw-enable.html" data-name="enable" data-tip="Re-activate a disabled property, model, or handler — its data is intact."><code>enable</code><span>Re-activate a disabled property, model, or handler — its data is intact.</span></a><a class="idx-item" href="kw-disable.html" data-name="disable" data-tip="Deactivate a property, model, or handler without destroying its data."><code>disable</code><span>Deactivate a property, model, or handler without destroying its data.</span></a><a class="idx-item" href="kw-attach.html" data-name="attach" data-tip="Structurally add a property to a live model instance, seeding its fields."><code>attach</code><span>Structurally add a property to a live model instance, seeding its fields.</span></a><a class="idx-item" href="kw-detach.html" data-name="detach" data-tip="Structurally remove a property from a live model instance."><code>detach</code><span>Structurally remove a property from a live model instance.</span></a><a class="idx-item" href="fn-world_attach_dyn.html" data-name="world_attach_dyn" data-tip="Attach a property to an instance by numeric id at runtime (dynamic ECS)."><code>world_attach_dyn</code><span>Attach a property to an instance by numeric id at runtime (dynamic ECS).</span></a><a class="idx-item" href="fn-world_count.html" data-name="world_count" data-tip="The total number of live model instances in the world."><code>world_count</code><span>The total number of live model instances in the world.</span></a><a class="idx-item" href="fn-world_detach_dyn.html" data-name="world_detach_dyn" data-tip="Detach a property from an instance by numeric id at runtime (dynamic ECS)."><code>world_detach_dyn</code><span>Detach a property from an instance by numeric id at runtime (dynamic ECS).</span></a><a class="idx-item" href="fn-world_field_id.html" data-name="world_field_id" data-tip="Resolve a field name within a property to its numeric index."><code>world_field_id</code><span>Resolve a field name within a property to its numeric index.</span></a><a class="idx-item" href="fn-world_get.html" data-name="world_get" data-tip="Read one field of a model instance by numeric id (reflection ABI)."><code>world_get</code><span>Read one field of a model instance by numeric id (reflection ABI).</span></a><a class="idx-item" href="fn-world_has.html" data-name="world_has" data-tip="Test whether a model instance currently carries a property."><code>world_has</code><span>Test whether a model instance currently carries a property.</span></a><a class="idx-item" href="fn-world_kind.html" data-name="world_kind" data-tip="The model id of an instance — which kind of thing it is."><code>world_kind</code><span>The model id of an instance — which kind of thing it is.</span></a><a class="idx-item" href="fn-world_load.html" data-name="world_load" data-tip="Restore the whole world from a serialized byte buffer."><code>world_load</code><span>Restore the whole world from a serialized byte buffer.</span></a><a class="idx-item" href="fn-world_model_id.html" data-name="world_model_id" data-tip="Resolve a model&#x27;s name to its stable numeric id."><code>world_model_id</code><span>Resolve a model's name to its stable numeric id.</span></a><a class="idx-item" href="fn-world_prop_id.html" data-name="world_prop_id" data-tip="Resolve a property&#x27;s name to its stable numeric id."><code>world_prop_id</code><span>Resolve a property's name to its stable numeric id.</span></a><a class="idx-item" href="fn-world_query_next.html" data-name="world_query_next" data-tip="Step to the next instance carrying a property, walking the world by id."><code>world_query_next</code><span>Step to the next instance carrying a property, walking the world by id.</span></a><a class="idx-item" href="fn-world_register_prop.html" data-name="world_register_prop" data-tip="Register a brand-new property at runtime and get its id (dynamic ECS)."><code>world_register_prop</code><span>Register a brand-new property at runtime and get its id (dynamic ECS).</span></a><a class="idx-item" href="fn-world_save.html" data-name="world_save" data-tip="Serialize the whole world into a buffer; returns the number of bytes written."><code>world_save</code><span>Serialize the whole world into a buffer; returns the number of bytes written.</span></a><a class="idx-item" href="fn-world_set.html" data-name="world_set" data-tip="Write one field of a model instance by numeric id (reflection ABI)."><code>world_set</code><span>Write one field of a model instance by numeric id (reflection ABI).</span></a><a class="idx-item" href="fn-world_size.html" data-name="world_size" data-tip="The number of live model instances in the world."><code>world_size</code><span>The number of live model instances in the world.</span></a><a class="idx-item" href="fn-world_spawn.html" data-name="world_spawn" data-tip="Spawn an instance of a model chosen by numeric id at runtime."><code>world_spawn</code><span>Spawn an instance of a model chosen by numeric id at runtime.</span></a></div></section><section class="idx-sec" data-sec="control"><h2 id="control">Control flow</h2><p class="sec-blurb">Branches, loops, and state machines.</p><div class="idx-grid"><a class="idx-item" href="kw-if.html" data-name="if / else" data-tip="A branch — run one block when a condition holds, another when it doesn&#x27;t."><code>if / else</code><span>A branch — run one block when a condition holds, another when it doesn't.</span></a><a class="idx-item" href="kw-while.html" data-name="while" data-tip="Loop as long as a condition holds, re-checking it before each pass."><code>while</code><span>Loop as long as a condition holds, re-checking it before each pass.</span></a><a class="idx-item" href="kw-for.html" data-name="for … in" data-tip="Range loop — iterate the half-open range from a up to but not including b."><code>for … in</code><span>Range loop — iterate the half-open range from a up to but not including b.</span></a><a class="idx-item" href="kw-in.html" data-name="in" data-tip="The part of a for loop that names what to iterate — a range or a query."><code>in</code><span>The part of a for loop that names what to iterate — a range or a query.</span></a><a class="idx-item" href="kw-match.html" data-name="match" data-tip="Multi-way branch on one value, matching one or more literals per arm."><code>match</code><span>Multi-way branch on one value, matching one or more literals per arm.</span></a><a class="idx-item" href="kw-machine.html" data-name="machine" data-tip="An explicit state machine over an int var — dispatches on the store&#x27;s value."><code>machine</code><span>An explicit state machine over an int var — dispatches on the store's value.</span></a><a class="idx-item" href="kw-state.html" data-name="state" data-tip="One state of a machine — its body runs while the machine sits in it."><code>state</code><span>One state of a machine — its body runs while the machine sits in it.</span></a><a class="idx-item" href="kw-become.html" data-name="become" data-tip="Transition to another state of the enclosing machine, or to another scene."><code>become</code><span>Transition to another state of the enclosing machine, or to another scene.</span></a><a class="idx-item" href="kw-break.html" data-name="break" data-tip="Leave the enclosing loop immediately."><code>break</code><span>Leave the enclosing loop immediately.</span></a><a class="idx-item" href="kw-continue.html" data-name="continue" data-tip="Skip to the next iteration of the loop."><code>continue</code><span>Skip to the next iteration of the loop.</span></a><a class="idx-item" href="kw-where.html" data-name="where" data-tip="Filter a query loop to entities that satisfy a condition."><code>where</code><span>Filter a query loop to entities that satisfy a condition.</span></a><a class="idx-item" href="kw-try.html" data-name="try" data-tip="Recover a fallible result as a value, with a fallback — no exceptions, no unwinding."><code>try</code><span>Recover a fallible result as a value, with a fallback — no exceptions, no unwinding.</span></a></div></section><section class="idx-sec" data-sec="scenes"><h2 id="scenes">Scenes &amp; layers</h2><p class="sec-blurb">One active scene at a time, each grouping handlers into layers.</p><div class="idx-grid"><a class="idx-item" href="kw-scene.html" data-name="scene" data-tip="A mutually-exclusive game state — a title screen, the overworld, a battle."><code>scene</code><span>A mutually-exclusive game state — a title screen, the overworld, a battle.</span></a><a class="idx-item" href="kw-layer.html" data-name="layer" data-tip="A named group of handlers inside a scene; layers render in declaration order."><code>layer</code><span>A named group of handlers inside a scene; layers render in declaration order.</span></a><a class="idx-item" href="kw-on.html" data-name="on enter / on exit" data-tip="Scene lifecycle hooks that fire as a scene becomes active or is left."><code>on enter / on exit</code><span>Scene lifecycle hooks that fire as a scene becomes active or is left.</span></a><a class="idx-item" href="kw-enter.html" data-name="enter" data-tip="The scene-entry hook — runs once as a scene becomes active."><code>enter</code><span>The scene-entry hook — runs once as a scene becomes active.</span></a><a class="idx-item" href="kw-exit.html" data-name="exit" data-tip="The scene-exit hook — runs once as a scene is left."><code>exit</code><span>The scene-exit hook — runs once as a scene is left.</span></a><a class="idx-item" href="kw-start.html" data-name="start" data-tip="Marks the one scene the game begins in."><code>start</code><span>Marks the one scene the game begins in.</span></a></div></section><section class="idx-sec" data-sec="events"><h2 id="events">Events</h2><p class="sec-blurb">Decoupled, named messages between handlers.</p><div class="idx-grid"><a class="idx-item" href="kw-event.html" data-name="event" data-tip="Declare a public event carrying a flat payload that listeners react to."><code>event</code><span>Declare a public event carrying a flat payload that listeners react to.</span></a><a class="idx-item" href="kw-emit.html" data-name="emit" data-tip="Fire an event, running every listener; as an expression it yields the veto flag."><code>emit</code><span>Fire an event, running every listener; as an expression it yields the veto flag.</span></a><a class="idx-item" href="kw-cancel.html" data-name="cancel" data-tip="Inside a listener, veto the cancellable event being emitted."><code>cancel</code><span>Inside a listener, veto the cancellable event being emitted.</span></a><a class="idx-item" href="kw-cancellable.html" data-name="cancellable" data-tip="Marks an event whose listeners may veto it with cancel."><code>cancellable</code><span>Marks an event whose listeners may veto it with cancel.</span></a></div></section><section class="idx-sec" data-sec="screen"><h2 id="screen">Screen — drawing</h2><p class="sec-blurb">The 2D drawing surface. Every call takes named arguments; draw during the <code>Render</code> phase, then <code>Screen.show()</code>.</p><div class="idx-grid"><a class="idx-item" href="screen-clear.html" data-name="Screen.clear" data-tip="Fill the whole framebuffer with one color to start a fresh frame."><code>Screen.clear</code><span>Fill the whole framebuffer with one color to start a fresh frame.</span></a><a class="idx-item" href="screen-fill_rectangle.html" data-name="Screen.fill_rectangle" data-tip="Draw a solid, filled rectangle at a pixel position."><code>Screen.fill_rectangle</code><span>Draw a solid, filled rectangle at a pixel position.</span></a><a class="idx-item" href="screen-draw_rectangle.html" data-name="Screen.draw_rectangle" data-tip="Draw a one-pixel-thick rectangle outline (not filled)."><code>Screen.draw_rectangle</code><span>Draw a one-pixel-thick rectangle outline (not filled).</span></a><a class="idx-item" href="screen-put_pixel.html" data-name="Screen.put_pixel" data-tip="Set a single pixel at a pixel coordinate to one color."><code>Screen.put_pixel</code><span>Set a single pixel at a pixel coordinate to one color.</span></a><a class="idx-item" href="screen-draw_text.html" data-name="Screen.draw_text" data-tip="Draw a string with the built-in font at an integer scale."><code>Screen.draw_text</code><span>Draw a string with the built-in font at an integer scale.</span></a><a class="idx-item" href="screen-draw_number.html" data-name="Screen.draw_number" data-tip="Draw an integer directly, with no string allocation or conversion."><code>Screen.draw_number</code><span>Draw an integer directly, with no string allocation or conversion.</span></a><a class="idx-item" href="screen-show.html" data-name="Screen.show" data-tip="Present the finished frame — copy everything drawn this frame to the window."><code>Screen.show</code><span>Present the finished frame — copy everything drawn this frame to the window.</span></a><a class="idx-item" href="screen-width.html" data-name="Screen.width" data-tip="The framebuffer width in pixels."><code>Screen.width</code><span>The framebuffer width in pixels.</span></a><a class="idx-item" href="screen-height.html" data-name="Screen.height" data-tip="The framebuffer height in pixels."><code>Screen.height</code><span>The framebuffer height in pixels.</span></a><a class="idx-item" href="screen-status.html" data-name="Screen.status" data-tip="Set the persistent one-line status/HUD string shown by the runtime."><code>Screen.status</code><span>Set the persistent one-line status/HUD string shown by the runtime.</span></a><a class="idx-item" href="screen-line.html" data-name="Screen.line" data-tip="Draw a straight line between two points."><code>Screen.line</code><span>Draw a straight line between two points.</span></a><a class="idx-item" href="screen-circle.html" data-name="Screen.circle" data-tip="Draw a circle outline."><code>Screen.circle</code><span>Draw a circle outline.</span></a><a class="idx-item" href="screen-fill_circle.html" data-name="Screen.fill_circle" data-tip="Draw a filled disc."><code>Screen.fill_circle</code><span>Draw a filled disc.</span></a><a class="idx-item" href="screen-triangle.html" data-name="Screen.triangle" data-tip="Draw a triangle outline."><code>Screen.triangle</code><span>Draw a triangle outline.</span></a><a class="idx-item" href="screen-fill_triangle.html" data-name="Screen.fill_triangle" data-tip="Draw a filled triangle."><code>Screen.fill_triangle</code><span>Draw a filled triangle.</span></a><a class="idx-item" href="screen-sprite.html" data-name="Screen.sprite" data-tip="Blit a sprite at its natural size."><code>Screen.sprite</code><span>Blit a sprite at its natural size.</span></a><a class="idx-item" href="screen-sprite_scaled.html" data-name="Screen.sprite_scaled" data-tip="Blit a sprite at an integer scale."><code>Screen.sprite_scaled</code><span>Blit a sprite at an integer scale.</span></a><a class="idx-item" href="screen-oval.html" data-name="Screen.oval" data-tip="Draw an axis-aligned ellipse outline."><code>Screen.oval</code><span>Draw an axis-aligned ellipse outline.</span></a><a class="idx-item" href="screen-camera.html" data-name="Screen.camera" data-tip="Set the world-space camera offset for the draw path."><code>Screen.camera</code><span>Set the world-space camera offset for the draw path.</span></a><a class="idx-item" href="screen-clip.html" data-name="Screen.clip" data-tip="Restrict drawing to a screen-space rectangle."><code>Screen.clip</code><span>Restrict drawing to a screen-space rectangle.</span></a><a class="idx-item" href="screen-clip_reset.html" data-name="Screen.clip_reset" data-tip="Lift the clip rectangle (draw to the whole screen again)."><code>Screen.clip_reset</code><span>Lift the clip rectangle (draw to the whole screen again).</span></a><a class="idx-item" href="screen-blend_mode.html" data-name="Screen.blend_mode" data-tip="Choose replace or additive pixel blending."><code>Screen.blend_mode</code><span>Choose replace or additive pixel blending.</span></a><a class="idx-item" href="screen-measure_text.html" data-name="Screen.measure_text" data-tip="The pixel advance width of text in the built-in font."><code>Screen.measure_text</code><span>The pixel advance width of text in the built-in font.</span></a><a class="idx-item" href="screen-pixel.html" data-name="Screen.pixel" data-tip="Read a framebuffer pixel (0x00RRGGBB), or 0 if off-screen."><code>Screen.pixel</code><span>Read a framebuffer pixel (0x00RRGGBB), or 0 if off-screen.</span></a><a class="idx-item" href="screen-bar.html" data-name="Screen.bar" data-tip="A filled meter: value of max over a track."><code>Screen.bar</code><span>A filled meter: value of max over a track.</span></a></div></section><section class="idx-sec" data-sec="clock"><h2 id="clock">Clock</h2><p class="sec-blurb">A game-controlled simulated clock: a single seconds counter the game owns. Unlike <code>Time.now</code> / <code>Time.since</code>, it never reads the wall clock, so any gameplay that reads <code>Clock.now()</code> is deterministic and replay-safe. Set it outright, or advance it by a <code>Duration</code> each tick to run time at whatever rate the simulation wants. The clock is a plain instant (seconds since 1970), so all the <code>DateTime.*</code> readers work on it directly.</p><div class="idx-grid"><a class="idx-item" href="clock-now.html" data-name="Clock.now" data-tip="The current simulated instant."><code>Clock.now</code><span>The current simulated instant.</span></a><a class="idx-item" href="clock-set.html" data-name="Clock.set" data-tip="Set the clock to an instant."><code>Clock.set</code><span>Set the clock to an instant.</span></a><a class="idx-item" href="clock-advance.html" data-name="Clock.advance" data-tip="Move the clock forward by a Duration."><code>Clock.advance</code><span>Move the clock forward by a Duration.</span></a><a class="idx-item" href="clock-reset.html" data-name="Clock.reset" data-tip="Reset the clock to the epoch (0)."><code>Clock.reset</code><span>Reset the clock to the epoch (0).</span></a></div></section><section class="idx-sec" data-sec="collision"><h2 id="collision">Collision</h2><p class="sec-blurb">2D overlap tests on integer coordinates (pixels or tiles). Rectangles are <code>(x, y, w, h)</code> from the top-left; circles are <code>(x, y, r)</code>. Each returns a bool. Squared distances are computed in 64-bit so large coordinates never overflow.
These are static boolean tests. For a *moving* body with real collision resolution, the engine ships a physics-lite movement system built on the same integer math — declare the well-known components and the engine advances them for you each frame, no handler wired:
- <code>property Body { vx, vy, gravity, max_fall, rx, ry, policy, on_ground, hit_wall, hit_ceiling }</code> — velocity/accel state in Q16.16 fixed-point (<code>vx</code>/<code>vy</code>/<code>gravity</code>/<code>max_fall</code>), engine-owned sub-pixel accumulators (<code>rx</code>/<code>ry</code>), an integration <code>policy</code> (<code>0</code> platformer with gravity, <code>1</code> top-down), and the derived contact flags the engine sets each frame.
- <code>property Collider { w, h, offx, offy, is_trigger, one_way, layer, mask, hit, entered, exited }</code> — an AABB shape offset from the entity's <code>Position { x, y }</code>, with layer/mask filtering, one-way-platform and trigger flags, and per-frame trigger outputs.
- <code>property Solids { tile, wall, oneway }</code> — an optional single config entity that turns on the tile-grid broadphase over the <a href="map"><code>Map</code></a> tilemap (<code>tile</code> px size, the solid <code>wall</code> glyph, and an optional one-way <code>oneway</code> glyph).
The engine-owned <code>esys_move</code> system (Update phase) integrates velocity and gravity into a tentative move, then resolves it with a per-axis **swept AABB** — against both solid <code>Collider</code> entities and the tile grid — so a fast body never tunnels through a wall. It handles one-way platforms (which block only a downward landing), reports trigger/sensor overlaps without resolving them, and sets <code>on_ground</code> / <code>hit_wall</code> / <code>hit_ceiling</code> for a controller to read. Everything is integer and deterministic, so movement reproduces exactly under replay, lockstep and <code>world_save</code> snapshots. Contact is surfaced as polled flags (the <code>SpriteAnim.event_fired</code> shape) rather than engine-emitted events, so a game raises its own <code>CollisionResolved</code> / <code>TriggerEntered</code> events from its handler with no coupling. This is the shared foundation the built-in gameplay controllers build on. Related: <a href="grid"><code>Grid</code></a>, <a href="map"><code>Map</code></a>, <a href="motion"><code>Motion</code></a>, <a href="annot-enginesystem"><code>@EngineSystem</code></a>.</p><div class="idx-grid"><a class="idx-item" href="collision-rects.html" data-name="Collision.rects" data-tip="Do two rectangles overlap?"><code>Collision.rects</code><span>Do two rectangles overlap?</span></a><a class="idx-item" href="collision-point_rect.html" data-name="Collision.point_rect" data-tip="Is a point inside a rectangle?"><code>Collision.point_rect</code><span>Is a point inside a rectangle?</span></a><a class="idx-item" href="collision-circles.html" data-name="Collision.circles" data-tip="Do two circles overlap?"><code>Collision.circles</code><span>Do two circles overlap?</span></a><a class="idx-item" href="collision-rect_circle.html" data-name="Collision.rect_circle" data-tip="Does a rectangle overlap a circle?"><code>Collision.rect_circle</code><span>Does a rectangle overlap a circle?</span></a></div></section><section class="idx-sec" data-sec="color"><h2 id="color">Color functions</h2><p class="sec-blurb">Building and blending colors at runtime. Colors are <code>0x00RRGGBB</code> ints; these pack channels and transform an existing color. The named palette constants (<code>Color.Charcoal</code>, …) are a separate compile-time set.</p><div class="idx-grid"><a class="idx-item" href="color-rgb.html" data-name="Color.rgb" data-tip="Build a color from red, green, blue."><code>Color.rgb</code><span>Build a color from red, green, blue.</span></a><a class="idx-item" href="color-rgba.html" data-name="Color.rgba" data-tip="Build a color with an alpha byte."><code>Color.rgba</code><span>Build a color with an alpha byte.</span></a><a class="idx-item" href="color-lerp.html" data-name="Color.lerp" data-tip="Blend between two colors."><code>Color.lerp</code><span>Blend between two colors.</span></a><a class="idx-item" href="color-darken.html" data-name="Color.darken" data-tip="Scale a color toward black."><code>Color.darken</code><span>Scale a color toward black.</span></a><a class="idx-item" href="color-lighten.html" data-name="Color.lighten" data-tip="Scale a color toward white."><code>Color.lighten</code><span>Scale a color toward white.</span></a><a class="idx-item" href="color-with_alpha.html" data-name="Color.with_alpha" data-tip="Replace a color&#x27;s alpha byte."><code>Color.with_alpha</code><span>Replace a color's alpha byte.</span></a></div></section><section class="idx-sec" data-sec="crypto"><h2 id="crypto">Crypto</h2><p class="sec-blurb">Secure, test-vector-backed hashing for the handful of security-sensitive things a game actually does: signing a save or leaderboard payload so casual tampering is detectable, and verifying that a network message or token was not forged by someone who does not hold the key. This is the deliberate counterpart to the fast <a href="ns-Hash"><code>Hash</code></a> library — same idea, opposite trade-off. <code>Hash</code> is fast and reversible and must never guard anything; <code>Crypto</code> is <a href="crypto-sha256"><code>SHA-256</code></a> and <a href="crypto-hmac_sha256"><code>HMAC-SHA256</code></a> implemented to the standard, so the algorithms are the ones with published known-answer tests rather than anything home-grown.
Digests are returned as lowercase hex strings, not raw bytes — a <code>str</code> is null-terminated and a raw digest can contain a zero byte, so hex is the form you can print, store, and compare directly.
Alongside hashing, this library exposes the OS cryptographically-secure random generator — <a href="crypto-random_bytes"><code>random_bytes</code></a>, <a href="crypto-random_hex"><code>random_hex</code></a>, and <a href="crypto-random_u32"><code>random_u32</code></a> — for tokens, nonces, and <a href="ns-Uuid"><code>Uuid</code></a> generation, plus <a href="crypto-base64"><code>base64</code></a> for moving bytes through text-only channels. The secure-random helpers are deliberately non-deterministic and must never seed the lockstep simulation RNG (<a href="ns-Random"><code>Random</code></a>).
What this is not: it is not DRM and it is not unbeatable anti-cheat. A client-side game cannot keep a secret from the machine it runs on — a determined owner can always read the key out of the binary. Use it to make *casual* tampering detectable and to authenticate messages between parties who share a key. To verify a MAC always use <a href="crypto-verify_hmac"><code>Crypto.verify_hmac</code></a> (a constant-time check), never <code>==</code>, which leaks how much of a guessed MAC was correct.</p><div class="idx-grid"><a class="idx-item" href="crypto-sha256.html" data-name="Crypto.sha256" data-tip="SHA-256 of a string, as 64 hex characters."><code>Crypto.sha256</code><span>SHA-256 of a string, as 64 hex characters.</span></a><a class="idx-item" href="crypto-hmac_sha256.html" data-name="Crypto.hmac_sha256" data-tip="Sign a message with a shared secret key."><code>Crypto.hmac_sha256</code><span>Sign a message with a shared secret key.</span></a><a class="idx-item" href="crypto-verify_hmac.html" data-name="Crypto.verify_hmac" data-tip="Constant-time check that a MAC matches."><code>Crypto.verify_hmac</code><span>Constant-time check that a MAC matches.</span></a><a class="idx-item" href="crypto-hex.html" data-name="Crypto.hex" data-tip="Lowercase hex of a string&#x27;s bytes."><code>Crypto.hex</code><span>Lowercase hex of a string's bytes.</span></a><a class="idx-item" href="crypto-ct_equal.html" data-name="Crypto.ct_equal" data-tip="Constant-time string equality for secrets."><code>Crypto.ct_equal</code><span>Constant-time string equality for secrets.</span></a><a class="idx-item" href="crypto-random_bytes.html" data-name="Crypto.random_bytes" data-tip="n bytes from the OS CSPRNG, as a 2n-character hex string."><code>Crypto.random_bytes</code><span>n bytes from the OS CSPRNG, as a 2n-character hex string.</span></a><a class="idx-item" href="crypto-random_hex.html" data-name="Crypto.random_hex" data-tip="Alias for random_bytes — n secure bytes as a 2n-char hex string."><code>Crypto.random_hex</code><span>Alias for random_bytes — n secure bytes as a 2n-char hex string.</span></a><a class="idx-item" href="crypto-random_u32.html" data-name="Crypto.random_u32" data-tip="One CSPRNG-drawn 32-bit integer."><code>Crypto.random_u32</code><span>One CSPRNG-drawn 32-bit integer.</span></a><a class="idx-item" href="crypto-base64.html" data-name="Crypto.base64" data-tip="Standard base64 (RFC 4648) of a string&#x27;s bytes."><code>Crypto.base64</code><span>Standard base64 (RFC 4648) of a string's bytes.</span></a></div></section><section class="idx-sec" data-sec="date"><h2 id="date">Date</h2><p class="sec-blurb">Calendar days on the proleptic Gregorian calendar (UTC). A <code>Date</code> is stored as a plain <code>int</code>: the count of days since 1970-01-01, so shifting a date by whole days is ordinary integer arithmetic and two dates subtract to a day count. Build one with <code>Date.new</code>, read its parts with <code>year</code>/<code>month</code>/<code>day</code>/<code>weekday</code>. Every operation is deterministic integer math — no leap seconds, no timezone, no floating point.</p><div class="idx-grid"><a class="idx-item" href="date-new.html" data-name="Date.new" data-tip="A calendar day as days-since-1970."><code>Date.new</code><span>A calendar day as days-since-1970.</span></a><a class="idx-item" href="date-year.html" data-name="Date.year" data-tip="The calendar year of a date."><code>Date.year</code><span>The calendar year of a date.</span></a><a class="idx-item" href="date-month.html" data-name="Date.month" data-tip="The month (1-12) of a date."><code>Date.month</code><span>The month (1-12) of a date.</span></a><a class="idx-item" href="date-day.html" data-name="Date.day" data-tip="The day of the month (1-31) of a date."><code>Date.day</code><span>The day of the month (1-31) of a date.</span></a><a class="idx-item" href="date-weekday.html" data-name="Date.weekday" data-tip="Day of the week, 0=Sunday..6=Saturday."><code>Date.weekday</code><span>Day of the week, 0=Sunday..6=Saturday.</span></a><a class="idx-item" href="date-is_leap.html" data-name="Date.is_leap" data-tip="True if the year is a leap year."><code>Date.is_leap</code><span>True if the year is a leap year.</span></a><a class="idx-item" href="date-days_in_month.html" data-name="Date.days_in_month" data-tip="Number of days in a given month."><code>Date.days_in_month</code><span>Number of days in a given month.</span></a><a class="idx-item" href="date-to_epoch.html" data-name="Date.to_epoch" data-tip="Midnight UTC of the day, as a DateTime."><code>Date.to_epoch</code><span>Midnight UTC of the day, as a DateTime.</span></a><a class="idx-item" href="date-add_days.html" data-name="Date.add_days" data-tip="The date n days later (n may be negative)."><code>Date.add_days</code><span>The date n days later (n may be negative).</span></a><a class="idx-item" href="date-diff_days.html" data-name="Date.diff_days" data-tip="Whole days from b to a (a - b)."><code>Date.diff_days</code><span>Whole days from b to a (a - b).</span></a></div></section><section class="idx-sec" data-sec="datetime"><h2 id="datetime">DateTime</h2><p class="sec-blurb">Instants on the wall-clock timeline (UTC), stored as a plain <code>int</code>: the count of seconds since 1970-01-01, matching <code>Time.now</code>. Build one with <code>DateTime.from</code>, shift it by a <code>Duration</code> with <code>DateTime.add</code>, and pull it apart with the <code>year</code>/<code>month</code>/<code>day</code>/<code>hour</code>/<code>minute</code>/<code>second</code> readers. Deterministic integer math throughout; v1 is UTC-only with no leap seconds, and assumes instants at or after 1970.</p><div class="idx-grid"><a class="idx-item" href="datetime-from.html" data-name="DateTime.from" data-tip="Build an instant from its calendar parts."><code>DateTime.from</code><span>Build an instant from its calendar parts.</span></a><a class="idx-item" href="datetime-date.html" data-name="DateTime.date" data-tip="The calendar day the instant falls on."><code>DateTime.date</code><span>The calendar day the instant falls on.</span></a><a class="idx-item" href="datetime-add.html" data-name="DateTime.add" data-tip="The instant `span` seconds later."><code>DateTime.add</code><span>The instant `span` seconds later.</span></a><a class="idx-item" href="datetime-year.html" data-name="DateTime.year" data-tip="The calendar year of an instant."><code>DateTime.year</code><span>The calendar year of an instant.</span></a><a class="idx-item" href="datetime-month.html" data-name="DateTime.month" data-tip="The month (1-12) of an instant."><code>DateTime.month</code><span>The month (1-12) of an instant.</span></a><a class="idx-item" href="datetime-day.html" data-name="DateTime.day" data-tip="The day of the month (1-31) of an instant."><code>DateTime.day</code><span>The day of the month (1-31) of an instant.</span></a><a class="idx-item" href="datetime-weekday.html" data-name="DateTime.weekday" data-tip="Day of the week, 0=Sunday..6=Saturday."><code>DateTime.weekday</code><span>Day of the week, 0=Sunday..6=Saturday.</span></a><a class="idx-item" href="datetime-hour.html" data-name="DateTime.hour" data-tip="The hour of day (0-23) of an instant."><code>DateTime.hour</code><span>The hour of day (0-23) of an instant.</span></a><a class="idx-item" href="datetime-minute.html" data-name="DateTime.minute" data-tip="The minute of the hour (0-59) of an instant."><code>DateTime.minute</code><span>The minute of the hour (0-59) of an instant.</span></a><a class="idx-item" href="datetime-second.html" data-name="DateTime.second" data-tip="The second of the minute (0-59) of an instant."><code>DateTime.second</code><span>The second of the minute (0-59) of an instant.</span></a><a class="idx-item" href="datetime-format.html" data-name="DateTime.format" data-tip="Render an instant as text using a token pattern."><code>DateTime.format</code><span>Render an instant as text using a token pattern.</span></a><a class="idx-item" href="datetime-parse.html" data-name="DateTime.parse" data-tip="Parse text into an instant; -1 on failure."><code>DateTime.parse</code><span>Parse text into an instant; -1 on failure.</span></a></div></section><section class="idx-sec" data-sec="duration"><h2 id="duration">Duration</h2><p class="sec-blurb">Spans of real time, measured in whole seconds and carried in a plain <code>int</code> — so a duration adds, subtracts and compares with the ordinary operators (<code>Duration.minutes(5) + Duration.seconds(30)</code>, <code>away &gt; Duration.hours(3)</code>). The constructors build a span from a unit; the <code>as_*</code> readers convert a span back to whole units (truncating toward zero). Integer-only, so no floating-point drift.</p><div class="idx-grid"><a class="idx-item" href="duration-seconds.html" data-name="Duration.seconds" data-tip="A span of n whole seconds."><code>Duration.seconds</code><span>A span of n whole seconds.</span></a><a class="idx-item" href="duration-minutes.html" data-name="Duration.minutes" data-tip="A span of n minutes, in seconds."><code>Duration.minutes</code><span>A span of n minutes, in seconds.</span></a><a class="idx-item" href="duration-hours.html" data-name="Duration.hours" data-tip="A span of n hours, in seconds."><code>Duration.hours</code><span>A span of n hours, in seconds.</span></a><a class="idx-item" href="duration-days.html" data-name="Duration.days" data-tip="A span of n days, in seconds."><code>Duration.days</code><span>A span of n days, in seconds.</span></a><a class="idx-item" href="duration-as_seconds.html" data-name="Duration.as_seconds" data-tip="The span in whole seconds."><code>Duration.as_seconds</code><span>The span in whole seconds.</span></a><a class="idx-item" href="duration-as_minutes.html" data-name="Duration.as_minutes" data-tip="The span in whole minutes."><code>Duration.as_minutes</code><span>The span in whole minutes.</span></a><a class="idx-item" href="duration-as_hours.html" data-name="Duration.as_hours" data-tip="The span in whole hours."><code>Duration.as_hours</code><span>The span in whole hours.</span></a><a class="idx-item" href="duration-as_days.html" data-name="Duration.as_days" data-tip="The span in whole days."><code>Duration.as_days</code><span>The span in whole days.</span></a></div></section><section class="idx-sec" data-sec="ease"><h2 id="ease">Ease</h2><p class="sec-blurb">Tween curves — the "juice" layer. Each takes a normalized amount <code>t</code> in <code>0.0</code>..<code>1.0</code> and returns an eased <code>fixed</code>, ready to feed to <code>Math.lerp</code>. All deterministic fixed-point.</p><div class="idx-grid"><a class="idx-item" href="ease-in.html" data-name="Ease.in" data-tip="Accelerate from rest (quadratic ease-in)."><code>Ease.in</code><span>Accelerate from rest (quadratic ease-in).</span></a><a class="idx-item" href="ease-out.html" data-name="Ease.out" data-tip="Decelerate to rest (quadratic ease-out)."><code>Ease.out</code><span>Decelerate to rest (quadratic ease-out).</span></a><a class="idx-item" href="ease-in_out.html" data-name="Ease.in_out" data-tip="Ease in and then out (smoothstep)."><code>Ease.in_out</code><span>Ease in and then out (smoothstep).</span></a><a class="idx-item" href="ease-back.html" data-name="Ease.back" data-tip="Ease in with a small backward anticipation."><code>Ease.back</code><span>Ease in with a small backward anticipation.</span></a><a class="idx-item" href="ease-bounce.html" data-name="Ease.bounce" data-tip="Ease out with a settling bounce."><code>Ease.bounce</code><span>Ease out with a settling bounce.</span></a><a class="idx-item" href="ease-elastic.html" data-name="Ease.elastic" data-tip="Ease out with a springy wobble."><code>Ease.elastic</code><span>Ease out with a springy wobble.</span></a></div></section><section class="idx-sec" data-sec="fs"><h2 id="fs">Fs</h2><p class="sec-blurb">The filesystem, wrapped into one safe, ergonomic API — no file descriptors, no byte buffers, no half-written files. The foundation for saves, config, mods, and asset loading: read and write whole files as text, check existence, make directories, copy, and list a folder. The bare <code>file_*</code> builtins remain underneath for streaming; <code>Fs.*</code> is the everyday layer.
Fallible calls surface failure as a value — <code>null</code>, <code>false</code>, or <code>-1</code> — that you branch on, never a crash (a first-class <code>try/else</code> lands with the error-handling work). Writes are atomic (written to a temporary file and renamed into place), so a crash mid-write never corrupts the previous file. <a href="fs-list"><code>list</code></a> returns entries sorted, so a directory walk is reproducible across runs and platforms.
Paths are <code>/</code>-separated over the native (macOS/BSD) filesystem — the fully supported target today; a sandboxed virtual filesystem for wasm and recursive directory copy are follow-ups. Text helpers are UTF-8 (they pair with <a href="ns-Unicode"><code>Unicode</code></a>); use <a href="ns-Path"><code>Path</code></a> to build the paths and <a href="ns-Os"><code>Os</code></a> for per-user locations.</p><div class="idx-grid"><a class="idx-item" href="fs-exists.html" data-name="Fs.exists" data-tip="Does a path exist?"><code>Fs.exists</code><span>Does a path exist?</span></a><a class="idx-item" href="fs-is_dir.html" data-name="Fs.is_dir" data-tip="Is a path a directory?"><code>Fs.is_dir</code><span>Is a path a directory?</span></a><a class="idx-item" href="fs-read_text.html" data-name="Fs.read_text" data-tip="Read a whole file as a string."><code>Fs.read_text</code><span>Read a whole file as a string.</span></a><a class="idx-item" href="fs-write_text.html" data-name="Fs.write_text" data-tip="Write a string to a file (atomically)."><code>Fs.write_text</code><span>Write a string to a file (atomically).</span></a><a class="idx-item" href="fs-append_text.html" data-name="Fs.append_text" data-tip="Append a string to a file."><code>Fs.append_text</code><span>Append a string to a file.</span></a><a class="idx-item" href="fs-remove.html" data-name="Fs.remove" data-tip="Delete a file."><code>Fs.remove</code><span>Delete a file.</span></a><a class="idx-item" href="fs-size.html" data-name="Fs.size" data-tip="File size in bytes."><code>Fs.size</code><span>File size in bytes.</span></a><a class="idx-item" href="fs-mkdir.html" data-name="Fs.mkdir" data-tip="Create a directory and its parents."><code>Fs.mkdir</code><span>Create a directory and its parents.</span></a><a class="idx-item" href="fs-copy.html" data-name="Fs.copy" data-tip="Copy a file byte-for-byte."><code>Fs.copy</code><span>Copy a file byte-for-byte.</span></a><a class="idx-item" href="fs-list.html" data-name="Fs.list" data-tip="Directory entries, sorted."><code>Fs.list</code><span>Directory entries, sorted.</span></a></div></section><section class="idx-sec" data-sec="hash"><h2 id="hash">Hash</h2><p class="sec-blurb">Fast, non-cryptographic hashing for everyday game needs: turning string IDs into integer handles, mixing a few numbers into one deterministic seed, and checksumming data to catch corruption. Every function is plain 32-bit integer arithmetic with a defined byte order and fixed constants, so a given input hashes to exactly the same value on every platform and every run — the guarantee that makes it safe for procedural generation and lockstep networking. Results are 32-bit and print as signed integers. Arguments are positional.
Not for security. These hashes are fast and reversible — never use them for passwords, tokens, or tamper-proofing. For secure hashing reach for the cryptography library instead.</p><div class="idx-grid"><a class="idx-item" href="hash-of.html" data-name="Hash.of" data-tip="The fast default string hash."><code>Hash.of</code><span>The fast default string hash.</span></a><a class="idx-item" href="hash-fnv1a.html" data-name="Hash.fnv1a" data-tip="FNV-1a 32-bit, named explicitly."><code>Hash.fnv1a</code><span>FNV-1a 32-bit, named explicitly.</span></a><a class="idx-item" href="hash-crc32.html" data-name="Hash.crc32" data-tip="CRC-32 checksum for corruption detection."><code>Hash.crc32</code><span>CRC-32 checksum for corruption detection.</span></a><a class="idx-item" href="hash-mix.html" data-name="Hash.mix" data-tip="Avalanche one integer into a well-scrambled value."><code>Hash.mix</code><span>Avalanche one integer into a well-scrambled value.</span></a><a class="idx-item" href="hash-combine.html" data-name="Hash.combine" data-tip="Fold several ints into one deterministic seed."><code>Hash.combine</code><span>Fold several ints into one deterministic seed.</span></a><a class="idx-item" href="hash-of64.html" data-name="Hash.of64" data-tip="The fast default 64-bit string hash."><code>Hash.of64</code><span>The fast default 64-bit string hash.</span></a><a class="idx-item" href="hash-fnv1a_64.html" data-name="Hash.fnv1a_64" data-tip="FNV-1a 64-bit, named explicitly."><code>Hash.fnv1a_64</code><span>FNV-1a 64-bit, named explicitly.</span></a><a class="idx-item" href="hash-mix64.html" data-name="Hash.mix64" data-tip="Avalanche one 64-bit integer into a well-scrambled value."><code>Hash.mix64</code><span>Avalanche one 64-bit integer into a well-scrambled value.</span></a></div></section><section class="idx-sec" data-sec="input"><h2 id="input">Input</h2><p class="sec-blurb">Reading input. At the base, <a href="input-key.html"><code>Input.key</code></a> gives this frame's key and <a href="input-poll.html"><code>Input.poll</code></a> is the single per-frame read that also drives deterministic record/replay. Over that sit <strong>named actions</strong> — <a href="input-bind.html"><code>Input.bind</code></a> / <a href="input-down.html"><code>Input.down</code></a> / <a href="input-pressed.html"><code>Input.pressed</code></a> / <a href="input-rebind.html"><code>Input.rebind</code></a> — so gameplay reads rebindable actions, not physical keys.
The <strong>device layer</strong> adds everything past one key per frame: multiple simultaneous held keys (<a href="input-key_down.html"><code>Input.key_down</code></a> / <a href="input-key_pressed.html"><code>key_pressed</code></a> / <a href="input-key_released.html"><code>key_released</code></a>), analog <a href="input-axis.html"><code>Input.axis</code></a> and normalized <a href="input-vector.html"><code>Input.vector</code></a>, the <a href="input-mouse_x.html">mouse</a> (position, delta, buttons, <a href="input-wheel.html">wheel</a>), <a href="input-pad_button.html">gamepads</a> and <a href="input-touch_count.html">touch</a>. The held set is fed by the platform when windowed and by the <a href="input-press.html"><code>Input.press</code></a> / <a href="input-set_mouse.html"><code>Input.set_*</code></a> injection on every target — the same idea as Godot's <code>action_press</code>, and what a replay, an AI, or the network feeds. Everything is integer and deterministic, and record/replay snapshots the whole per-frame state.</p><div class="idx-grid"><a class="idx-item" href="input-key.html" data-name="Input.key" data-tip="The key pressed this frame as a character code (0 when nothing is pressed)."><code>Input.key</code><span>The key pressed this frame as a character code (0 when nothing is pressed).</span></a><a class="idx-item" href="input-bind.html" data-name="Input.bind" data-tip="Bind a physical key to a named action, so gameplay reads the action, not the key."><code>Input.bind</code><span>Bind a physical key to a named action, so gameplay reads the action, not the key.</span></a><a class="idx-item" href="input-rebind.html" data-name="Input.rebind" data-tip="Remap an action from one key to another at runtime (rebinding menus)."><code>Input.rebind</code><span>Remap an action from one key to another at runtime (rebinding menus).</span></a><a class="idx-item" href="input-poll.html" data-name="Input.poll" data-tip="Advance one frame of input; the single per-frame read behind actions and replay."><code>Input.poll</code><span>Advance one frame of input; the single per-frame read behind actions and replay.</span></a><a class="idx-item" href="input-down.html" data-name="Input.down" data-tip="Is a named action held on the frame last polled?"><code>Input.down</code><span>Is a named action held on the frame last polled?</span></a><a class="idx-item" href="input-pressed.html" data-name="Input.pressed" data-tip="Did a named action go down this frame (a one-shot edge)?"><code>Input.pressed</code><span>Did a named action go down this frame (a one-shot edge)?</span></a><a class="idx-item" href="input-record.html" data-name="Input.record" data-tip="Start recording polled input each frame (for deterministic replay)."><code>Input.record</code><span>Start recording polled input each frame (for deterministic replay).</span></a><a class="idx-item" href="input-replay.html" data-name="Input.replay" data-tip="Replay recorded input; poll then reads the tape, not the device."><code>Input.replay</code><span>Replay recorded input; poll then reads the tape, not the device.</span></a><a class="idx-item" href="input-key_down.html" data-name="Input.key_down" data-tip="Is a physical key held this frame?"><code>Input.key_down</code><span>Is a physical key held this frame?</span></a><a class="idx-item" href="input-key_pressed.html" data-name="Input.key_pressed" data-tip="Did a key go down this frame (edge)?"><code>Input.key_pressed</code><span>Did a key go down this frame (edge)?</span></a><a class="idx-item" href="input-key_released.html" data-name="Input.key_released" data-tip="Did a key go up this frame (edge)?"><code>Input.key_released</code><span>Did a key go up this frame (edge)?</span></a><a class="idx-item" href="input-key_label.html" data-name="Input.key_label" data-tip="The name to show a player for a key - in their own keyboard layout."><code>Input.key_label</code><span>The name to show a player for a key - in their own keyboard layout.</span></a><a class="idx-item" href="input-press.html" data-name="Input.press" data-tip="Inject a held key (AI, tutorial, testing, network)."><code>Input.press</code><span>Inject a held key (AI, tutorial, testing, network).</span></a><a class="idx-item" href="input-release.html" data-name="Input.release" data-tip="Release an injected key."><code>Input.release</code><span>Release an injected key.</span></a><a class="idx-item" href="input-axis.html" data-name="Input.axis" data-tip="A -1..+1 axis from two keys."><code>Input.axis</code><span>A -1..+1 axis from two keys.</span></a><a class="idx-item" href="input-axis_i.html" data-name="Input.axis_i" data-tip="A -1/0/1 directional intent as a plain int, no bool-&gt;int glue."><code>Input.axis_i</code><span>A -1/0/1 directional intent as a plain int, no bool-&gt;int glue.</span></a><a class="idx-item" href="input-vector.html" data-name="Input.vector" data-tip="A normalized 2D vector from four keys."><code>Input.vector</code><span>A normalized 2D vector from four keys.</span></a><a class="idx-item" href="input-strength.html" data-name="Input.strength" data-tip="0..1 strength of a named action."><code>Input.strength</code><span>0..1 strength of a named action.</span></a><a class="idx-item" href="input-mouse_x.html" data-name="Input.mouse_x" data-tip="The mouse x position this frame."><code>Input.mouse_x</code><span>The mouse x position this frame.</span></a><a class="idx-item" href="input-mouse_y.html" data-name="Input.mouse_y" data-tip="The mouse y position this frame."><code>Input.mouse_y</code><span>The mouse y position this frame.</span></a><a class="idx-item" href="input-mouse_dx.html" data-name="Input.mouse_dx" data-tip="Mouse x movement since the last poll."><code>Input.mouse_dx</code><span>Mouse x movement since the last poll.</span></a><a class="idx-item" href="input-mouse_dy.html" data-name="Input.mouse_dy" data-tip="Mouse y movement since the last poll."><code>Input.mouse_dy</code><span>Mouse y movement since the last poll.</span></a><a class="idx-item" href="input-mouse_down.html" data-name="Input.mouse_down" data-tip="Is a mouse button held?"><code>Input.mouse_down</code><span>Is a mouse button held?</span></a><a class="idx-item" href="input-wheel.html" data-name="Input.wheel" data-tip="Scroll-wheel delta this frame."><code>Input.wheel</code><span>Scroll-wheel delta this frame.</span></a><a class="idx-item" href="input-set_mouse.html" data-name="Input.set_mouse" data-tip="Inject the mouse state (headless / AI / testing)."><code>Input.set_mouse</code><span>Inject the mouse state (headless / AI / testing).</span></a><a class="idx-item" href="input-pad_connected.html" data-name="Input.pad_connected" data-tip="Is a gamepad connected?"><code>Input.pad_connected</code><span>Is a gamepad connected?</span></a><a class="idx-item" href="input-pad_button.html" data-name="Input.pad_button" data-tip="Is a gamepad button held?"><code>Input.pad_button</code><span>Is a gamepad button held?</span></a><a class="idx-item" href="input-pad_axis.html" data-name="Input.pad_axis" data-tip="A gamepad analog axis, -1..+1."><code>Input.pad_axis</code><span>A gamepad analog axis, -1..+1.</span></a><a class="idx-item" href="input-set_pad.html" data-name="Input.set_pad" data-tip="Inject a gamepad&#x27;s whole state."><code>Input.set_pad</code><span>Inject a gamepad's whole state.</span></a><a class="idx-item" href="input-touch_count.html" data-name="Input.touch_count" data-tip="How many touch points are active?"><code>Input.touch_count</code><span>How many touch points are active?</span></a><a class="idx-item" href="input-touch_x.html" data-name="Input.touch_x" data-tip="The x of a touch point."><code>Input.touch_x</code><span>The x of a touch point.</span></a><a class="idx-item" href="input-touch_y.html" data-name="Input.touch_y" data-tip="The y of a touch point."><code>Input.touch_y</code><span>The y of a touch point.</span></a><a class="idx-item" href="input-set_touch.html" data-name="Input.set_touch" data-tip="Inject a touch point."><code>Input.set_touch</code><span>Inject a touch point.</span></a><a class="idx-item" href="input-action.html" data-name="Input.action" data-tip="Register a default key binding for an action (kept if already bound)."><code>Input.action</code><span>Register a default key binding for an action (kept if already bound).</span></a><a class="idx-item" href="input-bind_pad.html" data-name="Input.bind_pad" data-tip="Also fire a named action from a gamepad button (device-agnostic)."><code>Input.bind_pad</code><span>Also fire a named action from a gamepad button (device-agnostic).</span></a><a class="idx-item" href="input-active.html" data-name="Input.active" data-tip="Is a named action active right now (any bound key held, or pad button down)?"><code>Input.active</code><span>Is a named action active right now (any bound key held, or pad button down)?</span></a><a class="idx-item" href="input-just_pressed.html" data-name="Input.just_pressed" data-tip="Did a named action go active this frame (the deterministic on-press)?"><code>Input.just_pressed</code><span>Did a named action go active this frame (the deterministic on-press)?</span></a><a class="idx-item" href="input-just_released.html" data-name="Input.just_released" data-tip="Did a named action go inactive this frame (the on-release edge)?"><code>Input.just_released</code><span>Did a named action go inactive this frame (the on-release edge)?</span></a><a class="idx-item" href="input-cursor_mode.html" data-name="Input.cursor_mode" data-tip="Hide / lock / confine the OS mouse cursor to the window (windowed)."><code>Input.cursor_mode</code><span>Hide / lock / confine the OS mouse cursor to the window (windowed).</span></a><a class="idx-item" href="input-move_i.html" data-name="Input.move_i" data-tip="The standard top-down movement intent, -1/0/1 per axis."><code>Input.move_i</code><span>The standard top-down movement intent, -1/0/1 per axis.</span></a></div></section><section class="idx-sec" data-sec="list"><h2 id="list">List</h2><p class="sec-blurb">Operations over <code>[]T</code> slices — length, ends access, push/pop, swap, search, and in-place reverse. A slice is a shared growable buffer, so these mutate it in place and every holder sees the change. Arguments are positional.</p><div class="idx-grid"><a class="idx-item" href="list-len.html" data-name="List.len" data-tip="The number of elements in a slice."><code>List.len</code><span>The number of elements in a slice.</span></a><a class="idx-item" href="list-push.html" data-name="List.push" data-tip="Append an element to the end of a slice."><code>List.push</code><span>Append an element to the end of a slice.</span></a><a class="idx-item" href="list-clear.html" data-name="List.clear" data-tip="Remove all elements, keeping capacity."><code>List.clear</code><span>Remove all elements, keeping capacity.</span></a><a class="idx-item" href="list-first.html" data-name="List.first" data-tip="The first element of a slice."><code>List.first</code><span>The first element of a slice.</span></a><a class="idx-item" href="list-last.html" data-name="List.last" data-tip="The last element of a slice."><code>List.last</code><span>The last element of a slice.</span></a><a class="idx-item" href="list-pop.html" data-name="List.pop" data-tip="Remove and return the last element."><code>List.pop</code><span>Remove and return the last element.</span></a><a class="idx-item" href="list-swap.html" data-name="List.swap" data-tip="Exchange the elements at two indices."><code>List.swap</code><span>Exchange the elements at two indices.</span></a><a class="idx-item" href="list-contains.html" data-name="List.contains" data-tip="Whether a value appears in a slice."><code>List.contains</code><span>Whether a value appears in a slice.</span></a><a class="idx-item" href="list-index_of.html" data-name="List.index_of" data-tip="The index of a value in a slice, or -1 if absent."><code>List.index_of</code><span>The index of a value in a slice, or -1 if absent.</span></a><a class="idx-item" href="list-reverse.html" data-name="List.reverse" data-tip="Reverse the order of a slice in place."><code>List.reverse</code><span>Reverse the order of a slice in place.</span></a><a class="idx-item" href="list-insert.html" data-name="List.insert" data-tip="Insert an element at an index, shifting the rest up."><code>List.insert</code><span>Insert an element at an index, shifting the rest up.</span></a><a class="idx-item" href="list-remove_at.html" data-name="List.remove_at" data-tip="Remove the element at an index, shifting the rest down."><code>List.remove_at</code><span>Remove the element at an index, shifting the rest down.</span></a><a class="idx-item" href="list-remove.html" data-name="List.remove" data-tip="Remove the first element equal to a value."><code>List.remove</code><span>Remove the first element equal to a value.</span></a><a class="idx-item" href="list-sort.html" data-name="List.sort" data-tip="Sort a slice in ascending order, in place."><code>List.sort</code><span>Sort a slice in ascending order, in place.</span></a><a class="idx-item" href="list-sort_by.html" data-name="List.sort_by" data-tip="Sort a slice ascending by a key each element maps to."><code>List.sort_by</code><span>Sort a slice ascending by a key each element maps to.</span></a><a class="idx-item" href="list-sort_desc_by.html" data-name="List.sort_desc_by" data-tip="Sort a slice descending by a key each element maps to."><code>List.sort_desc_by</code><span>Sort a slice descending by a key each element maps to.</span></a><a class="idx-item" href="list-sort_with.html" data-name="List.sort_with" data-tip="Sort a slice with a full two-argument comparator."><code>List.sort_with</code><span>Sort a slice with a full two-argument comparator.</span></a><a class="idx-item" href="list-sample.html" data-name="List.sample" data-tip="Random picks from an int slice, distinct while it can."><code>List.sample</code><span>Random picks from an int slice, distinct while it can.</span></a></div></section><section class="idx-sec" data-sec="log"><h2 id="log">Log</h2><p class="sec-blurb">Levelled, structured logging — the default way to answer "what is my game doing?" and "why did that break?", and a real step up from scattering <code>print</code> calls through your code. Each message carries a level, from <a href="log-trace"><code>trace</code></a> (most verbose) through <a href="log-debug"><code>debug</code></a>, <a href="log-info"><code>info</code></a>, and <a href="log-warn"><code>warn</code></a> to <a href="log-error"><code>error</code></a>, and a runtime threshold set with <a href="log-set_level"><code>Log.set_level</code></a> decides which ones actually appear — so a development build can be chatty and a release build quiet, without touching the call sites.
Messages go to standard error, kept separate from a program's real stdout, tagged with their level. Beyond the message you can pass **structured fields** as trailing key/value pairs — <code>Log.warn("missing texture", "path", p, "id", n)</code> prints <code>[WARN] missing texture path=... id=...</code> — cheap to write and easy to grep. Numeric values (int, long) are formatted for you; the level tag is chosen at compile time, so a filtered-out level costs only a threshold comparison at runtime.
Logging never touches the simulation — it writes to stderr and returns — so it has no effect on gameplay determinism or replays. This first version ships the console (stderr) sink; a rotating-file sink and an in-engine overlay sink are planned follow-ups.</p><div class="idx-grid"><a class="idx-item" href="log-trace.html" data-name="Log.trace" data-tip="Log at the trace level (0) — the most verbose."><code>Log.trace</code><span>Log at the trace level (0) — the most verbose.</span></a><a class="idx-item" href="log-debug.html" data-name="Log.debug" data-tip="Log at the debug level (1) — development detail."><code>Log.debug</code><span>Log at the debug level (1) — development detail.</span></a><a class="idx-item" href="log-info.html" data-name="Log.info" data-tip="Log at the info level (2) — normal operation."><code>Log.info</code><span>Log at the info level (2) — normal operation.</span></a><a class="idx-item" href="log-warn.html" data-name="Log.warn" data-tip="Log at the warn level (3) — something looks wrong."><code>Log.warn</code><span>Log at the warn level (3) — something looks wrong.</span></a><a class="idx-item" href="log-error.html" data-name="Log.error" data-tip="Log at the error level (4) — a failure."><code>Log.error</code><span>Log at the error level (4) — a failure.</span></a><a class="idx-item" href="log-set_level.html" data-name="Log.set_level" data-tip="Show only messages at level n or above (0 = all)."><code>Log.set_level</code><span>Show only messages at level n or above (0 = all).</span></a><a class="idx-item" href="log-level.html" data-name="Log.level" data-tip="The current logging threshold."><code>Log.level</code><span>The current logging threshold.</span></a></div></section><section class="idx-sec" data-sec="math"><h2 id="math">Math</h2><p class="sec-blurb">Deterministic fixed-point math. Every function is computed in Q16.16 with plain integer arithmetic, so results are bit-identical on every platform and every run — the same guarantee the rest of the runtime gives. Arguments are positional.
Given a <code>float</code> or <code>double</code> argument, the same functions compute in that type instead (using the platform's math library) and return it — <code>floor</code>, <code>ceil</code> and <code>round</code> included, which return an <code>int</code> only for <code>fixed</code>. <code>sign</code> returns an <code>int</code> either way. <code>trunc</code> and <code>atan</code> exist only for floats.</p><div class="idx-grid"><a class="idx-item" href="math-min.html" data-name="Math.min" data-tip="The smaller of two values."><code>Math.min</code><span>The smaller of two values.</span></a><a class="idx-item" href="math-max.html" data-name="Math.max" data-tip="The larger of two values."><code>Math.max</code><span>The larger of two values.</span></a><a class="idx-item" href="math-abs.html" data-name="Math.abs" data-tip="The magnitude of a value, dropping its sign."><code>Math.abs</code><span>The magnitude of a value, dropping its sign.</span></a><a class="idx-item" href="math-clamp.html" data-name="Math.clamp" data-tip="Constrain a value to the range [lo, hi]."><code>Math.clamp</code><span>Constrain a value to the range [lo, hi].</span></a><a class="idx-item" href="math-sign.html" data-name="Math.sign" data-tip="The sign of a value as -1, 0, or 1."><code>Math.sign</code><span>The sign of a value as -1, 0, or 1.</span></a><a class="idx-item" href="math-floor.html" data-name="Math.floor" data-tip="Round a fixed value down to the nearest whole int."><code>Math.floor</code><span>Round a fixed value down to the nearest whole int.</span></a><a class="idx-item" href="math-ceil.html" data-name="Math.ceil" data-tip="Round a fixed value up to the nearest whole int."><code>Math.ceil</code><span>Round a fixed value up to the nearest whole int.</span></a><a class="idx-item" href="math-round.html" data-name="Math.round" data-tip="Round a fixed value to the nearest whole int."><code>Math.round</code><span>Round a fixed value to the nearest whole int.</span></a><a class="idx-item" href="math-lerp.html" data-name="Math.lerp" data-tip="Blend between two values by a 0..1 amount."><code>Math.lerp</code><span>Blend between two values by a 0..1 amount.</span></a><a class="idx-item" href="math-inverse_lerp.html" data-name="Math.inverse_lerp" data-tip="Find where a value sits between two endpoints as a 0..1 fraction."><code>Math.inverse_lerp</code><span>Find where a value sits between two endpoints as a 0..1 fraction.</span></a><a class="idx-item" href="math-remap.html" data-name="Math.remap" data-tip="Rescale a value from one range into another."><code>Math.remap</code><span>Rescale a value from one range into another.</span></a><a class="idx-item" href="math-sqrt.html" data-name="Math.sqrt" data-tip="The square root of a fixed value."><code>Math.sqrt</code><span>The square root of a fixed value.</span></a><a class="idx-item" href="math-sin.html" data-name="Math.sin" data-tip="Sine of an angle in radians."><code>Math.sin</code><span>Sine of an angle in radians.</span></a><a class="idx-item" href="math-cos.html" data-name="Math.cos" data-tip="Cosine of an angle in radians."><code>Math.cos</code><span>Cosine of an angle in radians.</span></a><a class="idx-item" href="math-tan.html" data-name="Math.tan" data-tip="Tangent of an angle in radians."><code>Math.tan</code><span>Tangent of an angle in radians.</span></a><a class="idx-item" href="math-hypot.html" data-name="Math.hypot" data-tip="Length of the vector (x, y)."><code>Math.hypot</code><span>Length of the vector (x, y).</span></a><a class="idx-item" href="math-dist.html" data-name="Math.dist" data-tip="Distance between two points."><code>Math.dist</code><span>Distance between two points.</span></a><a class="idx-item" href="math-dist2.html" data-name="Math.dist2" data-tip="Squared distance between two points."><code>Math.dist2</code><span>Squared distance between two points.</span></a><a class="idx-item" href="math-deg_to_rad.html" data-name="Math.deg_to_rad" data-tip="Convert degrees to radians."><code>Math.deg_to_rad</code><span>Convert degrees to radians.</span></a><a class="idx-item" href="math-rad_to_deg.html" data-name="Math.rad_to_deg" data-tip="Convert radians to degrees."><code>Math.rad_to_deg</code><span>Convert radians to degrees.</span></a><a class="idx-item" href="math-posmod.html" data-name="Math.posmod" data-tip="Modulo that is always non-negative."><code>Math.posmod</code><span>Modulo that is always non-negative.</span></a><a class="idx-item" href="math-wrap.html" data-name="Math.wrap" data-tip="Wrap a value into the range [lo, hi)."><code>Math.wrap</code><span>Wrap a value into the range [lo, hi).</span></a><a class="idx-item" href="math-ping_pong.html" data-name="Math.ping_pong" data-tip="Bounce a counter back and forth in [0, len]."><code>Math.ping_pong</code><span>Bounce a counter back and forth in [0, len].</span></a><a class="idx-item" href="math-snapped.html" data-name="Math.snapped" data-tip="Round a value to the nearest multiple of step."><code>Math.snapped</code><span>Round a value to the nearest multiple of step.</span></a><a class="idx-item" href="math-move_toward.html" data-name="Math.move_toward" data-tip="Step from one value toward another by at most delta."><code>Math.move_toward</code><span>Step from one value toward another by at most delta.</span></a><a class="idx-item" href="math-smoothstep.html" data-name="Math.smoothstep" data-tip="A smooth 0..1 ramp between two edges."><code>Math.smoothstep</code><span>A smooth 0..1 ramp between two edges.</span></a><a class="idx-item" href="math-atan2.html" data-name="Math.atan2" data-tip="The angle of the vector (x, y), in radians."><code>Math.atan2</code><span>The angle of the vector (x, y), in radians.</span></a><a class="idx-item" href="math-asin.html" data-name="Math.asin" data-tip="The arcsine of a value, in radians."><code>Math.asin</code><span>The arcsine of a value, in radians.</span></a><a class="idx-item" href="math-acos.html" data-name="Math.acos" data-tip="The arccosine of a value, in radians."><code>Math.acos</code><span>The arccosine of a value, in radians.</span></a><a class="idx-item" href="math-exp.html" data-name="Math.exp" data-tip="e raised to the power x."><code>Math.exp</code><span>e raised to the power x.</span></a><a class="idx-item" href="math-log.html" data-name="Math.log" data-tip="The natural logarithm of x."><code>Math.log</code><span>The natural logarithm of x.</span></a><a class="idx-item" href="math-pow.html" data-name="Math.pow" data-tip="base raised to a fixed exponent."><code>Math.pow</code><span>base raised to a fixed exponent.</span></a></div></section><section class="idx-sec" data-sec="memory"><h2 id="memory">Memory</h2><p class="sec-blurb">Raw memory — allocate byte and word buffers, copy and fill regions, and peek/poke individual bytes. The low-level escape hatch.</p><div class="idx-grid"><a class="idx-item" href="memory-bytes.html" data-name="Memory.bytes" data-tip="Allocate n bytes."><code>Memory.bytes</code><span>Allocate n bytes.</span></a><a class="idx-item" href="memory-words.html" data-name="Memory.words" data-tip="Allocate n 32-bit words."><code>Memory.words</code><span>Allocate n 32-bit words.</span></a><a class="idx-item" href="memory-copy.html" data-name="Memory.copy" data-tip="Copy n bytes between buffers."><code>Memory.copy</code><span>Copy n bytes between buffers.</span></a><a class="idx-item" href="memory-fill.html" data-name="Memory.fill" data-tip="Set n bytes to a value."><code>Memory.fill</code><span>Set n bytes to a value.</span></a><a class="idx-item" href="memory-peek.html" data-name="Memory.peek" data-tip="Read one byte."><code>Memory.peek</code><span>Read one byte.</span></a><a class="idx-item" href="memory-poke.html" data-name="Memory.poke" data-tip="Write one byte."><code>Memory.poke</code><span>Write one byte.</span></a></div></section><section class="idx-sec" data-sec="mime"><h2 id="mime">Mime</h2><p class="sec-blurb">Content-type detection for assets and downloads: map a filename to its MIME type, or refine the guess by peeking at a file's leading bytes. Useful for deciding how to load a dropped-in mod file, labelling an export, or picking a decoder.
<a href="mime-of"><code>of</code></a> is a pure lookup by extension; <a href="mime-sniff"><code>sniff</code></a> reads the first bytes and recognises a few well-known signatures (PNG, JPEG, GIF, PDF), falling back to the extension when nothing matches. The extension table is deliberately compact and documented; richer magic-byte coverage is a follow-up.</p><div class="idx-grid"><a class="idx-item" href="mime-of.html" data-name="Mime.of" data-tip="MIME type from a file extension."><code>Mime.of</code><span>MIME type from a file extension.</span></a><a class="idx-item" href="mime-sniff.html" data-name="Mime.sniff" data-tip="MIME type refined by magic bytes."><code>Mime.sniff</code><span>MIME type refined by magic bytes.</span></a></div></section><section class="idx-sec" data-sec="network"><h2 id="network">Network</h2><p class="sec-blurb">The low-level networking seam — send and poll datagrams, serialize and apply entity state, and read ownership and role. Multiplayer is normally a compile-time property of the ECS, not glue you thread by hand: mark fields <code>@Sync</code> and models <code>@Owned</code> and the compiler generates the replication. These <code>Network.*</code> primitives are what that sugar lowers to, for when you drive the transport yourself. Offline they collapse to single-player defaults.</p><div class="idx-grid"><a class="idx-item" href="network-send.html" data-name="Network.send" data-tip="Put a datagram on the wire."><code>Network.send</code><span>Put a datagram on the wire.</span></a><a class="idx-item" href="network-poll.html" data-name="Network.poll" data-tip="Read an inbound datagram."><code>Network.poll</code><span>Read an inbound datagram.</span></a><a class="idx-item" href="network-serialize.html" data-name="Network.serialize" data-tip="Serialize an entity&#x27;s synced state."><code>Network.serialize</code><span>Serialize an entity's synced state.</span></a><a class="idx-item" href="network-apply.html" data-name="Network.apply" data-tip="Apply serialized state to an entity."><code>Network.apply</code><span>Apply serialized state to an entity.</span></a><a class="idx-item" href="network-owner.html" data-name="Network.owner" data-tip="The peer that owns an entity."><code>Network.owner</code><span>The peer that owns an entity.</span></a><a class="idx-item" href="network-set_owner.html" data-name="Network.set_owner" data-tip="Assign ownership of an entity."><code>Network.set_owner</code><span>Assign ownership of an entity.</span></a><a class="idx-item" href="network-is_server.html" data-name="Network.is_server" data-tip="Is this peer the server?"><code>Network.is_server</code><span>Is this peer the server?</span></a><a class="idx-item" href="network-is_owner.html" data-name="Network.is_owner" data-tip="Does this peer own the entity?"><code>Network.is_owner</code><span>Does this peer own the entity?</span></a><a class="idx-item" href="network-local_id.html" data-name="Network.local_id" data-tip="This peer&#x27;s own id."><code>Network.local_id</code><span>This peer's own id.</span></a></div></section><section class="idx-sec" data-sec="noise"><h2 id="noise">Noise</h2><p class="sec-blurb">Procedural noise — the primitive that terrain, caves, biomes, textures, clouds, wind, and object placement are built on. Every generator is implemented in Q16.16 **fixed point** over an integer permutation hash seeded from an explicit seed, so a given seed reproduces the *exact* same field on every platform and every run: native, headless, and (later) wasm all agree bit-for-bit. That is a real edge over float-based engines, whose worlds can drift subtly across CPUs and break shared-seed multiplayer or replays.
Coordinates are <a href="type-fixed"><code>fixed</code></a> values. The integer part of a coordinate selects a lattice cell and the fraction interpolates within it, so you scale feature size by sampling at a fractional *frequency* (e.g. multiply coordinates by <code>1/64</code>). Outputs are <code>fixed</code> normalised to <code>[-1, 1]</code>; <a href="noise-unit"><code>Noise.unit</code></a> remaps that to <code>[0, 1]</code> when you want a height or a probability.
Pick a generator by feel: <a href="noise-value2"><code>value2</code></a> is cheap and blocky; <a href="noise-perlin2"><code>perlin2</code></a> is the classic gradient noise; <a href="noise-simplex2"><code>simplex2</code></a> is the organic default with fewer directional artifacts; <a href="noise-fbm2"><code>fbm2</code></a> stacks octaves of simplex for natural, detailed fields; and <a href="noise-cellular2"><code>cellular2</code></a> (Worley) gives Voronoi-cell structure for stone, cracks, and biome boundaries. Every sampler is a pure function of <code>(x, y, seed)</code> — no global state, no allocation — so it is safe to call across a whole worldgen pass or a per-pixel fill.
Seed worldgen from its own seed (or a dedicated <a href="ns-Random"><code>Random</code></a> stream), kept separate from gameplay RNG, so generating the world never desyncs the simulation.</p><div class="idx-grid"><a class="idx-item" href="noise-value2.html" data-name="Noise.value2" data-tip="2D value (lattice) noise, deterministic, in [-1, 1]."><code>Noise.value2</code><span>2D value (lattice) noise, deterministic, in [-1, 1].</span></a><a class="idx-item" href="noise-perlin2.html" data-name="Noise.perlin2" data-tip="2D Perlin gradient noise, deterministic, in [-1, 1]."><code>Noise.perlin2</code><span>2D Perlin gradient noise, deterministic, in [-1, 1].</span></a><a class="idx-item" href="noise-simplex2.html" data-name="Noise.simplex2" data-tip="2D simplex noise, the organic default, in [-1, 1]."><code>Noise.simplex2</code><span>2D simplex noise, the organic default, in [-1, 1].</span></a><a class="idx-item" href="noise-fbm2.html" data-name="Noise.fbm2" data-tip="Fractal Brownian motion — octaves of simplex, in [-1, 1]."><code>Noise.fbm2</code><span>Fractal Brownian motion — octaves of simplex, in [-1, 1].</span></a><a class="idx-item" href="noise-cellular2.html" data-name="Noise.cellular2" data-tip="Worley (cellular) F1 distance to the nearest cell point."><code>Noise.cellular2</code><span>Worley (cellular) F1 distance to the nearest cell point.</span></a><a class="idx-item" href="noise-cellular2_id.html" data-name="Noise.cellular2_id" data-tip="The id of the nearest Worley cell — stable per cell."><code>Noise.cellular2_id</code><span>The id of the nearest Worley cell — stable per cell.</span></a><a class="idx-item" href="noise-unit.html" data-name="Noise.unit" data-tip="Remap a [-1,1] noise sample to [0,1]."><code>Noise.unit</code><span>Remap a [-1,1] noise sample to [0,1].</span></a></div></section><section class="idx-sec" data-sec="os"><h2 id="os">Os</h2><p class="sec-blurb">The operating-system interface — the environment *around* the game rather than the game itself: the command line, environment variables, the standard streams, the process exit code, the host platform, and the per-user folders a game writes its saves, config, and cache into. It rounds the bare <a href="ns-System"><code>System</code></a> builtins (<code>arg</code>, <code>getenv</code>, <code>exit</code>) into one coherent, Go-flavored namespace.
It is deliberately small and game-scoped: there is no process spawning, no signals, and no user/permission APIs. Reach for it in launchers, asset pipelines, and dev tools — parsing launch flags like <code>--level 3</code>, reading config from the environment, or resolving where a save file belongs — far more than in the simulation itself.
**Determinism:** <a href="os-args"><code>args</code></a>, the <a href="os-env"><code>env</code></a> family, and <a href="os-platform"><code>platform</code></a>/<a href="os-arch"><code>arch</code></a> are non-deterministic host input. Read them once at startup to configure the game, and keep them out of the replayable simulation so a shared seed still reproduces.
**Platform coverage:** this first version targets the native macOS/BSD host — the fully supported target today. <a href="os-platform"><code>platform</code></a> is portable (the <code>uname</code> system name is available on every Unix); <a href="os-arch"><code>arch</code></a> and the known-folder layout (<a href="os-save_dir"><code>save_dir</code></a>/<a href="os-config_dir"><code>config_dir</code></a>/<a href="os-cache_dir"><code>cache_dir</code></a>) follow the macOS conventions. Linux/Windows/wasm folder resolution and a target-aware <code>arch</code> are documented follow-ups.</p><div class="idx-grid"><a class="idx-item" href="os-args.html" data-name="Os.args" data-tip="Every command-line argument, as a list."><code>Os.args</code><span>Every command-line argument, as a list.</span></a><a class="idx-item" href="os-arg_count.html" data-name="Os.arg_count" data-tip="How many command-line arguments there are."><code>Os.arg_count</code><span>How many command-line arguments there are.</span></a><a class="idx-item" href="os-arg.html" data-name="Os.arg" data-tip="The i-th command-line argument."><code>Os.arg</code><span>The i-th command-line argument.</span></a><a class="idx-item" href="os-env.html" data-name="Os.env" data-tip="Read an environment variable (null if unset)."><code>Os.env</code><span>Read an environment variable (null if unset).</span></a><a class="idx-item" href="os-env_or.html" data-name="Os.env_or" data-tip="Read an environment variable, or a fallback."><code>Os.env_or</code><span>Read an environment variable, or a fallback.</span></a><a class="idx-item" href="os-has_env.html" data-name="Os.has_env" data-tip="Is an environment variable set?"><code>Os.has_env</code><span>Is an environment variable set?</span></a><a class="idx-item" href="os-set_env.html" data-name="Os.set_env" data-tip="Set an environment variable."><code>Os.set_env</code><span>Set an environment variable.</span></a><a class="idx-item" href="os-unset_env.html" data-name="Os.unset_env" data-tip="Remove an environment variable."><code>Os.unset_env</code><span>Remove an environment variable.</span></a><a class="idx-item" href="os-exit.html" data-name="Os.exit" data-tip="Terminate the process with a status code."><code>Os.exit</code><span>Terminate the process with a status code.</span></a><a class="idx-item" href="os-platform.html" data-name="Os.platform" data-tip="The host platform id."><code>Os.platform</code><span>The host platform id.</span></a><a class="idx-item" href="os-arch.html" data-name="Os.arch" data-tip="The host CPU architecture."><code>Os.arch</code><span>The host CPU architecture.</span></a><a class="idx-item" href="os-stdout_write.html" data-name="Os.stdout_write" data-tip="Write a string to standard output."><code>Os.stdout_write</code><span>Write a string to standard output.</span></a><a class="idx-item" href="os-stderr_write.html" data-name="Os.stderr_write" data-tip="Write a string to standard error."><code>Os.stderr_write</code><span>Write a string to standard error.</span></a><a class="idx-item" href="os-save_dir.html" data-name="Os.save_dir" data-tip="Per-user save directory for an app."><code>Os.save_dir</code><span>Per-user save directory for an app.</span></a><a class="idx-item" href="os-config_dir.html" data-name="Os.config_dir" data-tip="Per-user config directory for an app."><code>Os.config_dir</code><span>Per-user config directory for an app.</span></a><a class="idx-item" href="os-cache_dir.html" data-name="Os.cache_dir" data-tip="Per-user cache directory for an app."><code>Os.cache_dir</code><span>Per-user cache directory for an app.</span></a><a class="idx-item" href="os-temp_dir.html" data-name="Os.temp_dir" data-tip="The system temporary directory."><code>Os.temp_dir</code><span>The system temporary directory.</span></a><a class="idx-item" href="os-pid.html" data-name="Os.pid" data-tip="This process&#x27;s id."><code>Os.pid</code><span>This process's id.</span></a></div></section><section class="idx-sec" data-sec="path"><h2 id="path">Path</h2><p class="sec-blurb">Path manipulation as pure string operations — no disk access, no allocation surprises, just the joining and splitting every save system, mod loader, and asset pipeline needs. Separate a filename from its folder, get an extension, join segments without worrying about doubled or missing separators, and collapse <code>.</code>/<code>..</code>/duplicate slashes into a canonical form.
Paths use <code>/</code> as the separator, matching the native (macOS/BSD) filesystem — the fully supported target today; Windows-style separators are a follow-up. Pair these with <a href="ns-Os"><code>Os</code></a> (which supplies per-user directory *locations*) and <a href="ns-Fs"><code>Fs</code></a> (which does the actual reading and writing).</p><div class="idx-grid"><a class="idx-item" href="path-join.html" data-name="Path.join" data-tip="Join two path segments with the separator."><code>Path.join</code><span>Join two path segments with the separator.</span></a><a class="idx-item" href="path-dir.html" data-name="Path.dir" data-tip="The directory part of a path."><code>Path.dir</code><span>The directory part of a path.</span></a><a class="idx-item" href="path-base.html" data-name="Path.base" data-tip="The final component of a path."><code>Path.base</code><span>The final component of a path.</span></a><a class="idx-item" href="path-ext.html" data-name="Path.ext" data-tip="The file extension, including the dot."><code>Path.ext</code><span>The file extension, including the dot.</span></a><a class="idx-item" href="path-stem.html" data-name="Path.stem" data-tip="The final component without its extension."><code>Path.stem</code><span>The final component without its extension.</span></a><a class="idx-item" href="path-normalize.html" data-name="Path.normalize" data-tip="Collapse . / .. / duplicate separators."><code>Path.normalize</code><span>Collapse . / .. / duplicate separators.</span></a></div></section><section class="idx-sec" data-sec="save"><h2 id="save">Save</h2><p class="sec-blurb">Whole-world save and restore — write a binary snapshot of the ECS world and read it back.</p><div class="idx-grid"><a class="idx-item" href="save-write.html" data-name="Save.write" data-tip="Save a snapshot of the world."><code>Save.write</code><span>Save a snapshot of the world.</span></a><a class="idx-item" href="save-read.html" data-name="Save.read" data-tip="Restore the saved snapshot."><code>Save.read</code><span>Restore the saved snapshot.</span></a></div></section><section class="idx-sec" data-sec="system"><h2 id="system">System</h2><p class="sec-blurb">Low-level file and process access — raw file handles, reading a character, and running a shell command. Outside the deterministic simulation. For command-line arguments, environment variables, the exit code, and the standard streams, use the <code>Os</code> namespace.</p><div class="idx-grid"><a class="idx-item" href="system-run.html" data-name="System.run" data-tip="Run a shell command."><code>System.run</code><span>Run a shell command.</span></a><a class="idx-item" href="system-read_char.html" data-name="System.read_char" data-tip="Read one byte from standard input."><code>System.read_char</code><span>Read one byte from standard input.</span></a><a class="idx-item" href="system-file_open.html" data-name="System.file_open" data-tip="Open a file."><code>System.file_open</code><span>Open a file.</span></a><a class="idx-item" href="system-file_read.html" data-name="System.file_read" data-tip="Read bytes from a file."><code>System.file_read</code><span>Read bytes from a file.</span></a><a class="idx-item" href="system-file_write.html" data-name="System.file_write" data-tip="Write bytes to a file."><code>System.file_write</code><span>Write bytes to a file.</span></a><a class="idx-item" href="system-file_seek.html" data-name="System.file_seek" data-tip="Move a file&#x27;s read/write position."><code>System.file_seek</code><span>Move a file's read/write position.</span></a><a class="idx-item" href="system-file_tell.html" data-name="System.file_tell" data-tip="The current file position."><code>System.file_tell</code><span>The current file position.</span></a><a class="idx-item" href="system-file_close.html" data-name="System.file_close" data-tip="Close a file."><code>System.file_close</code><span>Close a file.</span></a></div></section><section class="idx-sec" data-sec="text"><h2 id="text">Text</h2><p class="sec-blurb">String queries and building over <code>string</code> values — length, character access, substrings, search, prefix/suffix tests, and int conversion. Arguments are positional. Strings are byte sequences, so indices and lengths count bytes.</p><div class="idx-grid"><a class="idx-item" href="text-length.html" data-name="Text.length" data-tip="The number of bytes in a string."><code>Text.length</code><span>The number of bytes in a string.</span></a><a class="idx-item" href="text-char_at.html" data-name="Text.char_at" data-tip="The byte value at an index, 0..255."><code>Text.char_at</code><span>The byte value at an index, 0..255.</span></a><a class="idx-item" href="text-slice.html" data-name="Text.slice" data-tip="A substring covering bytes [a, b)."><code>Text.slice</code><span>A substring covering bytes [a, b).</span></a><a class="idx-item" href="text-starts_with.html" data-name="Text.starts_with" data-tip="Whether a string begins with a given prefix."><code>Text.starts_with</code><span>Whether a string begins with a given prefix.</span></a><a class="idx-item" href="text-ends_with.html" data-name="Text.ends_with" data-tip="Whether a string ends with a given suffix."><code>Text.ends_with</code><span>Whether a string ends with a given suffix.</span></a><a class="idx-item" href="text-contains.html" data-name="Text.contains" data-tip="Whether a substring appears anywhere in a string."><code>Text.contains</code><span>Whether a substring appears anywhere in a string.</span></a><a class="idx-item" href="text-index_of.html" data-name="Text.index_of" data-tip="The byte index of a substring, or -1 if absent."><code>Text.index_of</code><span>The byte index of a substring, or -1 if absent.</span></a><a class="idx-item" href="text-equals.html" data-name="Text.equals" data-tip="Whether two strings have identical bytes."><code>Text.equals</code><span>Whether two strings have identical bytes.</span></a><a class="idx-item" href="text-concat.html" data-name="Text.concat" data-tip="Join two strings into a new one."><code>Text.concat</code><span>Join two strings into a new one.</span></a><a class="idx-item" href="text-to_int.html" data-name="Text.to_int" data-tip="Parse a leading integer from a string."><code>Text.to_int</code><span>Parse a leading integer from a string.</span></a><a class="idx-item" href="text-from_int.html" data-name="Text.from_int" data-tip="Render an integer as a string."><code>Text.from_int</code><span>Render an integer as a string.</span></a><a class="idx-item" href="text-upper.html" data-name="Text.upper" data-tip="An uppercased copy of a string."><code>Text.upper</code><span>An uppercased copy of a string.</span></a><a class="idx-item" href="text-lower.html" data-name="Text.lower" data-tip="A lowercased copy of a string."><code>Text.lower</code><span>A lowercased copy of a string.</span></a><a class="idx-item" href="text-trim.html" data-name="Text.trim" data-tip="A copy with surrounding whitespace removed."><code>Text.trim</code><span>A copy with surrounding whitespace removed.</span></a><a class="idx-item" href="text-repeat.html" data-name="Text.repeat" data-tip="A string repeated n times."><code>Text.repeat</code><span>A string repeated n times.</span></a><a class="idx-item" href="text-pad_left.html" data-name="Text.pad_left" data-tip="Pad with spaces on the left to a width."><code>Text.pad_left</code><span>Pad with spaces on the left to a width.</span></a><a class="idx-item" href="text-pad_right.html" data-name="Text.pad_right" data-tip="Pad with spaces on the right to a width."><code>Text.pad_right</code><span>Pad with spaces on the right to a width.</span></a><a class="idx-item" href="text-split.html" data-name="Text.split" data-tip="Split a string on a separator into a list."><code>Text.split</code><span>Split a string on a separator into a list.</span></a><a class="idx-item" href="text-join.html" data-name="Text.join" data-tip="Join a list of strings with a separator."><code>Text.join</code><span>Join a list of strings with a separator.</span></a><a class="idx-item" href="text-replace.html" data-name="Text.replace" data-tip="Replace every occurrence of a substring."><code>Text.replace</code><span>Replace every occurrence of a substring.</span></a></div></section><section class="idx-sec" data-sec="time"><h2 id="time">Time</h2><p class="sec-blurb">The frame clock. <code>frame</code>/<code>elapsed</code>/<code>delta</code> are deterministic (driven by a per-frame counter at a fixed 60 fps), so a replay reproduces every value; <code>now</code> is the wall clock and is explicitly non-deterministic.</p><div class="idx-grid"><a class="idx-item" href="time-frame.html" data-name="Time.frame" data-tip="The number of frames elapsed since start."><code>Time.frame</code><span>The number of frames elapsed since start.</span></a><a class="idx-item" href="time-delta.html" data-name="Time.delta" data-tip="Seconds per frame (a fixed 1/60)."><code>Time.delta</code><span>Seconds per frame (a fixed 1/60).</span></a><a class="idx-item" href="time-elapsed.html" data-name="Time.elapsed" data-tip="Seconds since start (deterministic)."><code>Time.elapsed</code><span>Seconds since start (deterministic).</span></a><a class="idx-item" href="time-now.html" data-name="Time.now" data-tip="Wall-clock seconds (non-deterministic)."><code>Time.now</code><span>Wall-clock seconds (non-deterministic).</span></a><a class="idx-item" href="time-since.html" data-name="Time.since" data-tip="Seconds elapsed from a past instant to now (non-deterministic)."><code>Time.since</code><span>Seconds elapsed from a past instant to now (non-deterministic).</span></a></div></section><section class="idx-sec" data-sec="unicode"><h2 id="unicode">Unicode</h2><p class="sec-blurb">Correct-by-default text over UTF-8. Player names, translated menus, and chat arrive as UTF-8 bytes, and counting *bytes* gets non-ASCII text wrong — the wrong length, and truncation that slices a character in half into mojibake. The <a href="ns-Unicode"><code>Unicode</code></a> namespace works in <strong>code points</strong> and (approximately) <strong>grapheme clusters</strong> instead, so measuring, indexing, truncating, and case-mapping behave for every language.
This is the correctness layer, not a replacement: the byte-oriented <a href="ns-Text"><code>Text</code></a> operations stay for speed on ASCII and for raw byte work. Reach for <code>Unicode.*</code> whenever the text came from a human — a name, a message, a localized string.
Three notions of "length" matter, and the API keeps them distinct: <a href="unicode-byte_len"><code>byte_len</code></a> (storage), <a href="unicode-len"><code>len</code></a> (code points — Unicode scalar values), and <a href="unicode-grapheme_len"><code>grapheme_len</code></a> (user-perceived characters, where a base letter plus its combining accent, or a ZWJ emoji sequence, count as one).
**Coverage (v1):** decoding and <a href="unicode-is_valid_utf8"><code>validation</code></a> cover the full UTF-8 range. Case mapping covers ASCII and the Latin-1 letters — correct for Western-European text; wider scripts (Latin-Extended, Greek, Cyrillic), locale rules (Turkish <code>i</code>, German <code>ß</code>), and NFC normalization are follow-ups. <a href="unicode-grapheme_len"><code>grapheme_len</code></a> approximates UAX#29 for the cases real player text hits — combining marks, variation selectors, ZWJ sequences, and flag pairs.</p><div class="idx-grid"><a class="idx-item" href="unicode-len.html" data-name="Unicode.len" data-tip="Number of code points in a string (not bytes)."><code>Unicode.len</code><span>Number of code points in a string (not bytes).</span></a><a class="idx-item" href="unicode-byte_len.html" data-name="Unicode.byte_len" data-tip="Number of bytes in a string."><code>Unicode.byte_len</code><span>Number of bytes in a string.</span></a><a class="idx-item" href="unicode-is_valid_utf8.html" data-name="Unicode.is_valid_utf8" data-tip="Is a string well-formed UTF-8?"><code>Unicode.is_valid_utf8</code><span>Is a string well-formed UTF-8?</span></a><a class="idx-item" href="unicode-char_at.html" data-name="Unicode.char_at" data-tip="The i-th code point of a string."><code>Unicode.char_at</code><span>The i-th code point of a string.</span></a><a class="idx-item" href="unicode-chars.html" data-name="Unicode.chars" data-tip="Every code point of a string, in order."><code>Unicode.chars</code><span>Every code point of a string, in order.</span></a><a class="idx-item" href="unicode-upper.html" data-name="Unicode.upper" data-tip="Uppercase a string."><code>Unicode.upper</code><span>Uppercase a string.</span></a><a class="idx-item" href="unicode-lower.html" data-name="Unicode.lower" data-tip="Lowercase a string."><code>Unicode.lower</code><span>Lowercase a string.</span></a><a class="idx-item" href="unicode-truncate.html" data-name="Unicode.truncate" data-tip="First n code points of a string."><code>Unicode.truncate</code><span>First n code points of a string.</span></a><a class="idx-item" href="unicode-grapheme_len.html" data-name="Unicode.grapheme_len" data-tip="Number of user-perceived characters."><code>Unicode.grapheme_len</code><span>Number of user-perceived characters.</span></a></div></section><section class="idx-sec" data-sec="uuid"><h2 id="uuid">Uuid</h2><p class="sec-blurb">Universally-unique identifiers — stable IDs that don't collide, generated locally with no central authority handing out numbers. Reach for a UUID whenever something needs an identity that survives being saved, shared, or sent over a network: players and sessions in multiplayer, user-created content (levels, items, mods) that has to merge cleanly across installs, or a per-install / per-run ID for analytics and bug reports.
Two versions are provided. <a href="uuid-new"><code>Uuid.new</code></a> makes a **v4** (random) UUID — 122 bits of entropy, effectively never colliding. <a href="uuid-new_v7"><code>Uuid.new_v7</code></a> makes a **v7** (time-ordered) UUID whose leading bits are a millisecond timestamp, so a batch of v7 IDs sorts by creation time — friendly to database indexes and append logs. Both set the RFC 4122 version and variant bits correctly.
A UUID is represented as its canonical lowercase 36-character text form (<code>8-4-4-4-12</code>), the same shape you store, print, send, and compare — so there is no conversion at each boundary. Validate untrusted input with <a href="uuid-is_valid"><code>Uuid.is_valid</code></a> or normalise it with <a href="uuid-parse"><code>Uuid.parse</code></a>, and compare with <a href="uuid-equals"><code>Uuid.equals</code></a>, which ignores case.
**Determinism caveat.** v4 and the random tail of v7 come from the OS cryptographically-secure RNG (<a href="ns-Crypto"><code>Crypto</code></a>), which is non-deterministic by design. Minting a UUID inside the lockstep simulation will desync replays and networked peers — generate IDs at the edges (on connect, on save, on spawn-from-input), never per tick in reproducible gameplay code.</p><div class="idx-grid"><a class="idx-item" href="uuid-new.html" data-name="Uuid.new" data-tip="A new random (v4) UUID as a canonical 36-char string."><code>Uuid.new</code><span>A new random (v4) UUID as a canonical 36-char string.</span></a><a class="idx-item" href="uuid-v4.html" data-name="Uuid.v4" data-tip="Explicit alias for Uuid.new — a random (v4) UUID."><code>Uuid.v4</code><span>Explicit alias for Uuid.new — a random (v4) UUID.</span></a><a class="idx-item" href="uuid-new_v7.html" data-name="Uuid.new_v7" data-tip="A new time-ordered (v7) UUID; sorts by creation time."><code>Uuid.new_v7</code><span>A new time-ordered (v7) UUID; sorts by creation time.</span></a><a class="idx-item" href="uuid-v7.html" data-name="Uuid.v7" data-tip="Explicit alias for Uuid.new_v7 — a time-ordered UUID."><code>Uuid.v7</code><span>Explicit alias for Uuid.new_v7 — a time-ordered UUID.</span></a><a class="idx-item" href="uuid-parse.html" data-name="Uuid.parse" data-tip="Normalise an untrusted string to a lowercase UUID, or the nil UUID."><code>Uuid.parse</code><span>Normalise an untrusted string to a lowercase UUID, or the nil UUID.</span></a><a class="idx-item" href="uuid-is_valid.html" data-name="Uuid.is_valid" data-tip="Is s a well-formed UUID string?"><code>Uuid.is_valid</code><span>Is s a well-formed UUID string?</span></a><a class="idx-item" href="uuid-to_text.html" data-name="Uuid.to_text" data-tip="The canonical text form of a UUID."><code>Uuid.to_text</code><span>The canonical text form of a UUID.</span></a><a class="idx-item" href="uuid-equals.html" data-name="Uuid.equals" data-tip="Case-insensitive UUID equality."><code>Uuid.equals</code><span>Case-insensitive UUID equality.</span></a><a class="idx-item" href="uuid-nil.html" data-name="Uuid.nil" data-tip="The all-zero UUID."><code>Uuid.nil</code><span>The all-zero UUID.</span></a></div></section><section class="idx-sec" data-sec="world"><h2 id="world">World</h2><p class="sec-blurb">Runtime reflection over the ECS world — read and write component fields by id, spawn and inspect entities, and register components at runtime. The introspection layer a mod uses.</p><div class="idx-grid"><a class="idx-item" href="world-get.html" data-name="World.get" data-tip="Read a component field by id."><code>World.get</code><span>Read a component field by id.</span></a><a class="idx-item" href="world-set.html" data-name="World.set" data-tip="Write a component field by id."><code>World.set</code><span>Write a component field by id.</span></a><a class="idx-item" href="world-has.html" data-name="World.has" data-tip="Does an entity have a component?"><code>World.has</code><span>Does an entity have a component?</span></a><a class="idx-item" href="world-count.html" data-name="World.count" data-tip="The number of live entities."><code>World.count</code><span>The number of live entities.</span></a><a class="idx-item" href="world-size.html" data-name="World.size" data-tip="The serialized size of the world."><code>World.size</code><span>The serialized size of the world.</span></a><a class="idx-item" href="world-spawn.html" data-name="World.spawn" data-tip="Spawn an entity of a model by id."><code>World.spawn</code><span>Spawn an entity of a model by id.</span></a><a class="idx-item" href="world-save.html" data-name="World.save" data-tip="Serialize the world into a buffer."><code>World.save</code><span>Serialize the world into a buffer.</span></a><a class="idx-item" href="world-load.html" data-name="World.load" data-tip="Restore the world from a buffer."><code>World.load</code><span>Restore the world from a buffer.</span></a><a class="idx-item" href="world-prop_id.html" data-name="World.prop_id" data-tip="Look up a component&#x27;s id by name."><code>World.prop_id</code><span>Look up a component's id by name.</span></a><a class="idx-item" href="world-field_id.html" data-name="World.field_id" data-tip="Look up a field&#x27;s id by name."><code>World.field_id</code><span>Look up a field's id by name.</span></a><a class="idx-item" href="world-model_id.html" data-name="World.model_id" data-tip="Look up a model&#x27;s id by name."><code>World.model_id</code><span>Look up a model's id by name.</span></a><a class="idx-item" href="world-kind.html" data-name="World.kind" data-tip="The model id of an entity."><code>World.kind</code><span>The model id of an entity.</span></a><a class="idx-item" href="world-register_prop.html" data-name="World.register_prop" data-tip="Register a new component at runtime."><code>World.register_prop</code><span>Register a new component at runtime.</span></a><a class="idx-item" href="world-attach.html" data-name="World.attach" data-tip="Attach a component to an entity at runtime."><code>World.attach</code><span>Attach a component to an entity at runtime.</span></a><a class="idx-item" href="world-detach.html" data-name="World.detach" data-tip="Detach a component from an entity at runtime."><code>World.detach</code><span>Detach a component from an entity at runtime.</span></a><a class="idx-item" href="world-query_next.html" data-name="World.query_next" data-tip="Advance a reflective query."><code>World.query_next</code><span>Advance a reflective query.</span></a><a class="idx-item" href="world-despawn.html" data-name="World.despawn" data-tip="Despawn an entity by id — runs its @OnDespawn hooks and frees the slot."><code>World.despawn</code><span>Despawn an entity by id — runs its @OnDespawn hooks and frees the slot.</span></a></div></section><section class="idx-sec" data-sec="audio"><h2 id="audio">Audio</h2><p class="sec-blurb">Sound effects and music. A sound is loaded once with <a href="audio-load.html"><code>Audio.load</code></a> into a handle; <a href="audio-play.html"><code>Audio.play</code></a> fires it one-shot and <a href="audio-play_music.html"><code>Audio.play_music</code></a> loops it on a single music channel. Playback is <strong>out-of-band</strong> — the audio device is real-time, not part of the deterministic simulation — but every trigger here is an ordinary frame-driven call, so a recorded run replays the same sounds at the same frames. Headless builds carry the whole API as no-ops (no audio device needed), so the same game code runs under the test harness.</p><div class="idx-grid"><a class="idx-item" href="audio-load.html" data-name="Audio.load" data-tip="Load a sound file into a handle."><code>Audio.load</code><span>Load a sound file into a handle.</span></a><a class="idx-item" href="audio-play.html" data-name="Audio.play" data-tip="Fire a one-shot sound."><code>Audio.play</code><span>Fire a one-shot sound.</span></a><a class="idx-item" href="audio-play_at.html" data-name="Audio.play_at" data-tip="Fire a one-shot with its own gain, pitch and stereo position."><code>Audio.play_at</code><span>Fire a one-shot with its own gain, pitch and stereo position.</span></a><a class="idx-item" href="audio-play_sound.html" data-name="Audio.play_sound" data-tip="Fire a one-shot sound (alias of play)."><code>Audio.play_sound</code><span>Fire a one-shot sound (alias of play).</span></a><a class="idx-item" href="audio-play_music.html" data-name="Audio.play_music" data-tip="Loop a sound as background music."><code>Audio.play_music</code><span>Loop a sound as background music.</span></a><a class="idx-item" href="audio-stop.html" data-name="Audio.stop" data-tip="Stop one sound."><code>Audio.stop</code><span>Stop one sound.</span></a><a class="idx-item" href="audio-stop_music.html" data-name="Audio.stop_music" data-tip="Stop the music channel."><code>Audio.stop_music</code><span>Stop the music channel.</span></a><a class="idx-item" href="audio-stop_all.html" data-name="Audio.stop_all" data-tip="Stop every sound."><code>Audio.stop_all</code><span>Stop every sound.</span></a><a class="idx-item" href="audio-volume.html" data-name="Audio.volume" data-tip="Set the master volume."><code>Audio.volume</code><span>Set the master volume.</span></a><a class="idx-item" href="audio-pitch.html" data-name="Audio.pitch" data-tip="Set the playback rate / pitch."><code>Audio.pitch</code><span>Set the playback rate / pitch.</span></a><a class="idx-item" href="audio-is_playing.html" data-name="Audio.is_playing" data-tip="Is this sound playing?"><code>Audio.is_playing</code><span>Is this sound playing?</span></a><a class="idx-item" href="audio-define.html" data-name="Audio.define" data-tip="Load a sound into the bank under a name."><code>Audio.define</code><span>Load a sound into the bank under a name.</span></a><a class="idx-item" href="audio-named.html" data-name="Audio.named" data-tip="The handle registered under a name, or 0."><code>Audio.named</code><span>The handle registered under a name, or 0.</span></a></div></section><section class="idx-sec" data-sec="random"><h2 id="random">Random</h2><p class="sec-blurb">A seeded, deterministic RNG — same seed, same sequence, every run and every platform.</p><div class="idx-grid"><a class="idx-item" href="random-range.html" data-name="Random.range" data-tip="A random integer in the inclusive range [low, high]."><code>Random.range</code><span>A random integer in the inclusive range [low, high].</span></a><a class="idx-item" href="random-chance.html" data-name="Random.chance" data-tip="Return true with the given percent probability."><code>Random.chance</code><span>Return true with the given percent probability.</span></a><a class="idx-item" href="random-seed.html" data-name="Random.seed" data-tip="Seed the random generator so runs are reproducible."><code>Random.seed</code><span>Seed the random generator so runs are reproducible.</span></a><a class="idx-item" href="random-value.html" data-name="Random.value" data-tip="A random fixed value in [0, 1)."><code>Random.value</code><span>A random fixed value in [0, 1).</span></a><a class="idx-item" href="random-int.html" data-name="Random.int" data-tip="A random integer in [0, max)."><code>Random.int</code><span>A random integer in [0, max).</span></a><a class="idx-item" href="random-sign.html" data-name="Random.sign" data-tip="A random +1 or -1."><code>Random.sign</code><span>A random +1 or -1.</span></a><a class="idx-item" href="random-weighted.html" data-name="Random.weighted" data-tip="An index drawn in proportion to its weight."><code>Random.weighted</code><span>An index drawn in proportion to its weight.</span></a></div></section><section class="idx-sec" data-sec="vector"><h2 id="vector">Vector</h2><p class="sec-blurb">2D vector math for positions, velocities, and directions. A <code>Vector</code> is a pair of Q16.16 fixed components packed into one value, so it is copied by value and never allocates. Every operation is deterministic integer fixed-point — bit-identical on every platform, the same guarantee the rest of the runtime gives. Arguments are positional; angles are in radians.</p><div class="idx-grid"><a class="idx-item" href="vector-make.html" data-name="Vector.make" data-tip="Build a vector from x and y components."><code>Vector.make</code><span>Build a vector from x and y components.</span></a><a class="idx-item" href="vector-zero.html" data-name="Vector.zero" data-tip="The zero vector, (0, 0)."><code>Vector.zero</code><span>The zero vector, (0, 0).</span></a><a class="idx-item" href="vector-x.html" data-name="Vector.x" data-tip="The x component of a vector."><code>Vector.x</code><span>The x component of a vector.</span></a><a class="idx-item" href="vector-y.html" data-name="Vector.y" data-tip="The y component of a vector."><code>Vector.y</code><span>The y component of a vector.</span></a><a class="idx-item" href="vector-add.html" data-name="Vector.add" data-tip="Component-wise sum a + b."><code>Vector.add</code><span>Component-wise sum a + b.</span></a><a class="idx-item" href="vector-sub.html" data-name="Vector.sub" data-tip="Component-wise difference a - b."><code>Vector.sub</code><span>Component-wise difference a - b.</span></a><a class="idx-item" href="vector-scale.html" data-name="Vector.scale" data-tip="Scale a vector by a scalar."><code>Vector.scale</code><span>Scale a vector by a scalar.</span></a><a class="idx-item" href="vector-dot.html" data-name="Vector.dot" data-tip="The dot product of two vectors."><code>Vector.dot</code><span>The dot product of two vectors.</span></a><a class="idx-item" href="vector-length.html" data-name="Vector.length" data-tip="The length (magnitude) of a vector."><code>Vector.length</code><span>The length (magnitude) of a vector.</span></a><a class="idx-item" href="vector-distance.html" data-name="Vector.distance" data-tip="The distance between two points."><code>Vector.distance</code><span>The distance between two points.</span></a><a class="idx-item" href="vector-normalize.html" data-name="Vector.normalize" data-tip="A unit vector in the same direction."><code>Vector.normalize</code><span>A unit vector in the same direction.</span></a><a class="idx-item" href="vector-lerp.html" data-name="Vector.lerp" data-tip="Linear interpolation between two vectors."><code>Vector.lerp</code><span>Linear interpolation between two vectors.</span></a><a class="idx-item" href="vector-rotate.html" data-name="Vector.rotate" data-tip="Rotate a vector by an angle in radians."><code>Vector.rotate</code><span>Rotate a vector by an angle in radians.</span></a><a class="idx-item" href="vector-angle.html" data-name="Vector.angle" data-tip="The angle of a vector in radians."><code>Vector.angle</code><span>The angle of a vector in radians.</span></a><a class="idx-item" href="vector-from_angle.html" data-name="Vector.from_angle" data-tip="A unit vector pointing at an angle."><code>Vector.from_angle</code><span>A unit vector pointing at an angle.</span></a></div></section><section class="idx-sec" data-sec="http"><h2 id="http">Http</h2><p class="sec-blurb">A poll-based HTTP / HTTPS client for out-of-band data — leaderboards, cloud saves, remote config, telemetry, downloads. Open a request with <a href="http-get.html"><code>Http.get</code></a> / <a href="http-post.html"><code>Http.post</code></a> (or <a href="http-open.html"><code>Http.open</code></a> to add headers first), then each frame call <a href="http-poll.html"><code>Http.poll</code></a> — it returns <code>-1</code> while pending, <code>0</code> on error, or the status code — so the frame never blocks. Read the reply with <a href="http-status.html"><code>Http.status</code></a> / <a href="http-ok.html"><code>ok</code></a> / <a href="http-text.html"><code>text</code></a> / <a href="http-header.html"><code>header</code></a>, and pair it with <code>Json.*</code> for (de)serialization. TLS is the system's, on by default. A large download goes to a file instead of memory with <a href="http-save_to.html"><code>Http.save_to</code></a>, and <a href="http-received.html"><code>Http.received</code></a> / <a href="http-expected.html"><code>expected</code></a> drive a progress bar while it is pending.
HTTP depends on the network and the wall clock, so — like <code>Net.*</code> and <code>Time.now</code> — it is <strong>out-of-band</strong> and must never feed the deterministic lockstep/replay simulation. The transport is NSURLConnection / NSURLSession on macOS and WinHTTP on Windows; the raw-response parser (<a href="http-parse.html"><code>Http.parse</code></a>) is pure and portable.</p><div class="idx-grid"><a class="idx-item" href="http-get.html" data-name="Http.get" data-tip="Start an async GET request."><code>Http.get</code><span>Start an async GET request.</span></a><a class="idx-item" href="http-post.html" data-name="Http.post" data-tip="Start an async POST with a body."><code>Http.post</code><span>Start an async POST with a body.</span></a><a class="idx-item" href="http-request.html" data-name="Http.request" data-tip="Start a request with any method."><code>Http.request</code><span>Start a request with any method.</span></a><a class="idx-item" href="http-open.html" data-name="Http.open" data-tip="Open a request to configure before sending."><code>Http.open</code><span>Open a request to configure before sending.</span></a><a class="idx-item" href="http-set.html" data-name="Http.set" data-tip="Set a request header before sending."><code>Http.set</code><span>Set a request header before sending.</span></a><a class="idx-item" href="http-body.html" data-name="Http.body" data-tip="Set a string request body."><code>Http.body</code><span>Set a string request body.</span></a><a class="idx-item" href="http-body_bytes.html" data-name="Http.body_bytes" data-tip="Set a raw byte request body."><code>Http.body_bytes</code><span>Set a raw byte request body.</span></a><a class="idx-item" href="http-send.html" data-name="Http.send" data-tip="Dispatch an opened request."><code>Http.send</code><span>Dispatch an opened request.</span></a><a class="idx-item" href="http-poll.html" data-name="Http.poll" data-tip="Poll a request; -1 pending, 0 error, else status."><code>Http.poll</code><span>Poll a request; -1 pending, 0 error, else status.</span></a><a class="idx-item" href="http-status.html" data-name="Http.status" data-tip="The response HTTP status code."><code>Http.status</code><span>The response HTTP status code.</span></a><a class="idx-item" href="http-ok.html" data-name="Http.ok" data-tip="Was the response status 2xx?"><code>Http.ok</code><span>Was the response status 2xx?</span></a><a class="idx-item" href="http-text.html" data-name="Http.text" data-tip="The response body as text."><code>Http.text</code><span>The response body as text.</span></a><a class="idx-item" href="http-body_len.html" data-name="Http.body_len" data-tip="The response body length in bytes."><code>Http.body_len</code><span>The response body length in bytes.</span></a><a class="idx-item" href="http-header.html" data-name="Http.header" data-tip="A response header value (case-insensitive)."><code>Http.header</code><span>A response header value (case-insensitive).</span></a><a class="idx-item" href="http-free.html" data-name="Http.free" data-tip="Release a request&#x27;s resources."><code>Http.free</code><span>Release a request's resources.</span></a><a class="idx-item" href="http-parse.html" data-name="Http.parse" data-tip="Parse a raw HTTP response into a handle."><code>Http.parse</code><span>Parse a raw HTTP response into a handle.</span></a><a class="idx-item" href="http-save_to.html" data-name="Http.save_to" data-tip="Stream the response body to a file."><code>Http.save_to</code><span>Stream the response body to a file.</span></a><a class="idx-item" href="http-received.html" data-name="Http.received" data-tip="Body bytes received so far."><code>Http.received</code><span>Body bytes received so far.</span></a><a class="idx-item" href="http-expected.html" data-name="Http.expected" data-tip="The body length the server announced, or -1."><code>Http.expected</code><span>The body length the server announced, or -1.</span></a></div></section><section class="idx-sec" data-sec="ivec2"><h2 id="ivec2">IVec2</h2><p class="sec-blurb">Integer 2D vector math for tile and grid coordinates, cell offsets, and integer sizes. An <code>IVec2</code> is a pair of whole-number <code>int</code> components (x, y) packed into one value, so it is copied by value and never allocates. Every operation is exact integer arithmetic — no rounding, and bit-identical on every platform. Use it wherever a fractional part would be meaningless; reach for <code>Vector</code> when you need sub-pixel precision. Arguments are positional.</p><div class="idx-grid"><a class="idx-item" href="ivec2-make.html" data-name="IVec2.make" data-tip="Build an integer vector from x and y components."><code>IVec2.make</code><span>Build an integer vector from x and y components.</span></a><a class="idx-item" href="ivec2-zero.html" data-name="IVec2.zero" data-tip="The origin cell, (0, 0)."><code>IVec2.zero</code><span>The origin cell, (0, 0).</span></a><a class="idx-item" href="ivec2-x.html" data-name="IVec2.x" data-tip="The x component of an integer vector."><code>IVec2.x</code><span>The x component of an integer vector.</span></a><a class="idx-item" href="ivec2-y.html" data-name="IVec2.y" data-tip="The y component of an integer vector."><code>IVec2.y</code><span>The y component of an integer vector.</span></a><a class="idx-item" href="ivec2-add.html" data-name="IVec2.add" data-tip="Component-wise sum of two integer vectors."><code>IVec2.add</code><span>Component-wise sum of two integer vectors.</span></a><a class="idx-item" href="ivec2-sub.html" data-name="IVec2.sub" data-tip="Component-wise difference of two integer vectors."><code>IVec2.sub</code><span>Component-wise difference of two integer vectors.</span></a><a class="idx-item" href="ivec2-scale.html" data-name="IVec2.scale" data-tip="Multiply both components by an integer."><code>IVec2.scale</code><span>Multiply both components by an integer.</span></a><a class="idx-item" href="ivec2-dot.html" data-name="IVec2.dot" data-tip="The dot product ax*bx + ay*by."><code>IVec2.dot</code><span>The dot product ax*bx + ay*by.</span></a><a class="idx-item" href="ivec2-equal.html" data-name="IVec2.equal" data-tip="True when both components match."><code>IVec2.equal</code><span>True when both components match.</span></a><a class="idx-item" href="ivec2-manhattan.html" data-name="IVec2.manhattan" data-tip="Grid distance |dx| + |dy|."><code>IVec2.manhattan</code><span>Grid distance |dx| + |dy|.</span></a><a class="idx-item" href="ivec2-to_vector.html" data-name="IVec2.to_vector" data-tip="Widen to a fixed-point Vector."><code>IVec2.to_vector</code><span>Widen to a fixed-point Vector.</span></a><a class="idx-item" href="ivec2-distance2.html" data-name="IVec2.distance2" data-tip="The squared distance between two points."><code>IVec2.distance2</code><span>The squared distance between two points.</span></a><a class="idx-item" href="ivec2-within.html" data-name="IVec2.within" data-tip="Are two points within a radius of each other?"><code>IVec2.within</code><span>Are two points within a radius of each other?</span></a><a class="idx-item" href="ivec2-heading.html" data-name="IVec2.heading" data-tip="The direction from one point to another, in degrees."><code>IVec2.heading</code><span>The direction from one point to another, in degrees.</span></a><a class="idx-item" href="ivec2-along.html" data-name="IVec2.along" data-tip="The point a distance along a heading."><code>IVec2.along</code><span>The point a distance along a heading.</span></a><a class="idx-item" href="ivec2-step.html" data-name="IVec2.step" data-tip="A -1/0/1 unit step along a heading."><code>IVec2.step</code><span>A -1/0/1 unit step along a heading.</span></a></div></section><section class="idx-sec" data-sec="map"><h2 id="map">Map — tilemap</h2><p class="sec-blurb">A character grid the game paints and reads.</p><div class="idx-grid"><a class="idx-item" href="map-size.html" data-name="Map.size" data-tip="Set the tilemap dimensions in cells before filling rows."><code>Map.size</code><span>Set the tilemap dimensions in cells before filling rows.</span></a><a class="idx-item" href="map-row.html" data-name="Map.row" data-tip="Fill one row of the tilemap from a string of tile characters."><code>Map.row</code><span>Fill one row of the tilemap from a string of tile characters.</span></a><a class="idx-item" href="map-tile.html" data-name="Map.tile" data-tip="Read the tile character at a cell (out-of-bounds reads answer &#x27;#&#x27;)."><code>Map.tile</code><span>Read the tile character at a cell (out-of-bounds reads answer '#').</span></a><a class="idx-item" href="map-get.html" data-name="Map.get" data-tip="The glyph at a cell (&#x27;#&#x27; outside the map)."><code>Map.get</code><span>The glyph at a cell ('#' outside the map).</span></a><a class="idx-item" href="map-set.html" data-name="Map.set" data-tip="Write one cell in place."><code>Map.set</code><span>Write one cell in place.</span></a><a class="idx-item" href="map-fill.html" data-name="Map.fill" data-tip="Every cell becomes the glyph."><code>Map.fill</code><span>Every cell becomes the glyph.</span></a><a class="idx-item" href="map-rect.html" data-name="Map.rect" data-tip="Fill a rectangle of cells."><code>Map.rect</code><span>Fill a rectangle of cells.</span></a><a class="idx-item" href="map-border.html" data-name="Map.border" data-tip="The outermost ring of cells."><code>Map.border</code><span>The outermost ring of cells.</span></a><a class="idx-item" href="map-random_cell.html" data-name="Map.random_cell" data-tip="A random cell holding the glyph (seeded RNG)."><code>Map.random_cell</code><span>A random cell holding the glyph (seeded RNG).</span></a><a class="idx-item" href="map-is_solid.html" data-name="Map.is_solid" data-tip="Is a cell solid, per the Solids config?"><code>Map.is_solid</code><span>Is a cell solid, per the Solids config?</span></a><a class="idx-item" href="map-is_solid_at.html" data-name="Map.is_solid_at" data-tip="Is the cell under a pixel position solid?"><code>Map.is_solid_at</code><span>Is the cell under a pixel position solid?</span></a><a class="idx-item" href="map-width.html" data-name="Map.width" data-tip="The map&#x27;s width in cells."><code>Map.width</code><span>The map's width in cells.</span></a><a class="idx-item" href="map-height.html" data-name="Map.height" data-tip="The map&#x27;s height in cells."><code>Map.height</code><span>The map's height in cells.</span></a><a class="idx-item" href="map-random_cell_far.html" data-name="Map.random_cell_far" data-tip="A random cell with the glyph, at least a distance from a point."><code>Map.random_cell_far</code><span>A random cell with the glyph, at least a distance from a point.</span></a><a class="idx-item" href="map-to_tile.html" data-name="Map.to_tile" data-tip="The tile under a pixel position."><code>Map.to_tile</code><span>The tile under a pixel position.</span></a></div></section><section class="idx-sec" data-sec="rect"><h2 id="rect">Rect</h2><p class="sec-blurb">Axis-aligned rectangles for HUD layout boxes, hitboxes, and camera regions. A <code>Rect</code> is four Q16.16 <code>fixed</code> components — position <code>(x, y)</code> (its top-left corner) and size <code>(w, h)</code> — packed into a single value that is copied by value and never allocates. It offers fast point-in-rect and rectangle-overlap tests. Every operation is deterministic fixed-point, bit-identical on every platform. Arguments are positional.</p><div class="idx-grid"><a class="idx-item" href="rect-make.html" data-name="Rect.make" data-tip="Build a rectangle from a corner and a size."><code>Rect.make</code><span>Build a rectangle from a corner and a size.</span></a><a class="idx-item" href="rect-x.html" data-name="Rect.x" data-tip="The left edge (x position)."><code>Rect.x</code><span>The left edge (x position).</span></a><a class="idx-item" href="rect-y.html" data-name="Rect.y" data-tip="The top edge (y position)."><code>Rect.y</code><span>The top edge (y position).</span></a><a class="idx-item" href="rect-w.html" data-name="Rect.w" data-tip="The width."><code>Rect.w</code><span>The width.</span></a><a class="idx-item" href="rect-h.html" data-name="Rect.h" data-tip="The height."><code>Rect.h</code><span>The height.</span></a><a class="idx-item" href="rect-right.html" data-name="Rect.right" data-tip="The right edge, x + w."><code>Rect.right</code><span>The right edge, x + w.</span></a><a class="idx-item" href="rect-bottom.html" data-name="Rect.bottom" data-tip="The bottom edge, y + h."><code>Rect.bottom</code><span>The bottom edge, y + h.</span></a><a class="idx-item" href="rect-center.html" data-name="Rect.center" data-tip="The center point as a Vector."><code>Rect.center</code><span>The center point as a Vector.</span></a><a class="idx-item" href="rect-contains.html" data-name="Rect.contains" data-tip="True when the point is inside."><code>Rect.contains</code><span>True when the point is inside.</span></a><a class="idx-item" href="rect-intersects.html" data-name="Rect.intersects" data-tip="True when two rectangles overlap."><code>Rect.intersects</code><span>True when two rectangles overlap.</span></a></div></section><section class="idx-sec" data-sec="udp"><h2 id="udp">Udp</h2><p class="sec-blurb">Plain IPv4 datagrams, polled — the transport under a game's own netcode: peer-to-peer play, a LAN lobby, a STUN query. Open a socket with <a href="udp-open.html"><code>Udp.open</code></a>, send with <a href="udp-send.html"><code>Udp.send</code></a>, and each frame drain what arrived with <a href="udp-recv.html"><code>Udp.recv</code></a>, which returns <code>0</code> when nothing is waiting and never blocks. The sender of the last datagram read is <a href="udp-from_ip.html"><code>Udp.from_ip</code></a> / <a href="udp-from_port.html"><code>from_port</code></a>.
An address is an <code>int</code>: <code>a.b.c.d</code> is <code>(a &lt;&lt; 24) | (b &lt;&lt; 16) | (c &lt;&lt; 8) | d</code>, converted by <a href="udp-ip.html"><code>Udp.ip</code></a> and <a href="udp-ip_text.html"><code>Udp.ip_text</code></a>. Datagrams can be lost, repeated and reordered; the protocol a game builds on top says what to do about that. Like <code>Http.*</code> it is <strong>out-of-band</strong> and must never feed the deterministic lockstep/replay simulation directly. BSD sockets on macOS, Winsock on Windows.</p><div class="idx-grid"><a class="idx-item" href="udp-open.html" data-name="Udp.open" data-tip="Open a socket on a port."><code>Udp.open</code><span>Open a socket on a port.</span></a><a class="idx-item" href="udp-port.html" data-name="Udp.port" data-tip="The port a socket is bound to."><code>Udp.port</code><span>The port a socket is bound to.</span></a><a class="idx-item" href="udp-send.html" data-name="Udp.send" data-tip="Send one datagram."><code>Udp.send</code><span>Send one datagram.</span></a><a class="idx-item" href="udp-recv.html" data-name="Udp.recv" data-tip="Read the next waiting datagram."><code>Udp.recv</code><span>Read the next waiting datagram.</span></a><a class="idx-item" href="udp-from_ip.html" data-name="Udp.from_ip" data-tip="The sender of the last datagram read."><code>Udp.from_ip</code><span>The sender of the last datagram read.</span></a><a class="idx-item" href="udp-from_port.html" data-name="Udp.from_port" data-tip="The sender&#x27;s port."><code>Udp.from_port</code><span>The sender's port.</span></a><a class="idx-item" href="udp-close.html" data-name="Udp.close" data-tip="Close a socket."><code>Udp.close</code><span>Close a socket.</span></a><a class="idx-item" href="udp-resolve.html" data-name="Udp.resolve" data-tip="Look a host name up."><code>Udp.resolve</code><span>Look a host name up.</span></a><a class="idx-item" href="udp-local_ip.html" data-name="Udp.local_ip" data-tip="This machine&#x27;s address."><code>Udp.local_ip</code><span>This machine's address.</span></a><a class="idx-item" href="udp-ip.html" data-name="Udp.ip" data-tip="Parse a dotted address."><code>Udp.ip</code><span>Parse a dotted address.</span></a><a class="idx-item" href="udp-ip_text.html" data-name="Udp.ip_text" data-tip="Format an address."><code>Udp.ip_text</code><span>Format an address.</span></a></div></section><section class="idx-sec" data-sec="bigint"><h2 id="bigint">BigInt</h2><p class="sec-blurb">Arbitrary-precision integers with no upper bound, for idle/incremental counters, exact huge currencies, and score arithmetic that a 32- or 64-bit <code>int</code> would overflow. A <code>BigInt</code> is a sign-magnitude number stored as base-1e9 limbs, so every operation is <strong>exact</strong> and therefore deterministic — bit-identical on every platform, with no binary floating point. Build one with <code>BigInt.from</code> (an <code>int</code>) or <code>BigInt.parse</code> (decimal text), combine with <code>add</code> / <code>sub</code> / <code>mul</code> / <code>pow</code> / <code>div</code> / <code>mod</code>, compare with <code>cmp</code> / <code>eq</code> / <code>is_zero</code>, and render with <code>str</code>. Arguments are positional. The runtime is spliced in only when a program mentions <code>BigInt.*</code>.</p><div class="idx-grid"><a class="idx-item" href="bigint-from.html" data-name="BigInt.from" data-tip="Turn a plain int into a BigInt."><code>BigInt.from</code><span>Turn a plain int into a BigInt.</span></a><a class="idx-item" href="bigint-parse.html" data-name="BigInt.parse" data-tip="Parse decimal text into a BigInt."><code>BigInt.parse</code><span>Parse decimal text into a BigInt.</span></a><a class="idx-item" href="bigint-add.html" data-name="BigInt.add" data-tip="Exact sum of two big integers."><code>BigInt.add</code><span>Exact sum of two big integers.</span></a><a class="idx-item" href="bigint-sub.html" data-name="BigInt.sub" data-tip="Exact difference of two big integers."><code>BigInt.sub</code><span>Exact difference of two big integers.</span></a><a class="idx-item" href="bigint-mul.html" data-name="BigInt.mul" data-tip="Exact product of two big integers."><code>BigInt.mul</code><span>Exact product of two big integers.</span></a><a class="idx-item" href="bigint-neg.html" data-name="BigInt.neg" data-tip="Negate a big integer."><code>BigInt.neg</code><span>Negate a big integer.</span></a><a class="idx-item" href="bigint-pow.html" data-name="BigInt.pow" data-tip="Raise a big integer to an int power."><code>BigInt.pow</code><span>Raise a big integer to an int power.</span></a><a class="idx-item" href="bigint-div.html" data-name="BigInt.div" data-tip="Divide a big integer by an int (toward zero)."><code>BigInt.div</code><span>Divide a big integer by an int (toward zero).</span></a><a class="idx-item" href="bigint-mod.html" data-name="BigInt.mod" data-tip="Remainder of a big integer divided by an int."><code>BigInt.mod</code><span>Remainder of a big integer divided by an int.</span></a><a class="idx-item" href="bigint-cmp.html" data-name="BigInt.cmp" data-tip="Compare two big integers: -1, 0, or 1."><code>BigInt.cmp</code><span>Compare two big integers: -1, 0, or 1.</span></a><a class="idx-item" href="bigint-eq.html" data-name="BigInt.eq" data-tip="True when two big integers are equal."><code>BigInt.eq</code><span>True when two big integers are equal.</span></a><a class="idx-item" href="bigint-is_zero.html" data-name="BigInt.is_zero" data-tip="True when a big integer is zero."><code>BigInt.is_zero</code><span>True when a big integer is zero.</span></a><a class="idx-item" href="bigint-to_int.html" data-name="BigInt.to_int" data-tip="Narrow a big integer to a plain int (clamped)."><code>BigInt.to_int</code><span>Narrow a big integer to a plain int (clamped).</span></a><a class="idx-item" href="bigint-str.html" data-name="BigInt.str" data-tip="Render a big integer as decimal text."><code>BigInt.str</code><span>Render a big integer as decimal text.</span></a></div></section><section class="idx-sec" data-sec="colors"><h2 id="colors">Color — the named palette</h2><p class="sec-blurb"><code>Color.Name</code> lowers to a plain <code>0xRRGGBB</code> integer at compile time — no runtime cost, identical to writing the hex by hand, but readable. 221 names are built in; a custom shade is any hex literal or a named <code>const</code>. The full palette:</p><div class="idx-grid"><a class="idx-item" href="ns-color.html" data-name="Color" data-tip="The named color palette."><code>Color</code><span>The named color palette (221 names).</span></a></div></section><section class="idx-sec" data-sec="process"><h2 id="process">Process</h2><p class="sec-blurb">Child processes, started and polled — what a launcher is made of. <a href="process-spawn.html"><code>Process.spawn</code></a> starts a program directly, with no shell, and returns at once; each frame <a href="process-poll.html"><code>Process.poll</code></a> answers <code>-1</code> while the child runs and its exit code once it has ended, so a crash is a non-zero code the game can act on. <a href="process-kill.html"><code>Process.kill</code></a> ends a child and <a href="process-free.html"><code>Process.free</code></a> lets a handle go. Pair it with <a href="../app/app-window_hide.html"><code>App.window_hide</code></a> to step aside while the child runs.
The child inherits the environment and the working directory. <code>posix_spawn</code> on macOS; <code>CreateProcessW</code> on Windows, with each argument quoted by the MSVC rules and no console window. Like <code>Http.*</code> it is <strong>out-of-band</strong> and must never feed the deterministic lockstep/replay simulation.</p><div class="idx-grid"><a class="idx-item" href="process-spawn.html" data-name="Process.spawn" data-tip="Start a program; never blocks."><code>Process.spawn</code><span>Start a program; never blocks.</span></a><a class="idx-item" href="process-poll.html" data-name="Process.poll" data-tip="-1 while running, else the exit code."><code>Process.poll</code><span>-1 while running, else the exit code.</span></a><a class="idx-item" href="process-kill.html" data-name="Process.kill" data-tip="End a running child."><code>Process.kill</code><span>End a running child.</span></a><a class="idx-item" href="process-free.html" data-name="Process.free" data-tip="Let a process handle go."><code>Process.free</code><span>Let a process handle go.</span></a></div></section><section class="idx-sec" data-sec="decimal"><h2 id="decimal">Decimal</h2><p class="sec-blurb">Exact base-10 fixed-point numbers for game economies — prices, balances and taxes on values like <code>0.10</code> that binary floating point cannot represent, so they always add up exactly. A <code>Decimal</code> is a <code>BigInt</code> mantissa with a decimal <code>scale</code> (the number of digits after the point), giving unbounded range and exact <code>add</code> / <code>sub</code> / <code>mul</code>. Build one with <code>Decimal.from</code> (an <code>int</code>) or <code>Decimal.parse</code> (text like <code>"19.99"</code>), compare with <code>cmp</code> / <code>eq</code>, change precision with <code>rescale</code> (truncates toward zero), read the current precision with <code>scale</code>, and render with <code>str</code>. Every operation is exact and deterministic. The runtime is spliced in only when a program mentions <code>Decimal.*</code> (or <code>BigInt.*</code>).</p><div class="idx-grid"><a class="idx-item" href="decimal-from.html" data-name="Decimal.from" data-tip="Turn a whole int into a Decimal."><code>Decimal.from</code><span>Turn a whole int into a Decimal.</span></a><a class="idx-item" href="decimal-parse.html" data-name="Decimal.parse" data-tip="Parse decimal text like &quot;19.99&quot;."><code>Decimal.parse</code><span>Parse decimal text like "19.99".</span></a><a class="idx-item" href="decimal-add.html" data-name="Decimal.add" data-tip="Exact sum of two decimals."><code>Decimal.add</code><span>Exact sum of two decimals.</span></a><a class="idx-item" href="decimal-sub.html" data-name="Decimal.sub" data-tip="Exact difference of two decimals."><code>Decimal.sub</code><span>Exact difference of two decimals.</span></a><a class="idx-item" href="decimal-mul.html" data-name="Decimal.mul" data-tip="Exact product of two decimals."><code>Decimal.mul</code><span>Exact product of two decimals.</span></a><a class="idx-item" href="decimal-neg.html" data-name="Decimal.neg" data-tip="Negate a decimal."><code>Decimal.neg</code><span>Negate a decimal.</span></a><a class="idx-item" href="decimal-cmp.html" data-name="Decimal.cmp" data-tip="Compare two decimals: -1, 0, or 1."><code>Decimal.cmp</code><span>Compare two decimals: -1, 0, or 1.</span></a><a class="idx-item" href="decimal-eq.html" data-name="Decimal.eq" data-tip="True when two decimals are equal in value."><code>Decimal.eq</code><span>True when two decimals are equal in value.</span></a><a class="idx-item" href="decimal-scale.html" data-name="Decimal.scale" data-tip="The number of digits after the point."><code>Decimal.scale</code><span>The number of digits after the point.</span></a><a class="idx-item" href="decimal-rescale.html" data-name="Decimal.rescale" data-tip="Change precision (truncates toward zero)."><code>Decimal.rescale</code><span>Change precision (truncates toward zero).</span></a><a class="idx-item" href="decimal-str.html" data-name="Decimal.str" data-tip="Render a decimal as text."><code>Decimal.str</code><span>Render a decimal as text.</span></a></div></section><section class="idx-sec" data-sec="types"><h2 id="types">Types</h2><p class="sec-blurb">Ludic is statically typed; most code uses just <code>int</code>.</p><div class="idx-grid"><a class="idx-item" href="type-int.html" data-name="int" data-tip="The default 32-bit signed integer — also how colors, keys, and tiles are carried."><code>int</code><span>The default 32-bit signed integer — also how colors, keys, and tiles are carried.</span></a><a class="idx-item" href="type-fixed.html" data-name="fixed" data-tip="Q16.16 fixed-point for deterministic fractional math — no floats."><code>fixed</code><span>Q16.16 fixed-point for deterministic fractional math — no floats.</span></a><a class="idx-item" href="type-long.html" data-name="long" data-tip="A 64-bit signed integer for values that overflow a 32-bit int."><code>long</code><span>A 64-bit signed integer for values that overflow a 32-bit int.</span></a><a class="idx-item" href="type-bool.html" data-name="bool" data-tip="A truth value — the result of comparisons and of and / or / not."><code>bool</code><span>A truth value — the result of comparisons and of and / or / not.</span></a><a class="idx-item" href="type-float.html" data-name="float" data-tip="A 32-bit IEEE floating-point number — what the GPU uses."><code>float</code><span>A 32-bit IEEE floating-point number — what the GPU uses.</span></a><a class="idx-item" href="type-string.html" data-name="string" data-tip="An immutable string — compared by content, sliceable, and interpolatable."><code>string</code><span>An immutable string — compared by content, sliceable, and interpolatable.</span></a><a class="idx-item" href="type-double.html" data-name="double" data-tip="A 64-bit IEEE floating-point number for precise math."><code>double</code><span>A 64-bit IEEE floating-point number for precise math.</span></a><a class="idx-item" href="type-entity.html" data-name="entity" data-tip="The id/handle of a spawned model instance, as returned by self()."><code>entity</code><span>The id/handle of a spawned model instance, as returned by self().</span></a><a class="idx-item" href="type-pointer.html" data-name="pointer" data-tip="A raw address into memory — a byte buffer from bytes(n), or an FFI handle."><code>pointer</code><span>A raw address into memory — a byte buffer from bytes(n), or an FFI handle.</span></a><a class="idx-item" href="type-words.html" data-name="words" data-tip="A raw buffer indexed as 32-bit words — each buffer[i] reads or writes an int."><code>words</code><span>A raw buffer indexed as 32-bit words — each buffer[i] reads or writes an int.</span></a><a class="idx-item" href="type-byte.html" data-name="byte" data-tip="A raw buffer indexed one byte at a time — each buffer[i] reads or writes a byte."><code>byte</code><span>A raw buffer indexed one byte at a time — each buffer[i] reads or writes a byte.</span></a><a class="idx-item" href="type-slices.html" data-name="[]T (slices)" data-tip="A growable slice of T — new []T makes one, push appends, len counts, s[i] indexes."><code>[]T (slices)</code><span>A growable slice of T — new []T makes one, push appends, len counts, s[i] indexes.</span></a><a class="idx-item" href="type-fixeds.html" data-name="fixeds" data-tip="A buffer of fixed-point values — f[i] reads and writes a fixed."><code>fixeds</code><span>A buffer of fixed-point values — f[i] reads and writes a fixed.</span></a><a class="idx-item" href="type-countdown.html" data-name="countdown" data-tip="An int component field the engine steps toward 0 once per Update."><code>countdown</code><span>An int component field the engine steps toward 0 once per Update.</span></a><a class="idx-item" href="type-floats.html" data-name="floats" data-tip="A buffer of floats (or doubles) — v[i] reads and writes one."><code>floats</code><span>A buffer of floats (or doubles) — v[i] reads and writes one.</span></a><a class="idx-item" href="type-pointers.html" data-name="pointers" data-tip="A buffer of pointers — p[i] reads and writes a pointer."><code>pointers</code><span>A buffer of pointers — p[i] reads and writes a pointer.</span></a><a class="idx-item" href="type-vector.html" data-name="Vector" data-tip="A 2D vector — two fixed components (x, y), copied by value."><code>Vector</code><span>A 2D vector — two fixed components (x, y), copied by value.</span></a><a class="idx-item" href="type-ivec2.html" data-name="IVec2" data-tip="An integer 2D vector — two int components (x, y), copied by value."><code>IVec2</code><span>An integer 2D vector — two int components (x, y), copied by value.</span></a><a class="idx-item" href="type-rect.html" data-name="Rect" data-tip="A rectangle — position (x, y) and size (w, h), copied by value."><code>Rect</code><span>A rectangle — position (x, y) and size (w, h), copied by value.</span></a><a class="idx-item" href="type-void.html" data-name="void" data-tip="The absence of a value — the return type of a function that returns nothing."><code>void</code><span>The absence of a value — the return type of a function that returns nothing.</span></a></div></section><section class="idx-sec" data-sec="dict"><h2 id="dict">Dict</h2><p class="sec-blurb">A hash map from string keys to <code>int</code> values — the everyday lookup a game needs, like resource counts or an id registry by name. A <code>Dict</code> is backed by an open-addressing hash table (FNV-1a, linear probing, tombstone deletes, growing at load factor 0.7), so <code>get</code>/<code>set</code>/<code>has</code> are O(1) on average rather than the linear scan a list would give. Create one with <code>Dict.new</code>, then <code>set</code> / <code>get</code> / <code>get_or</code> / <code>has</code> / <code>remove</code> / <code>size</code> / <code>clear</code> / <code>keys</code>. Values are <code>int</code> (which also holds an <code>entity</code> or any small id); for richer values use the <code>Value.*</code> tree. Arguments are positional. The runtime is spliced in only when a program mentions <code>Dict.*</code> (or <code>Set.*</code>).</p><div class="idx-grid"><a class="idx-item" href="dict-new.html" data-name="Dict.new" data-tip="Create an empty string-keyed map."><code>Dict.new</code><span>Create an empty string-keyed map.</span></a><a class="idx-item" href="dict-set.html" data-name="Dict.set" data-tip="Insert or update a key."><code>Dict.set</code><span>Insert or update a key.</span></a><a class="idx-item" href="dict-get.html" data-name="Dict.get" data-tip="Look up a key (0 if absent)."><code>Dict.get</code><span>Look up a key (0 if absent).</span></a><a class="idx-item" href="dict-get_or.html" data-name="Dict.get_or" data-tip="Look up a key with an explicit default."><code>Dict.get_or</code><span>Look up a key with an explicit default.</span></a><a class="idx-item" href="dict-has.html" data-name="Dict.has" data-tip="Is a key present?"><code>Dict.has</code><span>Is a key present?</span></a><a class="idx-item" href="dict-remove.html" data-name="Dict.remove" data-tip="Delete a key."><code>Dict.remove</code><span>Delete a key.</span></a><a class="idx-item" href="dict-size.html" data-name="Dict.size" data-tip="How many keys are stored."><code>Dict.size</code><span>How many keys are stored.</span></a><a class="idx-item" href="dict-clear.html" data-name="Dict.clear" data-tip="Remove every key."><code>Dict.clear</code><span>Remove every key.</span></a><a class="idx-item" href="dict-keys.html" data-name="Dict.keys" data-tip="Every key, as a slice of strings."><code>Dict.keys</code><span>Every key, as a slice of strings.</span></a></div></section><section class="idx-sec" data-sec="operators"><h2 id="operators">Operators &amp; tokens</h2><p class="sec-blurb">The symbols the grammar recognizes.</p><div class="idx-grid"><a class="idx-item" href="op-arith.html" data-name="Arithmetic" data-tip="Add, subtract, multiply, integer-divide, and remainder — on int and fixed."><code>Arithmetic</code><span>Add, subtract, multiply, integer-divide, and remainder — on int and fixed.</span></a><a class="idx-item" href="op-compare.html" data-name="Comparison" data-tip="Compare two values and yield a bool; on strings == compares contents."><code>Comparison</code><span>Compare two values and yield a bool; on strings == compares contents.</span></a><a class="idx-item" href="op-logical.html" data-name="Logical" data-tip="The boolean combinators, spelled as words — never &amp;&amp; or || or a bare !."><code>Logical</code><span>The boolean combinators, spelled as words — never &amp;&amp; or || or a bare !.</span></a><a class="idx-item" href="op-bitwise.html" data-name="Bitwise" data-tip="Bit-level and, or, xor, not, and shifts — with Go-style precedence."><code>Bitwise</code><span>Bit-level and, or, xor, not, and shifts — with Go-style precedence.</span></a><a class="idx-item" href="op-range.html" data-name="Range" data-tip="A half-open range for numeric for loops — from a up to but not including b."><code>Range</code><span>A half-open range for numeric for loops — from a up to but not including b.</span></a><a class="idx-item" href="op-assign.html" data-name="Assignment" data-tip="Store into a var, a field, or an element — a statement, not an expression."><code>Assignment</code><span>Store into a var, a field, or an element — a statement, not an expression.</span></a><a class="idx-item" href="op-access.html" data-name="Member &amp; index" data-tip="Field access, element index, and string slice — usable as value or target."><code>Member &amp; index</code><span>Field access, element index, and string slice — usable as value or target.</span></a><a class="idx-item" href="op-interp.html" data-name="String interpolation" data-tip="A backtick string with {expr} holes, each stringified and concatenated."><code>String interpolation</code><span>A backtick string with {expr} holes, each stringified and concatenated.</span></a><a class="idx-item" href="op-literals.html" data-name="Literals" data-tip="Integer, hex, character, string, boolean, and null-pointer literals."><code>Literals</code><span>Integer, hex, character, string, boolean, and null-pointer literals.</span></a><a class="idx-item" href="op-comment.html" data-name="Comment" data-tip="Everything after # on a line is a comment, ignored by the compiler."><code>Comment</code><span>Everything after # on a line is a comment, ignored by the compiler.</span></a></div></section><section class="idx-sec" data-sec="builtins"><h2 id="builtins">Builtin functions</h2><p class="sec-blurb">Global functions available anywhere, beyond the namespaced APIs above.</p><div class="idx-grid"><a class="idx-item" href="fn-print.html" data-name="print" data-tip="Print an int or string followed by a newline — for headless tests and debugging."><code>print</code><span>Print an int or string followed by a newline — for headless tests and debugging.</span></a><a class="idx-item" href="fn-string.html" data-name="string" data-tip="Convert an int, bool, or fixed value to text; a string passes through unchanged."><code>string</code><span>Convert an int, bool, or fixed value to text; a string passes through unchanged.</span></a><a class="idx-item" href="fn-quit.html" data-name="quit" data-tip="Stop the game loop cleanly after the current frame finishes."><code>quit</code><span>Stop the game loop cleanly after the current frame finishes.</span></a><a class="idx-item" href="fn-save.html" data-name="save" data-tip="Serialize the whole world — every model instance, property, and program var — in one call."><code>save</code><span>Serialize the whole world — every model instance, property, and program var — in one call.</span></a><a class="idx-item" href="fn-load.html" data-name="load" data-tip="Restore the world from a snapshot previously written by save()."><code>load</code><span>Restore the world from a snapshot previously written by save().</span></a><a class="idx-item" href="fn-len.html" data-name="len" data-tip="The number of elements in a slice, or the byte length of a string."><code>len</code><span>The number of elements in a slice, or the byte length of a string.</span></a><a class="idx-item" href="fn-push.html" data-name="push" data-tip="Append one element to the end of a growable slice."><code>push</code><span>Append one element to the end of a growable slice.</span></a><a class="idx-item" href="fn-abs.html" data-name="abs" data-tip="The absolute value of an integer (its magnitude, never negative)."><code>abs</code><span>The absolute value of an integer (its magnitude, never negative).</span></a><a class="idx-item" href="fn-clamp.html" data-name="clamp" data-tip="Constrain a value to the inclusive range [lo, hi]."><code>clamp</code><span>Constrain a value to the inclusive range [lo, hi].</span></a><a class="idx-item" href="fn-panic.html" data-name="panic" data-tip="Abort with a located error message instead of crashing."><code>panic</code><span>Abort with a located error message instead of crashing.</span></a><a class="idx-item" href="fn-assert.html" data-name="assert" data-tip="Abort with a located message when an invariant is false."><code>assert</code><span>Abort with a located message when an invariant is false.</span></a><a class="idx-item" href="fn-ok.html" data-name="ok" data-tip="Wrap a success payload in a result — the happy half of try/else."><code>ok</code><span>Wrap a success payload in a result — the happy half of try/else.</span></a><a class="idx-item" href="fn-err.html" data-name="err" data-tip="Wrap a failure message in a result — the sad half, recovered by try/else."><code>err</code><span>Wrap a failure message in a result — the sad half, recovered by try/else.</span></a><a class="idx-item" href="fn-is_ok.html" data-name="is_ok" data-tip="True when a result carries a success payload."><code>is_ok</code><span>True when a result carries a success payload.</span></a><a class="idx-item" href="fn-is_err.html" data-name="is_err" data-tip="True when a result carries a failure."><code>is_err</code><span>True when a result carries a failure.</span></a><a class="idx-item" href="fn-some.html" data-name="some" data-tip="Wrap a present value in an option."><code>some</code><span>Wrap a present value in an option.</span></a><a class="idx-item" href="fn-none.html" data-name="none" data-tip="The empty option — a missing value."><code>none</code><span>The empty option — a missing value.</span></a><a class="idx-item" href="fn-is_some.html" data-name="is_some" data-tip="True when an option holds a value."><code>is_some</code><span>True when an option holds a value.</span></a><a class="idx-item" href="fn-is_none.html" data-name="is_none" data-tip="True when an option is empty."><code>is_none</code><span>True when an option is empty.</span></a><a class="idx-item" href="fn-unwrap_or.html" data-name="unwrap_or" data-tip="The option value, or a fallback if empty."><code>unwrap_or</code><span>The option value, or a fallback if empty.</span></a><a class="idx-item" href="fn-exit.html" data-name="exit" data-tip="Terminate the process immediately with a status code."><code>exit</code><span>Terminate the process immediately with a status code.</span></a><a class="idx-item" href="fn-run.html" data-name="run" data-tip="Run a string as a shell command."><code>run</code><span>Run a string as a shell command.</span></a><a class="idx-item" href="fn-getenv.html" data-name="getenv" data-tip="Read an environment variable, returning empty when it is unset."><code>getenv</code><span>Read an environment variable, returning empty when it is unset.</span></a><a class="idx-item" href="fn-read_char.html" data-name="read_char" data-tip="Read one byte from standard input, or -1 at end of input."><code>read_char</code><span>Read one byte from standard input, or -1 at end of input.</span></a><a class="idx-item" href="fn-arg.html" data-name="arg" data-tip="The i-th command-line argument as a string."><code>arg</code><span>The i-th command-line argument as a string.</span></a><a class="idx-item" href="fn-arg_count.html" data-name="arg_count" data-tip="The number of command-line arguments, counting the program name."><code>arg_count</code><span>The number of command-line arguments, counting the program name.</span></a><a class="idx-item" href="fn-bytes.html" data-name="bytes" data-tip="Allocate a raw buffer of n bytes and return a pointer to it."><code>bytes</code><span>Allocate a raw buffer of n bytes and return a pointer to it.</span></a><a class="idx-item" href="fn-file_stderr.html" data-name="file_stderr" data-tip="The standard-error stream handle for use with file_write."><code>file_stderr</code><span>The standard-error stream handle for use with file_write.</span></a><a class="idx-item" href="fn-file_stdout.html" data-name="file_stdout" data-tip="The standard-output stream handle for use with file_write."><code>file_stdout</code><span>The standard-output stream handle for use with file_write.</span></a><a class="idx-item" href="fn-file_write.html" data-name="file_write" data-tip="Write a run of raw bytes to a stream handle."><code>file_write</code><span>Write a run of raw bytes to a stream handle.</span></a><a class="idx-item" href="fn-fixed.html" data-name="fixed" data-tip="Convert an int (or a float) into a Q16.16 fixed-point value."><code>fixed</code><span>Convert an int (or a float) into a Q16.16 fixed-point value.</span></a><a class="idx-item" href="fn-floor.html" data-name="floor" data-tip="Floor a fixed-point value down to the nearest integer."><code>floor</code><span>Floor a fixed-point value down to the nearest integer.</span></a><a class="idx-item" href="fn-max.html" data-name="max" data-tip="The larger of two integers."><code>max</code><span>The larger of two integers.</span></a><a class="idx-item" href="fn-min.html" data-name="min" data-tip="The smaller of two integers."><code>min</code><span>The smaller of two integers.</span></a><a class="idx-item" href="fn-ui_build.html" data-name="ui_build" data-tip="Build the declared UI tree so it can be opened and rendered."><code>ui_build</code><span>Build the declared UI tree so it can be opened and rendered.</span></a><a class="idx-item" href="fn-words.html" data-name="words" data-tip="Allocate a raw buffer of n 32-bit words, indexable with [i]."><code>words</code><span>Allocate a raw buffer of n 32-bit words, indexable with [i].</span></a><a class="idx-item" href="fn-float.html" data-name="float" data-tip="Convert any number to a float (or double)."><code>float</code><span>Convert any number to a float (or double).</span></a><a class="idx-item" href="fn-int.html" data-name="int" data-tip="Convert a number to a whole number, truncating toward zero."><code>int</code><span>Convert a number to a whole number, truncating toward zero.</span></a><a class="idx-item" href="fn-float_bits.html" data-name="float_bits" data-tip="A float&#x27;s IEEE bit pattern as an int, and back."><code>float_bits</code><span>A float's IEEE bit pattern as an int, and back.</span></a></div></section><section class="idx-sec" data-sec="set"><h2 id="set">Set</h2><p class="sec-blurb">A set of string members — membership tests for tags, unlocked achievements, or visited tiles. A <code>Set</code> shares the same open-addressing hash table as <code>Dict</code>, so <code>add</code> / <code>has</code> / <code>remove</code> are O(1) on average and duplicates are ignored. Create one with <code>Set.new</code>, then <code>add</code> / <code>has</code> / <code>remove</code> / <code>size</code> / <code>clear</code> / <code>members</code>. Arguments are positional. The runtime is spliced in only when a program mentions <code>Set.*</code> (or <code>Dict.*</code>).</p><div class="idx-grid"><a class="idx-item" href="set-new.html" data-name="Set.new" data-tip="Create an empty string set."><code>Set.new</code><span>Create an empty string set.</span></a><a class="idx-item" href="set-add.html" data-name="Set.add" data-tip="Add a member (duplicates ignored)."><code>Set.add</code><span>Add a member (duplicates ignored).</span></a><a class="idx-item" href="set-has.html" data-name="Set.has" data-tip="Is a member present?"><code>Set.has</code><span>Is a member present?</span></a><a class="idx-item" href="set-remove.html" data-name="Set.remove" data-tip="Remove a member."><code>Set.remove</code><span>Remove a member.</span></a><a class="idx-item" href="set-size.html" data-name="Set.size" data-tip="How many members."><code>Set.size</code><span>How many members.</span></a><a class="idx-item" href="set-clear.html" data-name="Set.clear" data-tip="Remove every member."><code>Set.clear</code><span>Remove every member.</span></a><a class="idx-item" href="set-members.html" data-name="Set.members" data-tip="Every member, as a slice of strings."><code>Set.members</code><span>Every member, as a slice of strings.</span></a></div></section><section class="idx-sec" data-sec="annotations"><h2 id="annotations">Annotations</h2><p class="sec-blurb"><code>@Name(...)</code> decorators attach compile-time behavior to a handler, property, or function.</p><div class="idx-grid"><a class="idx-item" href="annot-queries.html" data-name="@Queries" data-tip="Declare the properties a handler operates on, binding their fields by name in the body."><code>@Queries</code><span>Declare the properties a handler operates on, binding their fields by name in the body.</span></a><a class="idx-item" href="annot-computed.html" data-name="@Computed" data-tip="A derived field expanded inline wherever it is read, never stored."><code>@Computed</code><span>A derived field expanded inline wherever it is read, never stored.</span></a><a class="idx-item" href="annot-on.html" data-name="@On" data-tip="Register a compile-time listener that runs whenever an event is emitted."><code>@On</code><span>Register a compile-time listener that runs whenever an event is emitted.</span></a><a class="idx-item" href="annot-export.html" data-name="@export" data-tip="Expose a function as a native symbol so a host can call it."><code>@export</code><span>Expose a function as a native symbol so a host can call it.</span></a><a class="idx-item" href="annot-sync.html" data-name="@Sync" data-tip="Mark fields as replicated and models as owned so the compiler generates networking."><code>@Sync</code><span>Mark fields as replicated and models as owned so the compiler generates networking.</span></a><a class="idx-item" href="annot-handles.html" data-name="@Handles" data-tip="Declarative hint naming the event or subsystem a handler is responsible for."><code>@Handles</code><span>Declarative hint naming the event or subsystem a handler is responsible for.</span></a><a class="idx-item" href="annot-onattach.html" data-name="@OnAttach" data-tip="Run a handler when a property is structurally attached to a live instance."><code>@OnAttach</code><span>Run a handler when a property is structurally attached to a live instance.</span></a><a class="idx-item" href="annot-ondespawn.html" data-name="@OnDespawn" data-tip="Run a handler when a model instance is torn down, optionally knowing why."><code>@OnDespawn</code><span>Run a handler when a model instance is torn down, optionally knowing why.</span></a><a class="idx-item" href="annot-ondetach.html" data-name="@OnDetach" data-tip="Run a handler when a property is structurally detached from a live instance."><code>@OnDetach</code><span>Run a handler when a property is structurally detached from a live instance.</span></a><a class="idx-item" href="annot-ondisable.html" data-name="@OnDisable" data-tip="Run a handler when a property is paused (disabled) on an instance."><code>@OnDisable</code><span>Run a handler when a property is paused (disabled) on an instance.</span></a><a class="idx-item" href="annot-onenable.html" data-name="@OnEnable" data-tip="Run a handler when a paused property is re-enabled on an instance."><code>@OnEnable</code><span>Run a handler when a paused property is re-enabled on an instance.</span></a><a class="idx-item" href="annot-onquit.html" data-name="@OnQuit" data-tip="Run a handler once at shutdown, after the last frame."><code>@OnQuit</code><span>Run a handler once at shutdown, after the last frame.</span></a><a class="idx-item" href="annot-onspawn.html" data-name="@OnSpawn" data-tip="Run a handler once each time an instance of a model is spawned."><code>@OnSpawn</code><span>Run a handler once each time an instance of a model is spawned.</span></a><a class="idx-item" href="annot-onstart.html" data-name="@OnStart" data-tip="Run a handler once at boot instead of assigning it a frame phase."><code>@OnStart</code><span>Run a handler once at boot instead of assigning it a frame phase.</span></a><a class="idx-item" href="annot-owned.html" data-name="@Owned" data-tip="Give a model a network owner slot so its instances can be assigned to a peer."><code>@Owned</code><span>Give a model a network owner slot so its instances can be assigned to a peer.</span></a><a class="idx-item" href="annot-predicted.html" data-name="@Predicted" data-tip="Run a control handler on the owning client speculatively and on the server authoritatively."><code>@Predicted</code><span>Run a control handler on the owning client speculatively and on the server authoritatively.</span></a><a class="idx-item" href="annot-public.html" data-name="@Public" data-tip="Promote a lifecycle hook to a public event other modules can listen for."><code>@Public</code><span>Promote a lifecycle hook to a public event other modules can listen for.</span></a><a class="idx-item" href="annot-reads.html" data-name="@Reads" data-tip="Declare that a handler reads a property — an analysis and scheduling hint."><code>@Reads</code><span>Declare that a handler reads a property — an analysis and scheduling hint.</span></a><a class="idx-item" href="annot-server.html" data-name="@Server" data-tip="Run a handler only on the authority; clients receive the result via @Sync."><code>@Server</code><span>Run a handler only on the authority; clients receive the result via @Sync.</span></a><a class="idx-item" href="annot-toclients.html" data-name="@ToClients" data-tip="A remote event broadcast from the server to clients — a server→clients notification."><code>@ToClients</code><span>A remote event broadcast from the server to clients — a server→clients notification.</span></a><a class="idx-item" href="annot-toserver.html" data-name="@ToServer" data-tip="A remote event sent from a client to the server — a client→server request."><code>@ToServer</code><span>A remote event sent from a client to the server — a client→server request.</span></a><a class="idx-item" href="annot-writes.html" data-name="@Writes" data-tip="Declare that a handler writes a property — an analysis and scheduling hint."><code>@Writes</code><span>Declare that a handler writes a property — an analysis and scheduling hint.</span></a><a class="idx-item" href="annot-enginesystem.html" data-name="@EngineSystem" data-tip="Register a package&#x27;s engine-owned system so the frame loop runs it each phase."><code>@EngineSystem</code><span>Register a package's engine-owned system so the frame loop runs it each phase.</span></a><a class="idx-item" href="annot-namespace.html" data-name="@Namespace" data-tip="Let a package provide a Name.method(…) namespace that dispatches to name_method."><code>@Namespace</code><span>Let a package provide a Name.method(…) namespace that dispatches to name_method.</span></a><a class="idx-item" href="annot-clearcolor.html" data-name="&quot;@ClearColor&quot;" data-tip="Declare a clear colour so the Render phase auto-clears + auto-presents for you."><code>"@ClearColor"</code><span>Declare a clear colour so the Render phase auto-clears + auto-presents for you.</span></a><a class="idx-item" href="annot-system.html" data-name="@System" data-tip="Register a prebuilt binary module&#x27;s system with the host at load, per phase."><code>@System</code><span>Register a prebuilt binary module's system with the host at load, per phase.</span></a></div></section><section class="idx-sec" data-sec="huge"><h2 id="huge">Huge</h2><p class="sec-blurb">Idle/incremental big numbers — magnitudes far past what a 32- or 64-bit integer can hold, for prestige currencies and exponential growth. A <code>Huge</code> is a normalized mantissa (a Q16.16 <code>fixed</code> in [1, 10)) times <code>10^exponent</code>, so it can represent 10^100 or 10^1000 while staying one small value. It is a <strong>display-scale</strong> number (about four significant digits), <em>not</em> a lockstep-exact one — keep it out of the deterministic simulation and reach for <code>BigInt</code> / <code>Decimal</code> when exactness matters. Build one with <code>Huge.from</code>, combine with <code>add</code> / <code>sub</code> / <code>mul</code> / <code>neg</code>, compare with <code>cmp</code> / <code>sign</code>, read <code>mantissa</code> / <code>exp</code>, and render as <code>1.23e45</code> with <code>str</code>. Arguments are positional. Spliced in only when a program mentions <code>Huge.*</code>.</p><div class="idx-grid"><a class="idx-item" href="huge-from.html" data-name="Huge.from" data-tip="Turn an int into a Huge."><code>Huge.from</code><span>Turn an int into a Huge.</span></a><a class="idx-item" href="huge-add.html" data-name="Huge.add" data-tip="Sum of two big numbers."><code>Huge.add</code><span>Sum of two big numbers.</span></a><a class="idx-item" href="huge-sub.html" data-name="Huge.sub" data-tip="Difference of two big numbers."><code>Huge.sub</code><span>Difference of two big numbers.</span></a><a class="idx-item" href="huge-mul.html" data-name="Huge.mul" data-tip="Product of two big numbers."><code>Huge.mul</code><span>Product of two big numbers.</span></a><a class="idx-item" href="huge-neg.html" data-name="Huge.neg" data-tip="Negate a big number."><code>Huge.neg</code><span>Negate a big number.</span></a><a class="idx-item" href="huge-cmp.html" data-name="Huge.cmp" data-tip="Compare two big numbers: -1, 0, or 1."><code>Huge.cmp</code><span>Compare two big numbers: -1, 0, or 1.</span></a><a class="idx-item" href="huge-sign.html" data-name="Huge.sign" data-tip="The sign: -1, 0, or 1."><code>Huge.sign</code><span>The sign: -1, 0, or 1.</span></a><a class="idx-item" href="huge-mantissa.html" data-name="Huge.mantissa" data-tip="The mantissa in [1, 10)."><code>Huge.mantissa</code><span>The mantissa in [1, 10).</span></a><a class="idx-item" href="huge-exp.html" data-name="Huge.exp" data-tip="The base-10 exponent."><code>Huge.exp</code><span>The base-10 exponent.</span></a><a class="idx-item" href="huge-str.html" data-name="Huge.str" data-tip="Render as scientific text like 1.23e45."><code>Huge.str</code><span>Render as scientific text like 1.23e45.</span></a></div></section><section class="idx-sec" data-sec="angle"><h2 id="angle">Angle</h2><p class="sec-blurb">An auto-wrapping angle in radians, so you never juggle <code>% TAU</code> by hand. Every <code>Angle.*</code> result is normalized into <code>[-pi, pi)</code>, which makes <code>diff</code> the shortest signed rotation between two headings and <code>lerp</code> turn the short way around. Build from degrees with <code>Angle.from_degrees</code> (read back with <code>to_degrees</code>), take <code>sin</code> / <code>cos</code>, combine with <code>add</code>, and normalize any raw value with <code>wrap</code>. It builds on the deterministic fixed-point <code>Math.*</code> trig, so results are bit-identical on every platform. Arguments are positional; angles are <code>fixed</code> radians. Spliced in only when a program mentions <code>Angle.*</code>.</p><div class="idx-grid"><a class="idx-item" href="angle-from_degrees.html" data-name="Angle.from_degrees" data-tip="Degrees to a wrapped radian angle."><code>Angle.from_degrees</code><span>Degrees to a wrapped radian angle.</span></a><a class="idx-item" href="angle-to_degrees.html" data-name="Angle.to_degrees" data-tip="Radians back to degrees."><code>Angle.to_degrees</code><span>Radians back to degrees.</span></a><a class="idx-item" href="angle-wrap.html" data-name="Angle.wrap" data-tip="Normalize any radian value to [-pi, pi)."><code>Angle.wrap</code><span>Normalize any radian value to [-pi, pi).</span></a><a class="idx-item" href="angle-sin.html" data-name="Angle.sin" data-tip="Sine of an angle."><code>Angle.sin</code><span>Sine of an angle.</span></a><a class="idx-item" href="angle-cos.html" data-name="Angle.cos" data-tip="Cosine of an angle."><code>Angle.cos</code><span>Cosine of an angle.</span></a><a class="idx-item" href="angle-add.html" data-name="Angle.add" data-tip="Add two angles (wrapped)."><code>Angle.add</code><span>Add two angles (wrapped).</span></a><a class="idx-item" href="angle-diff.html" data-name="Angle.diff" data-tip="Shortest signed rotation from a to b."><code>Angle.diff</code><span>Shortest signed rotation from a to b.</span></a><a class="idx-item" href="angle-lerp.html" data-name="Angle.lerp" data-tip="Interpolate along the shortest arc."><code>Angle.lerp</code><span>Interpolate along the shortest arc.</span></a><a class="idx-item" href="angle-diff_degrees.html" data-name="Angle.diff_degrees" data-tip="The signed difference between two headings in whole degrees."><code>Angle.diff_degrees</code><span>The signed difference between two headings in whole degrees.</span></a></div></section><section class="idx-sec" data-sec="percent"><h2 id="percent">Percent</h2><p class="sec-blurb">A value clamped to <code>[0, 1]</code> — health fractions, volumes, and the <code>t</code> of an interpolation, without stray values slipping below 0 or above 1. <code>Percent.clamp</code> pins any <code>fixed</code> into range; <code>Percent.of</code> forms a clamped ratio <code>num / den</code>; <code>Percent.lerp</code> interpolates <code>a..b</code> by a clamped <code>t</code>; and <code>Percent.apply</code> scales a value by a clamped fraction. Every operation is deterministic fixed-point. Arguments are positional. Spliced in only when a program mentions <code>Percent.*</code>.</p><div class="idx-grid"><a class="idx-item" href="percent-clamp.html" data-name="Percent.clamp" data-tip="Clamp any fixed into [0, 1]."><code>Percent.clamp</code><span>Clamp any fixed into [0, 1].</span></a><a class="idx-item" href="percent-of.html" data-name="Percent.of" data-tip="Clamped ratio num / den."><code>Percent.of</code><span>Clamped ratio num / den.</span></a><a class="idx-item" href="percent-lerp.html" data-name="Percent.lerp" data-tip="Interpolate a..b by a clamped t."><code>Percent.lerp</code><span>Interpolate a..b by a clamped t.</span></a><a class="idx-item" href="percent-apply.html" data-name="Percent.apply" data-tip="Scale a value by a clamped percent."><code>Percent.apply</code><span>Scale a value by a clamped percent.</span></a></div></section><section class="idx-sec" data-sec="regex"><h2 id="regex">Regex</h2><p class="sec-blurb">Regular expressions with PCRE/PECL-compatible syntax over a **linear-time** Thompson NFA (a Pike VM), so a bad pattern from a modder can never trigger catastrophic backtracking — matching is <code>O(n·m)</code>, never exponential. Compile a pattern once and reuse it; an invalid pattern is an <a href="regex-compile"><code>error value</code></a>, never a crash. Supported: literals, <code>.</code>, classes <code>[...]</code> with ranges/negation and <code>\d \w \s</code> (and their negations), anchors <code>^ $</code>, alternation <code>|</code>, capturing and <code>(?:…)</code> groups, and the quantifiers <code>* + ?</code> and <code>{n,m}</code> in greedy or lazy form. Backreferences and look-around are out of scope for a linear engine.</p><div class="idx-grid"><a class="idx-item" href="regex-compile.html" data-name="Regex.compile" data-tip="Compile a pattern once for reuse; returns an error value (null) if it is invalid."><code>Regex.compile</code><span>Compile a pattern once for reuse; returns an error value (null) if it is invalid.</span></a><a class="idx-item" href="regex-valid.html" data-name="Regex.valid" data-tip="True if the pattern is well-formed (compiles without error)."><code>Regex.valid</code><span>True if the pattern is well-formed (compiles without error).</span></a><a class="idx-item" href="regex-matches.html" data-name="Regex.matches" data-tip="True if the pattern matches anywhere in the text (a search)."><code>Regex.matches</code><span>True if the pattern matches anywhere in the text (a search).</span></a><a class="idx-item" href="regex-test.html" data-name="Regex.test" data-tip="Like matches, but reuses an already-compiled Regex."><code>Regex.test</code><span>Like matches, but reuses an already-compiled Regex.</span></a><a class="idx-item" href="regex-find.html" data-name="Regex.find" data-tip="The first match of the pattern in the text (a Match, or null if none)."><code>Regex.find</code><span>The first match of the pattern in the text (a Match, or null if none).</span></a><a class="idx-item" href="regex-exec.html" data-name="Regex.exec" data-tip="Like find, but with an already-compiled Regex."><code>Regex.exec</code><span>Like find, but with an already-compiled Regex.</span></a><a class="idx-item" href="regex-next.html" data-name="Regex.next" data-tip="The next match at or after byte offset from — the basis of a find-all loop."><code>Regex.next</code><span>The next match at or after byte offset from — the basis of a find-all loop.</span></a><a class="idx-item" href="regex-replace.html" data-name="Regex.replace" data-tip="Replace every match; the replacement expands \0..\9 group references."><code>Regex.replace</code><span>Replace every match; the replacement expands \0..\9 group references.</span></a><a class="idx-item" href="regex-group.html" data-name="Regex.group" data-tip="The text of capture group n (group 0 is the whole match); empty if unset."><code>Regex.group</code><span>The text of capture group n (group 0 is the whole match); empty if unset.</span></a><a class="idx-item" href="regex-group_count.html" data-name="Regex.group_count" data-tip="How many capture groups the match&#x27;s pattern has."><code>Regex.group_count</code><span>How many capture groups the match's pattern has.</span></a><a class="idx-item" href="regex-start.html" data-name="Regex.start" data-tip="The start byte offset of group n, or -1 if it did not participate."><code>Regex.start</code><span>The start byte offset of group n, or -1 if it did not participate.</span></a><a class="idx-item" href="regex-end.html" data-name="Regex.end" data-tip="The end byte offset of group n, or -1 if it did not participate."><code>Regex.end</code><span>The end byte offset of group n, or -1 if it did not participate.</span></a><a class="idx-item" href="regex-ok.html" data-name="Regex.ok" data-tip="True if the match succeeded (the Match is non-null)."><code>Regex.ok</code><span>True if the match succeeded (the Match is non-null).</span></a></div></section><section class="idx-sec" data-sec="grid"><h2 id="grid">Grid</h2><p class="sec-blurb">Tile geometry and pathfinding over the <a href="map"><code>Map</code></a> tilemap. A cell is passable unless it is out of bounds or holds the caller's <code>wall</code> tile (a char code, e.g. <code>'#'</code>), so any impassable glyph works. Everything is integer and deterministic — same map and query reproduce the same path every run. <a href="grid-line"><code>Grid.line</code></a>/<a href="grid-flood"><code>Grid.flood</code></a>/<a href="grid-a_star"><code>Grid.a_star</code></a> return <code>Cell</code> slices (index them with <code>len</code> / <code>[i]</code>; each cell has <code>.x</code> and <code>.y</code>).</p><div class="idx-grid"><a class="idx-item" href="grid-line.html" data-name="Grid.line" data-tip="Every cell a straight line from (x0,y0) to (x1,y1) crosses (Bresenham)."><code>Grid.line</code><span>Every cell a straight line from (x0,y0) to (x1,y1) crosses (Bresenham).</span></a><a class="idx-item" href="grid-blocked.html" data-name="Grid.blocked" data-tip="True if the cell is out of bounds or holds the wall tile."><code>Grid.blocked</code><span>True if the cell is out of bounds or holds the wall tile.</span></a><a class="idx-item" href="grid-line_of_sight.html" data-name="Grid.line_of_sight" data-tip="True if the straight line between two cells crosses no wall."><code>Grid.line_of_sight</code><span>True if the straight line between two cells crosses no wall.</span></a><a class="idx-item" href="grid-flood.html" data-name="Grid.flood" data-tip="Every passable cell reachable from (x,y), 4-connected, in BFS order."><code>Grid.flood</code><span>Every passable cell reachable from (x,y), 4-connected, in BFS order.</span></a><a class="idx-item" href="grid-a_star.html" data-name="Grid.a_star" data-tip="The shortest 4-connected path between two cells (A*), or an empty list."><code>Grid.a_star</code><span>The shortest 4-connected path between two cells (A*), or an empty list.</span></a></div></section><section class="idx-sec" data-sec="anim"><h2 id="anim">Anim</h2><p class="sec-blurb">Spritesheet frame animation off the fixed frame clock. Store an elapsed <code>timer</code> (seconds, a <code>fixed</code>) on a component and each frame ask <a href="anim-frame"><code>Anim.frame</code></a> / <a href="anim-once"><code>Anim.once</code></a> / <a href="anim-pingpong"><code>Anim.pingpong</code></a> which cell to draw; <a href="anim-cell_x"><code>Anim.cell_x</code></a>/<a href="anim-cell_y"><code>Anim.cell_y</code></a> turn a frame index into a source rectangle on the sheet. Everything is integer/fixed and deterministic — the same timer reproduces the same frame every run, so replays and lockstep netcode match exactly. For the ECS engine-owned <code>SpriteAnim</code> component there is also an ergonomic layer: register named clips with <a href="anim-clip"><code>Anim.clip</code></a> and play them by name with <a href="anim-play"><code>Anim.play</code></a>, and arm frame events with <a href="anim-on_frame"><code>Anim.on_frame</code></a> / <a href="anim-fired"><code>Anim.fired</code></a>.</p><div class="idx-grid"><a class="idx-item" href="anim-frame.html" data-name="Anim.frame" data-tip="The looping frame index for an elapsed timer at a given fps."><code>Anim.frame</code><span>The looping frame index for an elapsed timer at a given fps.</span></a><a class="idx-item" href="anim-once.html" data-name="Anim.once" data-tip="A non-looping frame index that clamps on the last frame."><code>Anim.once</code><span>A non-looping frame index that clamps on the last frame.</span></a><a class="idx-item" href="anim-pingpong.html" data-name="Anim.pingpong" data-tip="A frame index that bounces 0..count-1..0 and repeats."><code>Anim.pingpong</code><span>A frame index that bounces 0..count-1..0 and repeats.</span></a><a class="idx-item" href="anim-finished.html" data-name="Anim.finished" data-tip="True once a one-shot clip has run past its last frame."><code>Anim.finished</code><span>True once a one-shot clip has run past its last frame.</span></a><a class="idx-item" href="anim-duration.html" data-name="Anim.duration" data-tip="Seconds for one full cycle of a clip: count / fps."><code>Anim.duration</code><span>Seconds for one full cycle of a clip: count / fps.</span></a><a class="idx-item" href="anim-cell_x.html" data-name="Anim.cell_x" data-tip="The source x (pixels) of a frame on a grid spritesheet."><code>Anim.cell_x</code><span>The source x (pixels) of a frame on a grid spritesheet.</span></a><a class="idx-item" href="anim-cell_y.html" data-name="Anim.cell_y" data-tip="The source y (pixels) of a frame on a grid spritesheet."><code>Anim.cell_y</code><span>The source y (pixels) of a frame on a grid spritesheet.</span></a><a class="idx-item" href="anim-play.html" data-name="Anim.play" data-tip="Start (or restart) a spritesheet clip on an entity in one call."><code>Anim.play</code><span>Start (or restart) a spritesheet clip on an entity in one call.</span></a><a class="idx-item" href="anim-clip.html" data-name="Anim.clip" data-tip="Register a named spritesheet clip so Anim.play can play it by name."><code>Anim.clip</code><span>Register a named spritesheet clip so Anim.play can play it by name.</span></a><a class="idx-item" href="anim-on_frame.html" data-name="Anim.on_frame" data-tip="Arm a frame event — the engine flags the tick a clip lands on this frame."><code>Anim.on_frame</code><span>Arm a frame event — the engine flags the tick a clip lands on this frame.</span></a><a class="idx-item" href="anim-fired.html" data-name="Anim.fired" data-tip="Did the entity&#x27;s clip land on its armed frame event this tick?"><code>Anim.fired</code><span>Did the entity's clip land on its armed frame event this tick?</span></a></div></section><section class="idx-sec" data-sec="motion"><h2 id="motion">Motion</h2><p class="sec-blurb">Ergonomic control of the engine-owned <code>Motion</code> component — the value tween the engine advances each tick (see the ECS engine-systems). <a href="motion-to"><code>Motion.to</code></a> starts a tween on an entity from one value to another over a number of ticks with an easing curve, rewinding it so it plays from the start, instead of setting the component's <code>from</code>/<code>to</code>/<code>dur</code>/<code>ease</code> fields by hand. The tween is integer and deterministic, so motion reproduces exactly under replay and lockstep. For a standalone, sequenced tween not tied to a component, see the fluent <a href="tween"><code>Tween</code></a> handles. Related: <a href="anim"><code>Anim</code></a>, <a href="ease"><code>Ease</code></a>, <a href="tween"><code>Tween</code></a>.</p><div class="idx-grid"><a class="idx-item" href="motion-to.html" data-name="Motion.to" data-tip="Start a value tween on an entity&#x27;s Motion component in one call."><code>Motion.to</code><span>Start a value tween on an entity's Motion component in one call.</span></a></div></section><section class="idx-sec" data-sec="tween"><h2 id="tween">Tween</h2><p class="sec-blurb">Value interpolation over a timeline, off the fixed frame clock. The timeline helpers <a href="tween-progress"><code>Tween.progress</code></a>/<a href="tween-loop"><code>Tween.loop</code></a>/<a href="tween-yoyo"><code>Tween.yoyo</code></a> turn an elapsed <code>timer</code> and a <code>duration</code> into a normalized amount; <a href="tween-ease"><code>Tween.ease</code></a> shapes that amount through an easing curve (shared with <a href="ease"><code>Ease</code></a>); and the typed blends <a href="tween-number"><code>Tween.number</code></a>/<a href="tween-round"><code>Tween.round</code></a>/<a href="tween-point"><code>Tween.point</code></a>/<a href="tween-tint"><code>Tween.tint</code></a> interpolate a <code>fixed</code>, <code>int</code>, <code>Vector</code>, or color. All deterministic fixed-point, so a replay reproduces every eased value exactly. Beyond these pure interpolators there are <strong>fluent handles</strong> the engine advances for you: <a href="tween-to"><code>Tween.to</code></a> starts one and returns a handle, <a href="tween-chain"><code>Tween.chain</code></a> and <a href="tween-delay"><code>Tween.delay</code></a> sequence more segments, and <a href="tween-value"><code>Tween.value</code></a> / <a href="tween-done"><code>Tween.done</code></a> / <a href="tween-parallel"><code>Tween.parallel</code></a> / <a href="tween-stop"><code>Tween.stop</code></a> read and control them.</p><div class="idx-grid"><a class="idx-item" href="tween-progress.html" data-name="Tween.progress" data-tip="A one-shot 0..1 amount, clamped, for timer over duration."><code>Tween.progress</code><span>A one-shot 0..1 amount, clamped, for timer over duration.</span></a><a class="idx-item" href="tween-loop.html" data-name="Tween.loop" data-tip="A repeating 0..1 sawtooth amount over duration."><code>Tween.loop</code><span>A repeating 0..1 sawtooth amount over duration.</span></a><a class="idx-item" href="tween-yoyo.html" data-name="Tween.yoyo" data-tip="A repeating 0..1..0 triangle amount over duration."><code>Tween.yoyo</code><span>A repeating 0..1..0 triangle amount over duration.</span></a><a class="idx-item" href="tween-done.html" data-name="Tween.done" data-tip="True once a one-shot tween&#x27;s timer reaches its duration."><code>Tween.done</code><span>True once a one-shot tween's timer reaches its duration.</span></a><a class="idx-item" href="tween-ease.html" data-name="Tween.ease" data-tip="Shape a 0..1 amount through an easing curve chosen by a literal mode."><code>Tween.ease</code><span>Shape a 0..1 amount through an easing curve chosen by a literal mode.</span></a><a class="idx-item" href="tween-number.html" data-name="Tween.number" data-tip="Linear blend of two fixeds by amount t."><code>Tween.number</code><span>Linear blend of two fixeds by amount t.</span></a><a class="idx-item" href="tween-round.html" data-name="Tween.round" data-tip="Linear blend of two ints by amount t, rounded to the nearest int."><code>Tween.round</code><span>Linear blend of two ints by amount t, rounded to the nearest int.</span></a><a class="idx-item" href="tween-point.html" data-name="Tween.point" data-tip="Component-wise blend of two Vectors by amount t."><code>Tween.point</code><span>Component-wise blend of two Vectors by amount t.</span></a><a class="idx-item" href="tween-tint.html" data-name="Tween.tint" data-tip="Per-channel blend of two colors by amount t."><code>Tween.tint</code><span>Per-channel blend of two colors by amount t.</span></a><a class="idx-item" href="tween-to.html" data-name="Tween.to" data-tip="Start a fluent, engine-advanced tween and return a handle."><code>Tween.to</code><span>Start a fluent, engine-advanced tween and return a handle.</span></a><a class="idx-item" href="tween-chain.html" data-name="Tween.chain" data-tip="Append a tween segment that runs after the handle&#x27;s current queue."><code>Tween.chain</code><span>Append a tween segment that runs after the handle's current queue.</span></a><a class="idx-item" href="tween-delay.html" data-name="Tween.delay" data-tip="Append a pause to a tween handle&#x27;s sequence."><code>Tween.delay</code><span>Append a pause to a tween handle's sequence.</span></a><a class="idx-item" href="tween-value.html" data-name="Tween.value" data-tip="The current value of a fluent tween handle this frame."><code>Tween.value</code><span>The current value of a fluent tween handle this frame.</span></a><a class="idx-item" href="tween-stop.html" data-name="Tween.stop" data-tip="Stop and dispose a tween handle, freezing its value."><code>Tween.stop</code><span>Stop and dispose a tween handle, freezing its value.</span></a><a class="idx-item" href="tween-parallel.html" data-name="Tween.parallel" data-tip="Are two tween handles both finished? — a parallel completion query."><code>Tween.parallel</code><span>Are two tween handles both finished? — a parallel completion query.</span></a></div></section><section class="idx-sec" data-sec="query"><h2 id="query">Query</h2><p class="sec-blurb">Spatial and set queries over the live entities that carry a property, built on the <a href="world"><code>World</code></a> reflection ABI. <a href="query-count"><code>Query.count</code></a> and <a href="query-first"><code>Query.first</code></a> ask how many bearers there are and which is first; <a href="query-nearest"><code>Query.nearest</code></a> and <a href="query-within"><code>Query.within</code></a> add a position — read from a coordinate property's two int fields — to find the closest entity to a point or every entity inside a radius. A property id comes from <a href="world-prop_id"><code>World.prop_id</code></a> and a field id from <a href="world-field_id"><code>World.field_id</code></a>. Everything is integer and deterministic: the same world reproduces the same answers, entity order included, every run. The scan is linear over the entity table — ample for the entity counts Ludic targets — and a game that uses <code>Query.*</code> gets the reflection ABI emitted automatically, no <code>@event</code> required.</p><div class="idx-grid"><a class="idx-item" href="query-count.html" data-name="Query.count" data-tip="How many live entities carry a property."><code>Query.count</code><span>How many live entities carry a property.</span></a><a class="idx-item" href="query-first.html" data-name="Query.first" data-tip="The lowest-id live entity carrying a property, or -1."><code>Query.first</code><span>The lowest-id live entity carrying a property, or -1.</span></a><a class="idx-item" href="query-nearest.html" data-name="Query.nearest" data-tip="The bearer of prop closest to a point, by squared distance."><code>Query.nearest</code><span>The bearer of prop closest to a point, by squared distance.</span></a><a class="idx-item" href="query-within.html" data-name="Query.within" data-tip="Every bearer of prop inside a radius of a point."><code>Query.within</code><span>Every bearer of prop inside a radius of a point.</span></a></div></section><section class="idx-sec" data-sec="reflect"><h2 id="reflect">Reflect</h2><p class="sec-blurb">Runtime reflection over the world schema — inspect properties, fields, and entity state by name and by index. It powers the conveniences game devs consume without writing reflection code: automatic save/load, data-driven tools, and debug/inspector overlays. Enumerate with <a href="reflect-prop_count"><code>Reflect.prop_count</code></a>/<a href="reflect-prop_name"><code>Reflect.prop_name</code></a> and <a href="reflect-field_count"><code>Reflect.field_count</code></a>/<a href="reflect-field_name"><code>Reflect.field_name</code></a>/<a href="reflect-field_type"><code>Reflect.field_type</code></a>; resolve ids with <a href="reflect-prop"><code>Reflect.prop</code></a>/<a href="reflect-field"><code>Reflect.field</code></a>; read and write an entity's fields with <a href="reflect-get"><code>Reflect.get</code></a>/<a href="reflect-set"><code>Reflect.set</code></a>/<a href="reflect-has"><code>Reflect.has</code></a>; and identify its model with <a href="reflect-kind"><code>Reflect.kind</code></a>/<a href="reflect-model"><code>Reflect.model</code></a>. The metadata tables are generated at compile time (the same reflection ABI a foreign mod binds), so introspection is a table walk, not heavy runtime machinery. This is an advanced/tooling surface — most developers get its benefits through built-in features. Related: <a href="world"><code>World</code></a>, <a href="query"><code>Query</code></a>.</p><div class="idx-grid"><a class="idx-item" href="reflect-prop.html" data-name="Reflect.prop" data-tip="The property id for a property name, or -1 if unknown."><code>Reflect.prop</code><span>The property id for a property name, or -1 if unknown.</span></a><a class="idx-item" href="reflect-field.html" data-name="Reflect.field" data-tip="The field id of a named field within a property, or -1."><code>Reflect.field</code><span>The field id of a named field within a property, or -1.</span></a><a class="idx-item" href="reflect-prop_count.html" data-name="Reflect.prop_count" data-tip="How many properties the world schema defines."><code>Reflect.prop_count</code><span>How many properties the world schema defines.</span></a><a class="idx-item" href="reflect-prop_name.html" data-name="Reflect.prop_name" data-tip="The name of the property at an index (or &quot;&quot;)."><code>Reflect.prop_name</code><span>The name of the property at an index (or "").</span></a><a class="idx-item" href="reflect-field_count.html" data-name="Reflect.field_count" data-tip="How many fields a property has."><code>Reflect.field_count</code><span>How many fields a property has.</span></a><a class="idx-item" href="reflect-field_name.html" data-name="Reflect.field_name" data-tip="The name of the field at an index within a property."><code>Reflect.field_name</code><span>The name of the field at an index within a property.</span></a><a class="idx-item" href="reflect-field_type.html" data-name="Reflect.field_type" data-tip="The type name of the field at an index within a property."><code>Reflect.field_type</code><span>The type name of the field at an index within a property.</span></a><a class="idx-item" href="reflect-get.html" data-name="Reflect.get" data-tip="Read one field of an entity by (prop, field) id."><code>Reflect.get</code><span>Read one field of an entity by (prop, field) id.</span></a><a class="idx-item" href="reflect-set.html" data-name="Reflect.set" data-tip="Write one field of an entity by (prop, field) id."><code>Reflect.set</code><span>Write one field of an entity by (prop, field) id.</span></a><a class="idx-item" href="reflect-has.html" data-name="Reflect.has" data-tip="Does an entity carry a property?"><code>Reflect.has</code><span>Does an entity carry a property?</span></a><a class="idx-item" href="reflect-kind.html" data-name="Reflect.kind" data-tip="The model id of an entity."><code>Reflect.kind</code><span>The model id of an entity.</span></a><a class="idx-item" href="reflect-model.html" data-name="Reflect.model" data-tip="The model id for a model name, or -1 if unknown."><code>Reflect.model</code><span>The model id for a model name, or -1 if unknown.</span></a><a class="idx-item" href="reflect-serialize.html" data-name="Reflect.serialize" data-tip="Walk an entity&#x27;s components into a value tree."><code>Reflect.serialize</code><span>Walk an entity's components into a value tree.</span></a><a class="idx-item" href="reflect-apply.html" data-name="Reflect.apply" data-tip="Write a value tree&#x27;s fields back into an entity."><code>Reflect.apply</code><span>Write a value tree's fields back into an entity.</span></a></div></section><section class="idx-sec" data-sec="camera"><h2 id="camera">Camera</h2><p class="sec-blurb">A world-space camera — a draw offset threaded through the render path (the same offset <a href="screen-camera"><code>Screen.camera</code></a> sets). <a href="camera-set"><code>Camera.set</code></a> places it, <a href="camera-follow"><code>Camera.follow</code></a> eases it toward a target, and <a href="camera-shake"><code>Camera.shake</code></a> jitters it from the seeded RNG for impact and explosions. Everything is integer and deterministic — driven off the same seed and inputs, a replay reproduces the exact camera path, shake included. The camera moves everything drawn; reset it to <code>(0, 0)</code> to draw a fixed HUD.</p><div class="idx-grid"><a class="idx-item" href="camera-set.html" data-name="Camera.set" data-tip="Place the camera at a world-space offset."><code>Camera.set</code><span>Place the camera at a world-space offset.</span></a><a class="idx-item" href="camera-follow.html" data-name="Camera.follow" data-tip="Ease the camera toward centring a target point."><code>Camera.follow</code><span>Ease the camera toward centring a target point.</span></a><a class="idx-item" href="camera-shake.html" data-name="Camera.shake" data-tip="Jitter the camera by up to +/- amount pixels (seeded RNG)."><code>Camera.shake</code><span>Jitter the camera by up to +/- amount pixels (seeded RNG).</span></a><a class="idx-item" href="camera-zoom.html" data-name="Camera.zoom" data-tip="Scale the whole view about the screen centre by a Q16.16 factor (1.0 = none)."><code>Camera.zoom</code><span>Scale the whole view about the screen centre by a Q16.16 factor (1.0 = none).</span></a><a class="idx-item" href="camera-shake_for.html" data-name="Camera.shake_for" data-tip="Shake for a number of frames, then stop, with no bookkeeping."><code>Camera.shake_for</code><span>Shake for a number of frames, then stop, with no bookkeeping.</span></a></div></section><section class="idx-sec" data-sec="light"><h2 id="light">Light</h2><p class="sec-blurb">A software 2D light-accumulation pass over the framebuffer, run in a render phase after drawing the scene and before <a href="screen-show"><code>Screen.show</code></a>. <a href="light-ambient"><code>Light.ambient</code></a> multiplies the whole scene toward a tint — the night/cave modulate that darkens everything so lights add mood back on top. <a href="light-point"><code>Light.point</code></a> accumulates a radial glow that falls off with distance and clamps per channel, and <a href="light-occlude"><code>Light.occlude</code></a> registers rectangles that block a light's rays to cast hard shadows (cleared each frame with <a href="light-clear_occluders"><code>Light.clear_occluders</code></a>). Lighting is a rendering concern only — it never touches game state or replays — and it is fully deterministic (integer and Q16.16 fixed), so the same scene lights identically every run and in a headless render, keeping screenshots diffable. Colours are <code>0x00RRGGBB</code>. Beyond the radial core, the pass carries the render-quality tiers: <a href="light-spot"><code>Light.spot</code></a> cones, a <a href="light-falloff"><code>Light.falloff</code></a> exponent, <a href="light-soft"><code>Light.soft</code></a> shadows (penumbra), <a href="light-gel"><code>Light.gel</code></a> colour cookies, normal-mapped surfaces (<a href="light-normal"><code>Light.normal</code></a> + <a href="light-height"><code>Light.height</code></a>) that shade by facing, and a <a href="light-time_of_day"><code>Light.time_of_day</code></a> day/night ramp — every one deterministic. This is the imperative surface; the engine also consumes <code>Light2D</code>/<code>Occluder</code> components automatically (a Light2D may carry optional <code>direction</code>/<code>spread</code>/<code>falloff</code>/<code>softness</code>/<code>gel</code> fields). Related: <a href="screen"><code>Screen</code></a>, <a href="color"><code>Color</code></a>, <a href="camera"><code>Camera</code></a>.</p><div class="idx-grid"><a class="idx-item" href="light-ambient.html" data-name="Light.ambient" data-tip="Multiply the whole scene by a tint — the night/cave modulate."><code>Light.ambient</code><span>Multiply the whole scene by a tint — the night/cave modulate.</span></a><a class="idx-item" href="light-point.html" data-name="Light.point" data-tip="Add a radial glow that falls off with distance."><code>Light.point</code><span>Add a radial glow that falls off with distance.</span></a><a class="idx-item" href="light-occlude.html" data-name="Light.occlude" data-tip="Register a rectangle that blocks light — a hard shadow caster."><code>Light.occlude</code><span>Register a rectangle that blocks light — a hard shadow caster.</span></a><a class="idx-item" href="light-clear_occluders.html" data-name="Light.clear_occluders" data-tip="Forget every occluder — call once per frame before re-registering."><code>Light.clear_occluders</code><span>Forget every occluder — call once per frame before re-registering.</span></a><a class="idx-item" href="light-spot.html" data-name="Light.spot" data-tip="A cone / flashlight light aimed at a direction with a half-angle spread."><code>Light.spot</code><span>A cone / flashlight light aimed at a direction with a half-angle spread.</span></a><a class="idx-item" href="light-falloff.html" data-name="Light.falloff" data-tip="Set the brightness-ramp exponent for later lights (1 linear, 2 quadratic…)."><code>Light.falloff</code><span>Set the brightness-ramp exponent for later lights (1 linear, 2 quadratic…).</span></a><a class="idx-item" href="light-soft.html" data-name="Light.soft" data-tip="Soft shadows — an occluder edge fades through a penumbra of this radius."><code>Light.soft</code><span>Soft shadows — an occluder edge fades through a penumbra of this radius.</span></a><a class="idx-item" href="light-gel.html" data-name="Light.gel" data-tip="A colour cookie — later lights gel from their centre colour to this rim colour."><code>Light.gel</code><span>A colour cookie — later lights gel from their centre colour to this rim colour.</span></a><a class="idx-item" href="light-clear_gel.html" data-name="Light.clear_gel" data-tip="Clear the gel — later lights are a flat single colour again."><code>Light.clear_gel</code><span>Clear the gel — later lights are a flat single colour again.</span></a><a class="idx-item" href="light-normal.html" data-name="Light.normal" data-tip="Stamp a surface normal over a rectangle so lights shade it by facing (N·L)."><code>Light.normal</code><span>Stamp a surface normal over a rectangle so lights shade it by facing (N·L).</span></a><a class="idx-item" href="light-clear_normals.html" data-name="Light.clear_normals" data-tip="Forget every stamped normal — call once per frame before re-stamping."><code>Light.clear_normals</code><span>Forget every stamped normal — call once per frame before re-stamping.</span></a><a class="idx-item" href="light-height.html" data-name="Light.height" data-tip="Set the virtual height of lights above the surface, for normal-map shading."><code>Light.height</code><span>Set the virtual height of lights above the surface, for normal-map shading.</span></a><a class="idx-item" href="light-time_of_day.html" data-name="Light.time_of_day" data-tip="Set the ambient tint from a 0..1 time-of-day — a day/night cycle in one value."><code>Light.time_of_day</code><span>Set the ambient tint from a 0..1 time-of-day — a day/night cycle in one value.</span></a></div></section><section class="idx-sec" data-sec="sprite"><h2 id="sprite">Sprite</h2><p class="sec-blurb">A namespaced spritesheet / atlas API. <a href="sprite-sheet"><code>Sprite.sheet</code></a> loads one image and remembers its cell grid; <a href="sprite-cell"><code>Sprite.cell</code></a> addresses a cell by grid coords and <a href="sprite-cell_span"><code>Sprite.cell_span</code></a> a sprite that spans more than one cell; <a href="sprite-define"><code>Sprite.define</code></a> / <a href="sprite-named"><code>Sprite.named</code></a> name and look up a cell; <a href="sprite-draw"><code>Sprite.draw</code></a> / <a href="sprite-draw_scaled"><code>Sprite.draw_scaled</code></a> blit it (through the camera / zoom / clip). It stands on the variable-size image loader, so a cell can be any size — not just 16x16. (Distinct from the <code>Sprite</code> engine component of the sprite-render system.)</p><div class="idx-grid"><a class="idx-item" href="sprite-sheet.html" data-name="Sprite.sheet" data-tip="Load a spritesheet and remember its cell grid; returns a sheet handle."><code>Sprite.sheet</code><span>Load a spritesheet and remember its cell grid; returns a sheet handle.</span></a><a class="idx-item" href="sprite-cell.html" data-name="Sprite.cell" data-tip="One cell of a sheet, by grid coords; returns a sprite id."><code>Sprite.cell</code><span>One cell of a sheet, by grid coords; returns a sprite id.</span></a><a class="idx-item" href="sprite-cell_span.html" data-name="Sprite.cell_span" data-tip="A sprite spanning cols x rows cells (tall/wide art)."><code>Sprite.cell_span</code><span>A sprite spanning cols x rows cells (tall/wide art).</span></a><a class="idx-item" href="sprite-define.html" data-name="Sprite.define" data-tip="Name a cell for later lookup; returns its sprite id."><code>Sprite.define</code><span>Name a cell for later lookup; returns its sprite id.</span></a><a class="idx-item" href="sprite-named.html" data-name="Sprite.named" data-tip="Look up a named sprite&#x27;s id, or -1."><code>Sprite.named</code><span>Look up a named sprite's id, or -1.</span></a><a class="idx-item" href="sprite-draw.html" data-name="Sprite.draw" data-tip="Blit an atlas sprite at (x, y) through the camera/zoom/clip."><code>Sprite.draw</code><span>Blit an atlas sprite at (x, y) through the camera/zoom/clip.</span></a><a class="idx-item" href="sprite-draw_scaled.html" data-name="Sprite.draw_scaled" data-tip="Blit an atlas sprite scaled by an integer factor."><code>Sprite.draw_scaled</code><span>Blit an atlas sprite scaled by an integer factor.</span></a><a class="idx-item" href="sprite-width.html" data-name="Sprite.width" data-tip="The atlas sprite&#x27;s width in pixels."><code>Sprite.width</code><span>The atlas sprite's width in pixels.</span></a><a class="idx-item" href="sprite-height.html" data-name="Sprite.height" data-tip="The atlas sprite&#x27;s height in pixels."><code>Sprite.height</code><span>The atlas sprite's height in pixels.</span></a><a class="idx-item" href="sprite-strip.html" data-name="Sprite.strip" data-tip="A run of animation frames as consecutive sprite ids."><code>Sprite.strip</code><span>A run of animation frames as consecutive sprite ids.</span></a><a class="idx-item" href="sprite-draw_meter.html" data-name="Sprite.draw_meter" data-tip="A value as a row of full / half / empty icons."><code>Sprite.draw_meter</code><span>A value as a row of full / half / empty icons.</span></a></div></section><section class="idx-sec" data-sec="assets"><h2 id="assets">Assets</h2><p class="sec-blurb">Loading and lookup for whole-file assets, paired with the <a href="sprite-sheet"><code>Sprite.*</code></a> atlas API. <a href="assets-image"><code>Assets.image</code></a> (and its alias <a href="assets-load"><code>Assets.load</code></a>) loads a whole image file as one sprite; <a href="assets-get"><code>Assets.get</code></a> looks a named sprite up.</p><div class="idx-grid"><a class="idx-item" href="assets-image.html" data-name="Assets.image" data-tip="Load a whole image file as one sprite; returns its id."><code>Assets.image</code><span>Load a whole image file as one sprite; returns its id.</span></a><a class="idx-item" href="assets-load.html" data-name="Assets.load" data-tip="Alias of Assets.image."><code>Assets.load</code><span>Alias of Assets.image.</span></a><a class="idx-item" href="assets-get.html" data-name="Assets.get" data-tip="Look up a named sprite&#x27;s id (alias of Sprite.named)."><code>Assets.get</code><span>Look up a named sprite's id (alias of Sprite.named).</span></a><a class="idx-item" href="assets-enqueue.html" data-name="Assets.enqueue" data-tip="Queue a named image file to preload later."><code>Assets.enqueue</code><span>Queue a named image file to preload later.</span></a><a class="idx-item" href="assets-pump.html" data-name="Assets.pump" data-tip="Load up to max queued assets this frame; returns how many it loaded."><code>Assets.pump</code><span>Load up to max queued assets this frame; returns how many it loaded.</span></a><a class="idx-item" href="assets-total.html" data-name="Assets.total" data-tip="How many assets are enqueued."><code>Assets.total</code><span>How many assets are enqueued.</span></a><a class="idx-item" href="assets-loaded.html" data-name="Assets.loaded" data-tip="How many enqueued assets have loaded so far."><code>Assets.loaded</code><span>How many enqueued assets have loaded so far.</span></a><a class="idx-item" href="assets-ready.html" data-name="Assets.ready" data-tip="1 once every enqueued asset has loaded."><code>Assets.ready</code><span>1 once every enqueued asset has loaded.</span></a><a class="idx-item" href="assets-font.html" data-name="Assets.font" data-tip="A font loaded through the preload queue, by name."><code>Assets.font</code><span>A font loaded through the preload queue, by name.</span></a><a class="idx-item" href="assets-progress.html" data-name="Assets.progress" data-tip="Loading progress as a 0..100 percent."><code>Assets.progress</code><span>Loading progress as a 0..100 percent.</span></a><a class="idx-item" href="assets-enqueue_dir.html" data-name="Assets.enqueue_dir" data-tip="Enqueue every file of a directory, named by its file name."><code>Assets.enqueue_dir</code><span>Enqueue every file of a directory, named by its file name.</span></a></div></section><section class="idx-sec" data-sec="testing"><h2 id="testing">Testing</h2><p class="sec-blurb">A built-in testing framework in the spirit of Go's <code>go test</code>: tests live next to the code, run with one command, and report pass/fail — no harness to wire up. A <a href="kw-test"><code>test "name" { … }</code></a> block is discovered automatically and run by a synthetic entry point that prints <code>ok - name</code> or <code>FAIL - name</code> for each, a <code>== N passed, M failed ==</code> summary, and exits non-zero if anything failed (so CI and the <code>bin/ludic</code> runner catch it). Inside a test, the <code>expect</code>, <code>expect_eq</code> and <code>expect_near</code> assertions check a condition and, on failure, print <code>file:line: … failed (got …, want …)</code> and mark the test failed — without aborting, so one run reports every failure. <code>expect_near</code> takes a tolerance, which is what fixed-point and accumulated-integer game math need. Everything is deterministic and compiles to a native binary, so a suite runs in the same C-free toolchain as the rest of Ludic. Coverage instrumentation is a planned follow-up. Related: <a href="kw-function"><code>function</code></a>, <a href="fn-print"><code>print</code></a>.</p><div class="idx-grid"><a class="idx-item" href="kw-test.html" data-name="test" data-tip="A named test block, run automatically with pass/fail reporting."><code>test</code><span>A named test block, run automatically with pass/fail reporting.</span></a></div></section><section class="idx-sec" data-sec="pool"><h2 id="pool">Pool</h2><p class="sec-blurb">Entity-pool statistics. Ludic's ECS is already pool-based: the allocator recycles freed entity slots through a freelist (a <a href="../structure/kw-model"><code>despawn</code></a>ed slot is reused by the next <code>spawn</code> before any new slot is taken), and component storage is fixed per-entity arrays — so spawning and despawning many entities per frame does no per-spawn heap allocation and cannot fragment. <a href="pool-live"><code>Pool.live</code></a> / <a href="pool-free"><code>Pool.free</code></a> / <a href="pool-reserved"><code>Pool.reserved</code></a> / <a href="pool-capacity"><code>Pool.capacity</code></a> read those counters so a bullet-hell or horde game can watch reuse and budget against the cap.</p><div class="idx-grid"><a class="idx-item" href="pool-live.html" data-name="Pool.live" data-tip="How many entities are currently alive."><code>Pool.live</code><span>How many entities are currently alive.</span></a><a class="idx-item" href="pool-free.html" data-name="Pool.free" data-tip="How many freed slots are waiting to be reused."><code>Pool.free</code><span>How many freed slots are waiting to be reused.</span></a><a class="idx-item" href="pool-reserved.html" data-name="Pool.reserved" data-tip="High-water: how many slots have ever been allocated."><code>Pool.reserved</code><span>High-water: how many slots have ever been allocated.</span></a><a class="idx-item" href="pool-capacity.html" data-name="Pool.capacity" data-tip="The maximum number of entities."><code>Pool.capacity</code><span>The maximum number of entities.</span></a></div></section><section class="idx-sec" data-sec="value"><h2 id="value">Value</h2><p class="sec-blurb">A generic, self-describing value tree — the node type reflection serializes into and JSON round-trips through. A node is one of null, <code>int</code>, <code>fixed</code>, <code>bool</code>, <code>str</code>, <code>list</code>, or <code>object</code> (see <a href="value-kind"><code>Value.kind</code></a>). Build one with the constructors (<a href="value-int"><code>Value.int</code></a>, <a href="value-object"><code>Value.object</code></a>, …) and the builders <a href="value-add"><code>Value.add</code></a>/<a href="value-put"><code>Value.put</code></a>; read it with <a href="value-get"><code>Value.get</code></a>/<a href="value-at"><code>Value.at</code></a>/<a href="value-count"><code>Value.count</code></a> and the <code>as_*</code> accessors. Related: <a href="json"><code>Json</code></a>, <a href="reflect"><code>Reflect</code></a>.</p><div class="idx-grid"><a class="idx-item" href="value-null.html" data-name="Value.null" data-tip="An empty null node."><code>Value.null</code><span>An empty null node.</span></a><a class="idx-item" href="value-int.html" data-name="Value.int" data-tip="Wrap an int in a value node."><code>Value.int</code><span>Wrap an int in a value node.</span></a><a class="idx-item" href="value-fixed.html" data-name="Value.fixed" data-tip="Wrap a fixed in a value node."><code>Value.fixed</code><span>Wrap a fixed in a value node.</span></a><a class="idx-item" href="value-bool.html" data-name="Value.bool" data-tip="Wrap a bool in a value node."><code>Value.bool</code><span>Wrap a bool in a value node.</span></a><a class="idx-item" href="value-str.html" data-name="Value.str" data-tip="Wrap a string in a value node."><code>Value.str</code><span>Wrap a string in a value node.</span></a><a class="idx-item" href="value-list.html" data-name="Value.list" data-tip="An empty list node."><code>Value.list</code><span>An empty list node.</span></a><a class="idx-item" href="value-object.html" data-name="Value.object" data-tip="An empty object node."><code>Value.object</code><span>An empty object node.</span></a><a class="idx-item" href="value-add.html" data-name="Value.add" data-tip="Append an item to a list; returns the list."><code>Value.add</code><span>Append an item to a list; returns the list.</span></a><a class="idx-item" href="value-put.html" data-name="Value.put" data-tip="Set a key on an object; returns the object."><code>Value.put</code><span>Set a key on an object; returns the object.</span></a><a class="idx-item" href="value-get.html" data-name="Value.get" data-tip="Read a member of an object by key."><code>Value.get</code><span>Read a member of an object by key.</span></a><a class="idx-item" href="value-has.html" data-name="Value.has" data-tip="Whether an object has a member."><code>Value.has</code><span>Whether an object has a member.</span></a><a class="idx-item" href="value-at.html" data-name="Value.at" data-tip="Read a list item by index."><code>Value.at</code><span>Read a list item by index.</span></a><a class="idx-item" href="value-key_at.html" data-name="Value.key_at" data-tip="The key of an object member by position."><code>Value.key_at</code><span>The key of an object member by position.</span></a><a class="idx-item" href="value-count.html" data-name="Value.count" data-tip="Number of items/members in a list or object."><code>Value.count</code><span>Number of items/members in a list or object.</span></a><a class="idx-item" href="value-kind.html" data-name="Value.kind" data-tip="The node&#x27;s kind tag."><code>Value.kind</code><span>The node's kind tag.</span></a><a class="idx-item" href="value-as_int.html" data-name="Value.as_int" data-tip="Read a scalar node as an int."><code>Value.as_int</code><span>Read a scalar node as an int.</span></a><a class="idx-item" href="value-as_str.html" data-name="Value.as_str" data-tip="Read a str node&#x27;s text."><code>Value.as_str</code><span>Read a str node's text.</span></a></div></section><section class="idx-sec" data-sec="json"><h2 id="json">Json</h2><p class="sec-blurb">The text bridge over the <a href="value"><code>Value</code></a> tree: <a href="json-encode"><code>Json.encode</code></a> turns a value tree into compact, stable JSON text and <a href="json-parse"><code>Json.parse</code></a> reads it back. Together with <a href="reflect-serialize"><code>Reflect.serialize</code></a>/<a href="reflect-apply"><code>Reflect.apply</code></a> this is a one-call, bit-exact save/load for entities, and a diffable on-disk format for tooling. Determinism holds: the same tree always encodes to the same bytes.</p><div class="idx-grid"><a class="idx-item" href="json-encode.html" data-name="Json.encode" data-tip="Serialize a value tree to compact JSON text."><code>Json.encode</code><span>Serialize a value tree to compact JSON text.</span></a><a class="idx-item" href="json-parse.html" data-name="Json.parse" data-tip="Parse JSON text into a value tree."><code>Json.parse</code><span>Parse JSON text into a value tree.</span></a></div></section><section class="idx-sec" data-sec="job"><h2 id="job">Job</h2><p class="sec-blurb">Background work that stays out of the frame. A <code>Job</code> is a future — a handle to a result that lands later. Kick one off with <code>Job.run</code> (a background compute that advances a little each <code>Job.pump</code> and finishes after enough frames, so heavy work never hitches) or <code>Job.defer</code> (a future you resolve yourself with <code>Job.fulfill</code> / <code>Job.fail</code>). Poll it with <code>done</code> / <code>ok</code> / <code>failed</code> / <code>cancelled</code>, read <code>result</code> / <code>error</code>, and always collect on the main thread — a Job must never touch the ECS world directly. The scheduler is deterministic and cooperative, so the same jobs and the same budget reproduce byte-for-byte, every run and every target. For work that should use every core now, <code>Job.parallel_for(count, fn work, ctx)</code> runs <code>work(i, ctx)</code> across a pool of real OS threads and returns when all of it is done; a worker computes on what it was handed and never changes the world. Arguments are positional. Spliced in only when a program mentions <code>Job.*</code>.</p><div class="idx-grid"><a class="idx-item" href="job-defer.html" data-name="Job.defer" data-tip="A future you resolve yourself later."><code>Job.defer</code><span>A future you resolve yourself later.</span></a><a class="idx-item" href="job-run.html" data-name="Job.run" data-tip="Start a background compute job."><code>Job.run</code><span>Start a background compute job.</span></a><a class="idx-item" href="job-fulfill.html" data-name="Job.fulfill" data-tip="Resolve a pending job with a value."><code>Job.fulfill</code><span>Resolve a pending job with a value.</span></a><a class="idx-item" href="job-fail.html" data-name="Job.fail" data-tip="Resolve a pending job as failed."><code>Job.fail</code><span>Resolve a pending job as failed.</span></a><a class="idx-item" href="job-cancel.html" data-name="Job.cancel" data-tip="Cancel a job before it finishes."><code>Job.cancel</code><span>Cancel a job before it finishes.</span></a><a class="idx-item" href="job-pump.html" data-name="Job.pump" data-tip="Advance background jobs; collect results."><code>Job.pump</code><span>Advance background jobs; collect results.</span></a><a class="idx-item" href="job-done.html" data-name="Job.done" data-tip="Has the job resolved (any outcome)?"><code>Job.done</code><span>Has the job resolved (any outcome)?</span></a><a class="idx-item" href="job-ok.html" data-name="Job.ok" data-tip="Did the job succeed?"><code>Job.ok</code><span>Did the job succeed?</span></a><a class="idx-item" href="job-failed.html" data-name="Job.failed" data-tip="Did the job fail?"><code>Job.failed</code><span>Did the job fail?</span></a><a class="idx-item" href="job-cancelled.html" data-name="Job.cancelled" data-tip="Was the job cancelled?"><code>Job.cancelled</code><span>Was the job cancelled?</span></a><a class="idx-item" href="job-result.html" data-name="Job.result" data-tip="The success value of a done job."><code>Job.result</code><span>The success value of a done job.</span></a><a class="idx-item" href="job-error.html" data-name="Job.error" data-tip="The error code of a failed job."><code>Job.error</code><span>The error code of a failed job.</span></a><a class="idx-item" href="job-pending.html" data-name="Job.pending" data-tip="How many jobs are still unresolved."><code>Job.pending</code><span>How many jobs are still unresolved.</span></a><a class="idx-item" href="job-free.html" data-name="Job.free" data-tip="Release a job slot back to the pool."><code>Job.free</code><span>Release a job slot back to the pool.</span></a><a class="idx-item" href="job-parallel_for.html" data-name="Job.parallel_for" data-tip="Run work(i, ctx) for every i in [0, count) across all cores; returns when every call is done."><code>Job.parallel_for</code><span>Run work(i, ctx) for every i in [0, count) across all cores; returns when every call is done.</span></a><a class="idx-item" href="job-is_worker.html" data-name="Job.is_worker" data-tip="True on a Job.parallel_for pool thread, false on the main thread."><code>Job.is_worker</code><span>True on a Job.parallel_for pool thread, false on the main thread.</span></a></div></section><section class="idx-sec" data-sec="promise"><h2 id="promise">Promise</h2><p class="sec-blurb">Combine several <code>Job</code> futures and resolve the group on the main thread. <code>Promise.all</code> succeeds once every member has, <code>Promise.race</code> once the first does; both return an ordinary job handle you poll like any other. For a loading screen, <code>Promise.count_done</code> over the same handles is the bar's numerator and <code>len</code> the denominator, and <code>Promise.all_done</code> is the ready check. Ludic has no closures, so progress is polled rather than chained through a <code>then</code> callback. Build the handle list with <code>new []int</code> + <code>push</code>. Spliced in only when a program mentions <code>Promise.*</code>.</p><div class="idx-grid"><a class="idx-item" href="promise-all.html" data-name="Promise.all" data-tip="Succeeds when every member succeeds."><code>Promise.all</code><span>Succeeds when every member succeeds.</span></a><a class="idx-item" href="promise-race.html" data-name="Promise.race" data-tip="Succeeds when the first member does."><code>Promise.race</code><span>Succeeds when the first member does.</span></a><a class="idx-item" href="promise-count_done.html" data-name="Promise.count_done" data-tip="How many members have resolved."><code>Promise.count_done</code><span>How many members have resolved.</span></a><a class="idx-item" href="promise-all_done.html" data-name="Promise.all_done" data-tip="Have all members resolved?"><code>Promise.all_done</code><span>Have all members resolved?</span></a></div></section><section class="idx-sec" data-sec="sync"><h2 id="sync">Sync</h2><p class="sec-blurb">The advanced, opt-in tier — <strong>here be dragons</strong>. Raw building blocks for engine-level systems that pass data around: a <code>mutex</code> (cooperative lock), an <code>atomic</code> counter (<code>get</code> / <code>set</code> / <code>add</code> / <code>cas</code>) and a bounded <code>channel</code> (<code>send</code> / <code>recv</code> / <code>can_recv</code> / <code>len</code>). On today's single-threaded deterministic runtime these are cooperative — correct, ordered, replayable and impossible to deadlock — and exist so message-passing code reads the same now as it will when a preemptive OS-thread backend lands behind this same API. Beginners never need this; reach for <code>Job.*</code> / <code>Promise.*</code> instead. Spliced in only when a program mentions <code>Sync.*</code>.</p><div class="idx-grid"><a class="idx-item" href="sync-mutex.html" data-name="Sync.mutex" data-tip="Create a cooperative lock."><code>Sync.mutex</code><span>Create a cooperative lock.</span></a><a class="idx-item" href="sync-lock.html" data-name="Sync.lock" data-tip="Take the lock."><code>Sync.lock</code><span>Take the lock.</span></a><a class="idx-item" href="sync-unlock.html" data-name="Sync.unlock" data-tip="Release the lock."><code>Sync.unlock</code><span>Release the lock.</span></a><a class="idx-item" href="sync-try_lock.html" data-name="Sync.try_lock" data-tip="Take the lock only if it is free."><code>Sync.try_lock</code><span>Take the lock only if it is free.</span></a><a class="idx-item" href="sync-atomic.html" data-name="Sync.atomic" data-tip="Create an atomic counter (starts at 0)."><code>Sync.atomic</code><span>Create an atomic counter (starts at 0).</span></a><a class="idx-item" href="sync-get.html" data-name="Sync.get" data-tip="Read the counter."><code>Sync.get</code><span>Read the counter.</span></a><a class="idx-item" href="sync-set.html" data-name="Sync.set" data-tip="Store a value in the counter."><code>Sync.set</code><span>Store a value in the counter.</span></a><a class="idx-item" href="sync-add.html" data-name="Sync.add" data-tip="Add to the counter; return the new value."><code>Sync.add</code><span>Add to the counter; return the new value.</span></a><a class="idx-item" href="sync-cas.html" data-name="Sync.cas" data-tip="Compare-and-set the counter."><code>Sync.cas</code><span>Compare-and-set the counter.</span></a><a class="idx-item" href="sync-channel.html" data-name="Sync.channel" data-tip="Create a bounded int FIFO channel."><code>Sync.channel</code><span>Create a bounded int FIFO channel.</span></a><a class="idx-item" href="sync-send.html" data-name="Sync.send" data-tip="Enqueue a value (false if full)."><code>Sync.send</code><span>Enqueue a value (false if full).</span></a><a class="idx-item" href="sync-recv.html" data-name="Sync.recv" data-tip="Dequeue the oldest value."><code>Sync.recv</code><span>Dequeue the oldest value.</span></a><a class="idx-item" href="sync-can_recv.html" data-name="Sync.can_recv" data-tip="Is there a value waiting?"><code>Sync.can_recv</code><span>Is there a value waiting?</span></a><a class="idx-item" href="sync-len.html" data-name="Sync.len" data-tip="How many values are queued."><code>Sync.len</code><span>How many values are queued.</span></a><a class="idx-item" href="sync-cpu_count.html" data-name="Sync.cpu_count" data-tip="The machine&#x27;s logical cores (1 to 64); Job.parallel_for uses one thread per core."><code>Sync.cpu_count</code><span>The machine's logical cores (1 to 64); Job.parallel_for uses one thread per core.</span></a></div></section><section class="idx-sec" data-sec="xml"><h2 id="xml">Xml</h2><p class="sec-blurb">A minimal, deterministic XML reader for the element/attribute/CDATA subset the native Tiled formats (TMX/TSX/TX) use. <a href="xml-parse"><code>Xml.parse</code></a> turns a document into an element tree; the accessors read a node's <a href="xml-tag"><code>tag</code></a>, <a href="xml-text"><code>text</code></a>, attributes (<a href="xml-attr"><code>Xml.attr</code></a>/<a href="xml-attr_int"><code>Xml.attr_int</code></a>/<a href="xml-has"><code>Xml.has</code></a>) and children (<a href="xml-child"><code>Xml.child</code></a>/<a href="xml-find"><code>Xml.find</code></a>/<a href="xml-count"><code>Xml.count</code></a>). It expands the five predefined entities and numeric character references, skips the <code>&lt;?xml?&gt;</code> prolog, comments and <code>&lt;!DOCTYPE&gt;</code>, and is best-effort rather than validating — the same contract as <a href="json"><code>Json</code></a>. Spliced on demand when a program mentions <code>Xml.*</code>.</p><div class="idx-grid"><a class="idx-item" href="xml-parse.html" data-name="Xml.parse" data-tip="Parse XML text into an element tree."><code>Xml.parse</code><span>Parse XML text into an element tree.</span></a><a class="idx-item" href="xml-tag.html" data-name="Xml.tag" data-tip="The element&#x27;s tag name."><code>Xml.tag</code><span>The element's tag name.</span></a><a class="idx-item" href="xml-text.html" data-name="Xml.text" data-tip="The element&#x27;s character data."><code>Xml.text</code><span>The element's character data.</span></a><a class="idx-item" href="xml-attr.html" data-name="Xml.attr" data-tip="An attribute&#x27;s value by name."><code>Xml.attr</code><span>An attribute's value by name.</span></a><a class="idx-item" href="xml-attr_int.html" data-name="Xml.attr_int" data-tip="An attribute parsed as an integer."><code>Xml.attr_int</code><span>An attribute parsed as an integer.</span></a><a class="idx-item" href="xml-has.html" data-name="Xml.has" data-tip="Whether an attribute is present."><code>Xml.has</code><span>Whether an attribute is present.</span></a><a class="idx-item" href="xml-attr_count.html" data-name="Xml.attr_count" data-tip="How many attributes the element has."><code>Xml.attr_count</code><span>How many attributes the element has.</span></a><a class="idx-item" href="xml-child_count.html" data-name="Xml.child_count" data-tip="How many child elements."><code>Xml.child_count</code><span>How many child elements.</span></a><a class="idx-item" href="xml-child.html" data-name="Xml.child" data-tip="A child element by index."><code>Xml.child</code><span>A child element by index.</span></a><a class="idx-item" href="xml-find.html" data-name="Xml.find" data-tip="The first child with a given tag."><code>Xml.find</code><span>The first child with a given tag.</span></a><a class="idx-item" href="xml-count.html" data-name="Xml.count" data-tip="How many children have a given tag."><code>Xml.count</code><span>How many children have a given tag.</span></a></div></section><section class="idx-sec" data-sec="base64"><h2 id="base64">Base64</h2><p class="sec-blurb">Standard base64 (RFC 4648) — <a href="base64-decode"><code>Base64.decode</code></a> reads base64 text into the bytes it stands for, and <a href="base64-encode"><code>Base64.encode</code></a> is the inverse. The decoder ignores ASCII whitespace, so it reads the newline-wrapped base64 that Tiled writes inside a <code>&lt;data&gt;</code> element; that output then feeds the DEFLATE inflater for zlib/gzip-compressed layer data. Deterministic; spliced on demand when a program mentions <code>Base64.*</code>. (The security-sensitive encoder <a href="crypto-base64"><code>Crypto.base64</code></a> is a separate, hardened path.)</p><div class="idx-grid"><a class="idx-item" href="base64-decode.html" data-name="Base64.decode" data-tip="Decode standard base64 text to bytes."><code>Base64.decode</code><span>Decode standard base64 text to bytes.</span></a><a class="idx-item" href="base64-encode.html" data-name="Base64.encode" data-tip="Encode bytes as standard base64 text."><code>Base64.encode</code><span>Encode bytes as standard base64 text.</span></a></div></section><section class="idx-sec" data-sec="tiled"><h2 id="tiled">Tiled</h2><p class="sec-blurb">Load and draw <a href="https://www.mapeditor.org/">Tiled</a> maps. Both native format families — TMX/TSX/TX (XML) and TMJ/TSJ/TJ (JSON) — read onto one intermediate, a <a href="value"><code>Value</code></a> tree in Tiled's JSON schema, with layer data decoded to a dense GID list; so a CSV <code>.tmx</code> and a base64+zlib <code>.tmj</code> of the same map read identically. <a href="tiled-read"><code>Tiled.read</code></a> returns that intermediate tree for a map file and <a href="tiled-read_tsx"><code>Tiled.read_tsx</code></a> for a tileset file. Spliced on demand when a program mentions <code>Tiled.*</code>, alongside the <a href="xml"><code>Xml</code></a>, <a href="base64"><code>Base64</code></a> and <a href="value"><code>Value</code></a> runtimes it builds on.</p><div class="idx-grid"><a class="idx-item" href="tiled-read.html" data-name="Tiled.read" data-tip="Read a map file into the intermediate value tree."><code>Tiled.read</code><span>Read a map file into the intermediate value tree.</span></a><a class="idx-item" href="tiled-read_tsx.html" data-name="Tiled.read_tsx" data-tip="Read a tileset file into a value object."><code>Tiled.read_tsx</code><span>Read a tileset file into a value object.</span></a><a class="idx-item" href="tiled-load.html" data-name="Tiled.load" data-tip="Load a map file into the runtime map model."><code>Tiled.load</code><span>Load a map file into the runtime map model.</span></a><a class="idx-item" href="tiled-gid.html" data-name="Tiled.gid" data-tip="The raw GID at a cell in a tile layer."><code>Tiled.gid</code><span>The raw GID at a cell in a tile layer.</span></a><a class="idx-item" href="tiled-resolve.html" data-name="Tiled.resolve" data-tip="Decode a GID into tileset, local id and flip flags."><code>Tiled.resolve</code><span>Decode a GID into tileset, local id and flip flags.</span></a><a class="idx-item" href="tiled-width.html" data-name="Tiled.width" data-tip="The map width in tiles."><code>Tiled.width</code><span>The map width in tiles.</span></a><a class="idx-item" href="tiled-height.html" data-name="Tiled.height" data-tip="The map height in tiles."><code>Tiled.height</code><span>The map height in tiles.</span></a><a class="idx-item" href="tiled-layer_count.html" data-name="Tiled.layer_count" data-tip="How many layers the map has."><code>Tiled.layer_count</code><span>How many layers the map has.</span></a><a class="idx-item" href="tiled-layer_name.html" data-name="Tiled.layer_name" data-tip="A layer&#x27;s name by index."><code>Tiled.layer_name</code><span>A layer's name by index.</span></a><a class="idx-item" href="tiled-draw.html" data-name="Tiled.draw" data-tip="Draw every visible tile layer."><code>Tiled.draw</code><span>Draw every visible tile layer.</span></a><a class="idx-item" href="tiled-project.html" data-name="Tiled.project" data-tip="Project a collision layer to the byte tilemap."><code>Tiled.project</code><span>Project a collision layer to the byte tilemap.</span></a><a class="idx-item" href="tiled-tree.html" data-name="Tiled.tree" data-tip="The underlying intermediate value tree."><code>Tiled.tree</code><span>The underlying intermediate value tree.</span></a><a class="idx-item" href="tiled-tile_prop.html" data-name="Tiled.tile_prop" data-tip="Whether a GID&#x27;s tile carries a bool property."><code>Tiled.tile_prop</code><span>Whether a GID's tile carries a bool property.</span></a><a class="idx-item" href="tiled-collide.html" data-name="Tiled.collide" data-tip="Drive collision from per-tile metadata."><code>Tiled.collide</code><span>Drive collision from per-tile metadata.</span></a><a class="idx-item" href="tiled-collision_kind.html" data-name="Tiled.collision_kind" data-tip="Classify a GID&#x27;s collision from its tile metadata."><code>Tiled.collision_kind</code><span>Classify a GID's collision from its tile metadata.</span></a><a class="idx-item" href="tiled-tile_shapes.html" data-name="Tiled.tile_shapes" data-tip="Whether a GID&#x27;s tile has a collision shape."><code>Tiled.tile_shapes</code><span>Whether a GID's tile has a collision shape.</span></a><a class="idx-item" href="tiled-draw_anim.html" data-name="Tiled.draw_anim" data-tip="Draw with animated tiles advanced to a frame."><code>Tiled.draw_anim</code><span>Draw with animated tiles advanced to a frame.</span></a><a class="idx-item" href="tiled-frame_gid.html" data-name="Tiled.frame_gid" data-tip="The current GID of an animated tile at a frame."><code>Tiled.frame_gid</code><span>The current GID of an animated tile at a frame.</span></a><a class="idx-item" href="tiled-animated.html" data-name="Tiled.animated" data-tip="Whether a GID&#x27;s tile is animated."><code>Tiled.animated</code><span>Whether a GID's tile is animated.</span></a><a class="idx-item" href="tiled-object_count.html" data-name="Tiled.object_count" data-tip="How many objects an object layer holds."><code>Tiled.object_count</code><span>How many objects an object layer holds.</span></a><a class="idx-item" href="tiled-object.html" data-name="Tiled.object" data-tip="An object on an object layer by index."><code>Tiled.object</code><span>An object on an object layer by index.</span></a><a class="idx-item" href="tiled-object_shape.html" data-name="Tiled.object_shape" data-tip="Classify an object&#x27;s shape."><code>Tiled.object_shape</code><span>Classify an object's shape.</span></a><a class="idx-item" href="tiled-prop.html" data-name="Tiled.prop" data-tip="A custom property&#x27;s value, with class-default fallback."><code>Tiled.prop</code><span>A custom property's value, with class-default fallback.</span></a><a class="idx-item" href="tiled-prop_int.html" data-name="Tiled.prop_int" data-tip="A custom property parsed as an integer."><code>Tiled.prop_int</code><span>A custom property parsed as an integer.</span></a><a class="idx-item" href="tiled-prop_type.html" data-name="Tiled.prop_type" data-tip="A custom property&#x27;s declared type."><code>Tiled.prop_type</code><span>A custom property's declared type.</span></a><a class="idx-item" href="tiled-load_types.html" data-name="Tiled.load_types" data-tip="Load a project custom-type table."><code>Tiled.load_types</code><span>Load a project custom-type table.</span></a><a class="idx-item" href="tiled-template.html" data-name="Tiled.template" data-tip="Read a template file into an object value."><code>Tiled.template</code><span>Read a template file into an object value.</span></a><a class="idx-item" href="tiled-spawn.html" data-name="Tiled.spawn" data-tip="Spawn a Ludic entity from an object."><code>Tiled.spawn</code><span>Spawn a Ludic entity from an object.</span></a><a class="idx-item" href="tiled-spawn_layer.html" data-name="Tiled.spawn_layer" data-tip="Spawn every object on a layer."><code>Tiled.spawn_layer</code><span>Spawn every object on a layer.</span></a><a class="idx-item" href="tiled-cell_x.html" data-name="Tiled.cell_x" data-tip="The screen x of a tile cell for the map orientation."><code>Tiled.cell_x</code><span>The screen x of a tile cell for the map orientation.</span></a><a class="idx-item" href="tiled-cell_y.html" data-name="Tiled.cell_y" data-tip="The screen y of a tile cell for the map orientation."><code>Tiled.cell_y</code><span>The screen y of a tile cell for the map orientation.</span></a><a class="idx-item" href="tiled-layer_kind.html" data-name="Tiled.layer_kind" data-tip="A layer&#x27;s kind."><code>Tiled.layer_kind</code><span>A layer's kind.</span></a><a class="idx-item" href="tiled-layer_opacity.html" data-name="Tiled.layer_opacity" data-tip="A layer&#x27;s opacity."><code>Tiled.layer_opacity</code><span>A layer's opacity.</span></a><a class="idx-item" href="tiled-layer_tint.html" data-name="Tiled.layer_tint" data-tip="A layer&#x27;s tint colour."><code>Tiled.layer_tint</code><span>A layer's tint colour.</span></a><a class="idx-item" href="tiled-layer_offsetx.html" data-name="Tiled.layer_offsetx" data-tip="A layer&#x27;s horizontal offset."><code>Tiled.layer_offsetx</code><span>A layer's horizontal offset.</span></a><a class="idx-item" href="tiled-layer_offsety.html" data-name="Tiled.layer_offsety" data-tip="A layer&#x27;s vertical offset."><code>Tiled.layer_offsety</code><span>A layer's vertical offset.</span></a><a class="idx-item" href="tiled-world.html" data-name="Tiled.world" data-tip="Read a .world file."><code>Tiled.world</code><span>Read a .world file.</span></a><a class="idx-item" href="tiled-world_count.html" data-name="Tiled.world_count" data-tip="How many maps a world stitches."><code>Tiled.world_count</code><span>How many maps a world stitches.</span></a><a class="idx-item" href="tiled-world_map.html" data-name="Tiled.world_map" data-tip="A world member map by index."><code>Tiled.world_map</code><span>A world member map by index.</span></a></div></section><section class="idx-sec" data-sec="ui"><h2 id="ui">Ui</h2><p class="sec-blurb">The retained-mode menu API over a <code>ui</code> block. <a href="ui-build"><code>Ui.build</code></a> constructs every declared widget tree once (after fonts and skins are loaded); <a href="ui-open"><code>Ui.open</code></a> makes one menu active and <a href="ui-close"><code>Ui.close</code></a> deactivates it; the frame loop ticks navigation on its own, an activation fires the <code>UiClicked</code> event, and <a href="ui-clicked"><code>Ui.clicked</code></a> is the polled form; <a href="ui-set_text"><code>Ui.set_text</code></a> updates a label or button, and <a href="ui-render"><code>Ui.render</code></a> draws the active menu (call it from an <code>Overlay</code> handler so it paints over the world). Every <code>id: Name</code> in a <code>ui</code> block mints a <code>UI_Name</code> handle.</p><div class="idx-grid"><a class="idx-item" href="ui-build.html" data-name="Ui.build" data-tip="Construct every declared ui block (loads skins, measures fonts)."><code>Ui.build</code><span>Construct every declared ui block (loads skins, measures fonts).</span></a><a class="idx-item" href="ui-open.html" data-name="Ui.open" data-tip="Make one menu active and focus its first button."><code>Ui.open</code><span>Make one menu active and focus its first button.</span></a><a class="idx-item" href="ui-close.html" data-name="Ui.close" data-tip="Deactivate the menu: no menu is open."><code>Ui.close</code><span>Deactivate the menu: no menu is open.</span></a><a class="idx-item" href="ui-tick.html" data-name="Ui.tick" data-tip="Advance navigation by one key (the frame loop does this for you)."><code>Ui.tick</code><span>Advance navigation by one key (the frame loop does this for you).</span></a><a class="idx-item" href="ui-clicked.html" data-name="Ui.clicked" data-tip="Was this control activated this frame? (polled form of UiClicked)"><code>Ui.clicked</code><span>Was this control activated this frame? (polled form of UiClicked)</span></a><a class="idx-item" href="ui-set_text.html" data-name="Ui.set_text" data-tip="Replace a label&#x27;s or button&#x27;s text."><code>Ui.set_text</code><span>Replace a label's or button's text.</span></a><a class="idx-item" href="ui-render.html" data-name="Ui.render" data-tip="Draw the active menu."><code>Ui.render</code><span>Draw the active menu.</span></a></div></section><section class="idx-sec" data-sec="file"><h2 id="file">File</h2><p class="sec-blurb">Raw file access over the C stdio calls, for programs that read and write their own formats. <a href="file-open"><code>File.open</code></a> returns a handle (or <code>null</code>), <a href="file-read"><code>File.read</code></a> / <a href="file-write"><code>File.write</code></a> move bytes through a <code>bytes</code> buffer, <a href="file-seek"><code>File.seek</code></a> / <a href="file-tell"><code>File.tell</code></a> position the cursor, and <a href="file-close"><code>File.close</code></a> releases the handle. For text and structured data prefer the higher-level <code>Fs</code>, <code>Json</code> and <code>Prefs</code> APIs.</p><div class="idx-grid"><a class="idx-item" href="file-open.html" data-name="File.open" data-tip="Open a file (fopen); null when it cannot be opened."><code>File.open</code><span>Open a file (fopen); null when it cannot be opened.</span></a><a class="idx-item" href="file-read.html" data-name="File.read" data-tip="Read up to n bytes into a buffer; returns the bytes read."><code>File.read</code><span>Read up to n bytes into a buffer; returns the bytes read.</span></a><a class="idx-item" href="file-write.html" data-name="File.write" data-tip="Write n bytes from a buffer; returns the bytes written."><code>File.write</code><span>Write n bytes from a buffer; returns the bytes written.</span></a><a class="idx-item" href="file-seek.html" data-name="File.seek" data-tip="Move the file cursor (0 start, 1 current, 2 end)."><code>File.seek</code><span>Move the file cursor (0 start, 1 current, 2 end).</span></a><a class="idx-item" href="file-tell.html" data-name="File.tell" data-tip="The cursor position in bytes."><code>File.tell</code><span>The cursor position in bytes.</span></a><a class="idx-item" href="file-close.html" data-name="File.close" data-tip="Close a handle from File.open."><code>File.close</code><span>Close a handle from File.open.</span></a></div></section><section class="idx-sec" data-sec="font"><h2 id="font">Font</h2><p class="sec-blurb">TrueType fonts for the retained UI and for <code>Screen.draw_text</code>-style drawing. <a href="font-load"><code>Font.load</code></a> reads a <code>.ttf</code> / <code>.ttc</code> file and returns a handle that a <code>ui</code> block's <code>font:</code> property or a text call takes.</p><div class="idx-grid"><a class="idx-item" href="font-load.html" data-name="Font.load" data-tip="Load a TrueType font; returns a font handle."><code>Font.load</code><span>Load a TrueType font; returns a font handle.</span></a></div></section><section class="idx-sec" data-sec="fx"><h2 id="fx">Fx</h2><p class="sec-blurb">Engine-owned transient effects. A game asks for a burst of sparks or a floating number and the engine owns the rest: it moves and ages them every Update, draws them every Render after the sprites (through the camera, shake and clip), and drops them when they expire. Nothing is an entity, so a hit effect needs no component, model, handler or draw call. Velocities and lifetimes come from the seeded RNG, so a replay produces the same sparks.</p><div class="idx-grid"><a class="idx-item" href="fx-sparks.html" data-name="Fx.sparks" data-tip="A burst of sparks flying out of a point."><code>Fx.sparks</code><span>A burst of sparks flying out of a point.</span></a><a class="idx-item" href="fx-number.html" data-name="Fx.number" data-tip="A number that floats up from a point and fades."><code>Fx.number</code><span>A number that floats up from a point and fades.</span></a><a class="idx-item" href="fx-clear.html" data-name="Fx.clear" data-tip="Drop every spark and number at once."><code>Fx.clear</code><span>Drop every spark and number at once.</span></a></div></section><section class="idx-sec" data-sec="prefab"><h2 id="prefab">Prefab</h2><p class="sec-blurb">A <code>prefab</code> is a model with preset component fields — <code>prefab Grunt: Creature { Stats { hp: 30 }, Weapon { def_id: 1 } }</code> — spawned with <code>spawn Grunt { Position { x: 40 } }</code>, where the spawn's own fields override the presets. Prefabs chain (<code>prefab Grunt: Foe</code>, where <code>Foe</code> is itself a prefab) so shared presets live once. <code>spawn</code> is also an expression yielding the new entity (<code>let e = spawn Grunt { … }</code>), and <a href="prefab-spawn"><code>Prefab.spawn</code></a> spawns a prefab chosen at runtime by name.</p><div class="idx-grid"><a class="idx-item" href="prefab-spawn.html" data-name="Prefab.spawn" data-tip="Spawn a prefab chosen by name at runtime; -1 if none has that name."><code>Prefab.spawn</code><span>Spawn a prefab chosen by name at runtime; -1 if none has that name.</span></a><a class="idx-item" href="prefab-spawn_at.html" data-name="Prefab.spawn_at" data-tip="Spawn a prefab by name and place it."><code>Prefab.spawn_at</code><span>Spawn a prefab by name and place it.</span></a></div></section><section class="idx-sec" data-sec="app"><h2 id="app">App</h2><p class="sec-blurb">The running application, as distinct from its window. Today that is the boot splash: the runtime raises it before <code>main</code> from the game's asset pack, and <a href="app-splash_hide"><code>App.splash_hide</code></a> takes it down when the game has something to show instead. <a href="app-window_hide"><code>App.window_hide</code></a> and <a href="app-window_show"><code>App.window_show</code></a> take the game's own window off the screen and bring it back without closing it — a launcher stepping aside while the game it started runs.</p><div class="idx-grid"><a class="idx-item" href="app-splash_hide.html" data-name="App.splash_hide" data-tip="Dismiss the boot splash."><code>App.splash_hide</code><span>Dismiss the boot splash.</span></a><a class="idx-item" href="app-set_icon.html" data-name="App.set_icon" data-tip="Set the Dock icon from an image the game ships."><code>App.set_icon</code><span>Set the Dock icon from an image the game ships.</span></a><a class="idx-item" href="app-window_hide.html" data-name="App.window_hide" data-tip="Take the game&#x27;s window off the screen."><code>App.window_hide</code><span>Take the game's window off the screen.</span></a><a class="idx-item" href="app-window_show.html" data-name="App.window_show" data-tip="Bring the game&#x27;s window back."><code>App.window_show</code><span>Bring the game's window back.</span></a></div></section><section class="idx-sec" data-sec="gl"><h2 id="gl">Gl</h2><p class="sec-blurb">OpenGL for Ludic. <code>Gl.*</code> binds the <strong>whole OpenGL 4.1 core API</strong>: every <code>gl*</code> entry point of the platform <code>gl3.h</code> is a method named by its snake case (<code>glBindBuffer</code> → <code>Gl.bind_buffer</code>, <code>glTexImage2D</code> → <code>Gl.tex_image2d</code>, <code>glDrawElementsInstanced</code> → <code>Gl.draw_elements_instanced</code>), with every <code>GL_*</code> constant available as written. Parameters keep the header's names as labels (<code>glVertexAttribPointer</code>'s <code>pointer</code> is called <code>offset</code>, <code>program</code> is <code>prog</code>); <code>GLfloat</code>/<code>GLdouble</code> parameters take <code>fixed</code>, pointer parameters take the raw <code>bytes</code>/<code>words</code> buffers Ludic already has, and 64-bit sizes take <code>long</code> (an <code>int</code> widens). The binding is generated by <code>ludic-dev glgen</code> from the header, with one ABI thunk per entry point.
A context comes from <code>Gl.open(width, height, title)</code>: windowed, an <code>NSOpenGLContext</code> on the game's window at the display's backing resolution (2× on Retina — <code>Gl.width()</code>/<code>Gl.height()</code> are the drawable's pixels); headless, an offscreen context with a framebuffer standing in for the screen (<code>Gl.screen_fbo()</code>), so the same program renders and screenshots under the test harness. <code>Gl.swap()</code> presents, <code>Gl.screenshot(path)</code> writes the screen as a PPM, <code>Gl.check(tag)</code> prints any pending error.
The glue: <code>Gl.program(vs, fs)</code> / <code>Gl.program5(vs, tcs, tes, gs, fs)</code> compile and link (logs on failure), <code>Gl.uniform(prog, name)</code>, <code>Gl.vao()</code>, <code>Gl.buffer()</code>, <code>Gl.texture()</code>, <code>Gl.framebuffer()</code> allocate, and float data is filled from Q16.16 with <code>Gl.floats(n)</code> / <code>Gl.put(buf, i, v)</code> / <code>Gl.bytes_of(n)</code> or from IEEE bits with <code>Gl.put_bits</code>; <code>Gl.f32(v)</code> and <code>Gl.fixed(bits)</code> convert single values. The bare <code>f_add</code>/<code>f_mul</code>/… helpers do IEEE single-precision arithmetic on those bit patterns for programs that want real floats on the CPU.
Using <code>Gl.*</code> links <code>gl.ll</code>, the thunks and <code>OpenGL.framework</code>; a program that does not is byte-identical to before. The <code>ludic.render3d</code> package is a physically based 3D renderer written on this surface (see <code>examples/rendering/smooth.ludic</code> here, and <a href="https://git.workshopsoft.io/workshopsoft/maroon-lake">Maroon Lake</a> for a game built on it).
``<code>ludic
program Triangle {
property Marker { on: int = 1 }
model Anchor { Marker }
var prog: int = 0
var vao: int = 0
handler Boot phase Start {
spawn Anchor {}
if not Gl.open(width: 640, height: 360, title: "GL") { quit() }
prog = Gl.program(vs: "#version 410 core\nvoid main(){ gl_Position = vec4(float(gl_VertexID == 1) * 2.0 - 0.5, float(gl_VertexID == 2) * 2.0 - 0.5, 0.0, 1.0); }\n",
fs: "#version 410 core\nout vec4 o; void main(){ o = vec4(1.0, 0.5, 0.2, 1.0); }\n")
vao = Gl.vao()
}
handler Draw phase Render {
Gl.clear_color(red: 0.1, green: 0.1, blue: 0.15, alpha: 1.0)
Gl.clear(mask: GL_COLOR_BUFFER_BIT)
Gl.use_program(prog: prog)
Gl.bind_vertex_array(array: vao)
Gl.draw_arrays(mode: GL_TRIANGLES, first: 0, count: 3)
Gl.swap()
}
}
</code>``</p><div class="idx-grid"></div></section><section class="idx-sec" data-sec="vk"><h2 id="vk">Vk</h2><p class="sec-blurb">Vulkan for Ludic. <code>Vk.*</code> binds <strong>Vulkan 1.0–1.4</strong> and the extensions a modern renderer is built around — swapchain and HDR colour spaces, ray query and acceleration structures, opacity micromaps, mesh shaders, variable rate shading, memory budget, pipeline libraries, NVIDIA low latency, and portability enumeration for MoltenVK. Every command is a method named by its snake case (<code>vkCreateInstance</code> → <code>Vk.create_instance</code>, <code>vkCmdDrawIndexedIndirectCount</code> → <code>Vk.cmd_draw_indexed_indirect_count</code>), every <code>VK_*</code> constant is available as written, and every struct has its size and field offsets as constants: <code>VkDeviceCreateInfo_sizeof</code>, <code>VkDeviceCreateInfo_queueCreateInfoCount</code>. The binding is generated by <code>ludic-dev vkgen</code> from the Vulkan registry (<code>vk.xml</code>), and every size and offset is checked against the SDK's C headers.
A struct is plain memory filled by field name: <code>bytes(Vk…_sizeof)</code>, <code>Vk.zero(p, n)</code>, then <code>Vk.put_i32</code> / <code>Vk.put_i64</code> / <code>Vk.put_ptr(p, offset, value)</code>, read back with <code>Vk.get_i32</code> / <code>get_i64</code> / <code>get_ptr</code>, and <code>Vk.at(p, offset)</code> for a nested struct or an inline array. Numbers follow the C types: a <code>float</code> is its IEEE bit pattern in an <code>int</code>, and <code>uint64_t</code>, <code>VkDeviceSize</code> and non-dispatchable handles are <code>long</code>. A negative <code>long</code> has to come from a <code>long</code> variable — an <code>int</code> literal passed straight to a <code>long</code> parameter is zero-extended.
The loader is opened <strong>at run time</strong> by <code>Vk.open()</code>, never linked: <code>vulkan-1.dll</code> on Windows, <code>libvulkan.1.dylib</code> (the LunarG loader and MoltenVK) on macOS — beside the executable, in the library paths, or under <code>$VULKAN_SDK</code>. It returns 0 on a machine without Vulkan, and the program carries on; <code>Vk.has(name)</code> says whether one command is there. Using <code>Vk.*</code> links the generated thunks and the loader; a program that does not is unchanged. See <code>examples/rendering/vk_probe.ludic</code> (what a machine's Vulkan can do) and <code>vk_compute.ludic</code> (a Slang compute shader, dispatched and read back).
``<code>ludic
program Probe {
property Marker { on: int = 1 }
model Anchor { Marker }
handler Boot phase Start {
spawn Anchor {}
if Vk.open() == 0 { print("no Vulkan here"); quit() }
let app = bytes(VkApplicationInfo_sizeof)
Vk.zero(app, VkApplicationInfo_sizeof)
Vk.put_i32(app, VkApplicationInfo_sType, VK_STRUCTURE_TYPE_APPLICATION_INFO)
Vk.put_i32(app, VkApplicationInfo_apiVersion, (1 << 22) | (3 << 12))
let ci = bytes(VkInstanceCreateInfo_sizeof)
Vk.zero(ci, VkInstanceCreateInfo_sizeof)
Vk.put_i32(ci, VkInstanceCreateInfo_sType, VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO)
Vk.put_ptr(ci, VkInstanceCreateInfo_pApplicationInfo, app)
let out = bytes(8)
if Vk.create_instance(ci, null, out) == VK_SUCCESS {
print("a Vulkan instance")
Vk.destroy_instance(Vk.get_ptr(out, 0), null)
}
quit()
}
}
</code>``</p><div class="idx-grid"></div></section><section class="idx-sec" data-sec="phases"><h2 id="phases">Phases</h2><p class="sec-blurb"></p><div class="idx-grid"><a class="idx-item" href="phase-start.html" data-name="Start" data-tip="Runs once at boot, before the game loop — the place to set up initial state."><code>Start</code><span>Runs once at boot, before the game loop — the place to set up initial state.</span></a><a class="idx-item" href="phase-input.html" data-name="Input" data-tip="The first per-frame phase — read the keyboard and record the player&#x27;s intent."><code>Input</code><span>The first per-frame phase — read the keyboard and record the player's intent.</span></a><a class="idx-item" href="phase-fixedupdate.html" data-name="FixedUpdate" data-tip="The deterministic simulation step — physics and gameplay meant to be reproducible."><code>FixedUpdate</code><span>The deterministic simulation step — physics and gameplay meant to be reproducible.</span></a><a class="idx-item" href="phase-update.html" data-name="Update" data-tip="The ordinary per-frame game-logic step, run after Input and FixedUpdate."><code>Update</code><span>The ordinary per-frame game-logic step, run after Input and FixedUpdate.</span></a><a class="idx-item" href="phase-lateupdate.html" data-name="LateUpdate" data-tip="Runs each frame after Update and before Render."><code>LateUpdate</code><span>Runs each frame after Update and before Render.</span></a><a class="idx-item" href="phase-render.html" data-name="Render" data-tip="The last per-frame phase — draw the world, then call Screen.show() once."><code>Render</code><span>The last per-frame phase — draw the world, then call Screen.show() once.</span></a><a class="idx-item" href="phase-overlay.html" data-name="Overlay" data-tip="The HUD pass — runs after Render and after every engine-owned drawing system."><code>Overlay</code><span>The HUD pass — runs after Render and after every engine-owned drawing system.</span></a></div></section>
</main>
<script src="ludic-highlight.js"></script>
<script>Ludic.installCards(); Ludic.installSearch();</script>
</body></html>