Building initial worlds
Keep your simulation rules in .hyle files. Put its starting layout in
a .hyleworld file selected by the project manifest, beside main.hyle. New
Studio projects already select initial.hyleworld; edit that file to define the
starting scene. No hand-written dependency manifest is needed. Compile builds
the starting cells and opens them in Studio. The same builder supplies Atlas previews and validates
published projects.
A complete example
Section titled “A complete example”These three files build two copies of a small tank and a procedural platform.
property Matter { density: Float<1.0> [0.0 10.0]; }model Water : Matter;model Wall : Matter;world { dimensions 3; cell Cube; neighborhood VonNeumann; }visual WaterColor for Matter { color { rgba(0.1, 0.6, 0.9, 1.0) } }visual WallColor for Matter { color { rgba(0.6, 0.5, 0.4, 1.0) } }visualize Water with WaterColor;visualize Wall with WallColor;---######WWW######---#...##WWW######use models {Water, Wall};let tank = load "objects/tank.hyleobject";let materials = legend { # = Wall; W = Water { density = 1.5; };};
fn platform(width: Int) -> Object { return object { place Wall in box([0, 0, 0], [width, 5, 1]); };}
place platform(18) at [-1, -1, -1];for x in 0..2 { place tank at [x * 10, 0, 0] with materials;}
// Later occupied placements replace earlier cells.place Water at [2, 1, 2] { set target.density = 2.0; }Dense objects
Section titled “Dense objects”.hyleobject is literal geometry, with one or more equal-size slices.
Columns advance along +X, rows along +Y, and each --- advances +Z.
The first cell is [0, 0, 0]; adding slices never recenters existing coordinates.
Place the object at any world coordinate to move that local origin.
. always means empty. Every grid character occupies exactly one cell. There
are no skip symbols, compression, operations, or implicit padding. Leading and
trailing indentation, blank lines, and whole-line // comments are formatting.
Use dots for actual empty cells. Rows must have equal widths and slices equal
heights. Define the legend in the consuming world. Legend symbols must be single ASCII tokens; ., -, /, quotes and
legend delimiters are reserved. Legend field values are scalar literals.
Empty cells in a placed object leave existing world cells untouched. Use erase
in the world script when you want to remove cells.
World operations
Section titled “World operations”Models and reusable files
Section titled “Models and reusable files”Bind models declared in your physics project, optionally with recipe-local aliases:
use models {Water, Wall as Barrier};Or import a published model directly with its exact revision. This illustrative coordinate must exist in your Atlas installation:
use model "@hyle/Water#4" as Liquid;place Liquid at [0, 0, 0];Loading geometry does not place it. Bind its symbols when placing it:
let tank = load "objects/tank.hyleobject";let materials = legend { # = Wall; W = Water { density = 1.5; };};place tank at [20, 0, 0] with materials;A world file builds an isolated reusable world. Each placed copy has independent cells:
let room = load "rooms/room.hyleworld";place room at [0, 0, 0];Placement and editing
Section titled “Placement and editing”The following snippets assume the model and object names above are in scope.
| Operation | Example |
|---|---|
| Immutable binding | let width = 10; |
| Single cell | place Water at [2, 3, 0]; |
| Region placement | place Water in sphere([0, 0, 0], 5.0); |
| Remove cells | erase box([0, 0, 0], [2, 2, 2]); |
| Translate an object | translate(bind(tank, materials), [0, 0, 2]) |
| Translate a region | translate(region, [0, 0, 2]) |
A placement filter selects cells inside a region. A property body sets the placed cell’s values:
place Water in box([0, 0, 0], [10, 10, 1]) when random(42, position) < 0.2;place Water at [2, 3, 0] { set target.density = 2.0; }Update existing cells without adding new ones:
set Water in sphere([0, 0, 0], 3.0) { set self.density = self.density + 0.1;}Loops, conditions and constructors
Section titled “Loops, conditions and constructors”Loops exclude the upper bound. Conditions choose which construction to perform:
for x in 0..10 { place tank at [x * 10, 0, 0] with materials;}if width > 5 { place tank at [0, 0, 0] with materials;} else { place Water at [0, 0, 0];}An object block groups procedural geometry. A constructor returns an object
parameterized by its arguments:
fn make(height: Int) -> Object { return object { place Wall in box([0, 0, 0], [1, 1, height]); };}let wall = object { place Wall in box([0, 0, 0], [10, 1, 5]); };place wall at [0, 0, 0];place make(8) at [12, 0, 0];Constructor parameters and return values use Int, Float, Bool, Position,
Region, or Object. Declare constructors before calling them. Recursion is
rejected. Objects are immutable values, not classes with inheritance or shared
mutable state.
Boxes use an inclusive minimum and exclusive maximum. Spheres select cell
centers at distance at most their radius. cylinder(start, end, radius) uses
flat end caps. Combine regions with | (union), & (intersection), and -
(difference). Integer vector + and - translate coordinates exactly.
position.x, .y, and .z are available inside placement filters and property
bodies. Property writes can use qualified names such as target.Matter.density.
Writes in one body read the original cell and commit together. Put any local
let bindings before the set assignments.
Scalar expressions support arithmetic, comparisons, boolean operators,
min, max, clamp, abs, sqrt, sin, cos, exp, floor, and ceil.
Trigonometric arguments use radians; these math functions return finite f64 values
or a construction error. They are useful for waves and Gaussian initial fields.
Transcendental results may differ by floating-point roundoff across platforms.
Integer arithmetic stays
integer, including integer division. floor and ceil return floats; coordinates
require integers. random(seed, position) returns a repeatable value in [0,1).
There is no implicit random seed or dependency on iteration order.
Files, simulation, and saving
Section titled “Files, simulation, and saving”Source edits take effect on Compile. Construction is bounded and runs in a separate worker in Studio; changing the source cancels an unfinished build. Failed construction keeps the existing scene. Scripts cannot access the network, filesystem, clock, or simulation solver.
There is no step statement. Running, scrubbing, and painting in the live viewport
operate on the timeline; they do not append commands to your source files.
Use Fork & save to preserve a simulated or manually edited state. That fork
converts the exact viewed cells into captured.hyleworld and selects it as the
world entrypoint. Other hand-written recipes remain available in the project.
No simulation steps are replayed to reconstruct this starting state.
Projects and bakes retain all source files. Standalone objects need a consuming world script and model definitions. Object placement handles, automatic brush-to- source rewriting, rotations, and noise functions are not implemented yet.