Skip to content

release: v0.12.0 - #306

Merged
octalide merged 35 commits into
mainfrom
dev
Oct 4, 2026
Merged

octalide merged 35 commits into
mainfrom
dev

Conversation

@octalide

@octalide octalide commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Integration merge for 0.12.0.

A fill is a shape (square or circle around the view's centre, or the
bounded grid) and a density, carried by the randomize command and
remembered in the app so the randomize key repeats it. The selection
fill takes the remembered density too. A new target is one variant and
one arm of fill.bounds and fill.covers.
The frame button and the F key frame the fill randomize would make now: its
shape around the view's centre at its size, the grid, or the selection. The
centre floors for negative coordinates. The panel puts density and the
randomize button above the size table so they stay in view.
feat(#290): randomize fills a shape, a region or the selection
A region is bands of rows holding the same spans, so a rectangle costs one
band however large. Shapes combine by adding, subtracting or intersecting,
regions apart from one another are named in reading order, and a chunk is
classed inside, outside or across the edge with the bits of one across it.
The pool holds a world inside a boundary. No chunk wholly outside it is
allocated, each slot keeps a block word and, only across the edge, a mask,
and writes outside are dropped. The CPU and GPU steps hold cells outside at
zero, a word operation a row for 1-bit rules, and read the edge as each
family's open edge: dead or zero, no-flux for reaction-diffusion, and the
flipped edge of a B0 rule along a kept rim. The stages reach the domain by
an address in the meta head, so a world without a boundary adds no memory
and no dispatch.

A plane is now the boundary of its rectangle, the old dead-edge link path
gone, while grids that wrap stay link topologies. The simulation sets and
combines a boundary (set_bound, shape_bound), and HashLife refuses a drawn
one with the reason.
feat(#287): a world's domain as drawn boundary regions
A region is one more fill shape, resolved against the world's boundary
(sim.bound) with the cell a click chose. The grid fill of a bounded world
fills every region of its boundary, and nothing outside it. The panel gains a
Region target that arms a click to choose, and F frames the chosen region.
feat(#290): randomize fills a chosen boundary region or every region
Snapshot holds the drawn boundary with a whole copy, and restore puts it
back before the cells, so undo, redo and reset return the domain with the
world. sim counts the boundary's changes (reframed) for a copy to know it is
stale, and clear_in kills the cells a region holds.
cellar.domain combines a shape into the boundary, a shape added to a world
without one becoming it, and moves, deletes or clears the region holding a
cell, a move carrying the region's cells with it. Removing the bounds takes a
drawn boundary away, and a grid that replaces one says so.
cellar.gesture draws a rectangle, ellipse, polygon or freehand brush as a
region for any tool to take. The bounds tool combines it into the boundary,
picks a region to move, delete or clear, and keeps dragging grids and their
edges. cellar.shade draws outside the domain shaded and outlines its edge.
# Conflicts:
#	src/exec.mach
#	src/game.mach
#	src/sim.mach
A wall layer joins the layer contract: one bit a cell, after the word's
layers and ahead of the view layers, single-buffered, and held only while
the world holds a wall. A slot's edge word says whether its chunk holds
one, so only walled chunks read it and none is ever freed. Every family
keeps a wall cell's word through a step on the CPU and in each GPU stage,
flipped where the background flips. Edits pass walls by unless they draw
or erase them, fills keep them, snapshots and the journal carry them, the
draw shows them in a colour of their own, and HashLife refuses them.
The Wall tool (L) draws a stroke of walls, or a rectangle or an ellipse
dragged out, each wall dead or holding the pen's state, a value under a
continuous rule. The eraser takes walls away. A stroke, a shape and an
erase are each one undo step.
…e target

The app finds the chosen region (sim.chosen_cell) in the boundary as last
seen, and the domain's draw fills and outlines it in a colour of its own
while randomize fills the chosen region.
feat(#288): tools to draw and combine boundaries
… its walls

A cell edit goes up through the edit stage marked as one (layout.EDIT_GUARD),
which drops it where its cell is a wall of a walled chunk, word-wide layers
included where the pool holds walls. A pull replays a pending cell edit only
where the cell read back is no wall, and brings every walled bit level. An
erase written blind clears the walls it covers and leaves its chunk's walled
bit set until the host's cells are the world's again. Painting a walled world
on the GPU reads nothing back.
A polygon takes a corner a press and is drawn once a press lands on its first
corner again, its edges shown as it is clicked out; Escape drops it. The
shape is boundary.polygon's, as the rectangle and the ellipse are its own.
The Wall button pushed the toolbar onto a second row at 1280 pixels. The two
shape tools, which draw with the same gestures, now share one button named
for the one it takes up; a press on it while it is the tool takes up the
other, and W and L take each up directly. The wall tool's gestures, what its
walls hold and the brush's radius move to a Walls section of the world
panel, beside the boundary's.
feat(#289): walls with a fixed state or value
…dit take them

boundary.append builds a region a band at a time, refusing one that does not
fit. sim gains fill_walled and fill_walls for a load that brings walls,
walled_chunks for a save, read_walls for a copy, and edit_as so one edit
writes a pattern's walls and its other cells alike.
…alls

A pattern marks its walls and the cells inside the boundary it carries.
place writes its walls as walls holding their cells' states or words, and
stamp gives the world its boundary over the pattern's box first.

The format contract gains walls: a format that records them emits them ahead
of every cell, a sink takes them (Sink.walls) and a source offers them
(Source.walls). RLW writes them after its body as a [walls] section of o and
b runs, which a reader that knows none stops before. A pattern with walls
defaults to RLW.
…ellar 7

A cellar 7 file's header says whether its cells are states or words, and its
body holds a bound record, a band a line, and a wall record for each walled
chunk, a row of 16 hex digits a line. A wall holds its cell's word, so dead
walls cost a bit each. Every older file loads as a world without a boundary
or walls, dropping a drawn boundary the world had. A boundary or walls the
world cannot take load without them, and the load says so.
…lection when asked

A copy carries the selection's walls, and a cut takes them with its cells.
With the selection's "Copy keeps the boundary" on, it carries the boundary
inside the selection too, which a stamp gives the world over its box. The
clipboard remembers such a copy beside its RLE, so that text pastes back
whole, while text another program wrote pastes as its cells. A stamp that
cannot take its boundary or walls says why.
WorldSource lists the walled chunks as it is made, ordered as its cell runs
are, widens its extent to every wall, a dead one too, and offers them as runs
of their own (Source.walls), so cellar run --out x.rlw and every other
whole-world export to RLW keeps them.
feat(#291): worlds and patterns carry boundaries and walls
@octalide
octalide merged commit 603de81 into main Oct 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant