Using the partial builder
This tool is not part of rlife, and amling doesn't support it. It was written with an AI model. If a search set up with it misbehaves, don't take the builder's files to the LLSSS thread. First rebuild the input with rlife's own tools (mgp-tool ingest-1gp or @yolo_1gp) or by hand, and report only what still happens then.
The builder turns a spaceship partial into a start file for rlife's LLSSS searches, and writes the command to run it. It does not run the search. You run the command yourself, then use the Stitcher to join the search output back onto the partial.
1. Setup
You need a built copy of rlife. The commands assume you run them from rlife/target/release, with the start file (and any constraint files) saved in that same folder. If you keep the files elsewhere, put the full path in the command wherever a file name appears, including inside the quotes of a --constraint argument.
The online builder adds .txt to saved files. Remove it before running rlife. The offline copy saves files with their real names.
2. Pasting a partial
Set the rule first. B/S notation works, with Hensel letters if needed (B3/S23-q4i).
The pattern box accepts:
- An RLE with every phase side by side. This is the most reliable input. The phases are split on the empty columns between them.
- An RLE of one generation. The builder simulates the other phases. Only use this if the partial is valid for a full period.
- A grid copied from an LLSSS log, such as a "Thinnest partial" block, or a LifeHistory RLE of one. Phases can be side by side or stacked.
If a phase has a wide gap inside it, the automatic split can cut it in two. Set Phases in RLE to the period to stop that.
The builder works out the speed, the direction of travel, the symmetry, and which side is torn. The stats panel shows what it found. Check it before using the output: a wrong period or symmetry makes the start file useless.
3. Choosing a mode
Each mode keeps the valid part of the partial and sets up a different search for the rest. Some modes need a mirror-symmetric partial and are greyed out otherwise. Hover over a greyed-out mode to see why.
Extend and let it widen
A recentering search (llsss-recentering) from the last valid row. The back is free to grow sideways. Use this for an ordinary partial you want to continue. Symmetric partials get --left-edge odd or even so the search stays symmetric.
Extend at a fixed width
A fixed-board search (llsss). The torn back is replaced by a block of ? cells, and the board is the pattern plus Extra columns. The width never changes, which keeps memory predictable, but anything that needs to be wider than the board is never found. Symmetry is not enforced in this mode.
Rebuild the outer branch
For a symmetric partial whose back has split into an inner piece near the axis and an outer leg. Everything up to the tear is kept, the inner piece is carried along unchanged, and only the outer leg is searched. This follows amling's --fuzzy-left-edge recipe. The mode refuses if the inner piece itself breaks the rule, since it can't be carried unchanged.
Split into branches, axis constraint
For a symmetric partial where the two halves should separate into branches. The file keeps everything up to the tear. Two constraint files tell rlife to keep the axis column empty in every row it adds, so the branches can come within one column of the axis but never touch it.
This mode writes three files: the start file and NAME-pre.cstr and NAME-axis.cstr. The pre file covers the rows already in the start file, since rlife applies constraints to those as well. The axis file is one row that rlife repeats for every new row.
If the axis column is still alive in the last rows kept, the builder warns you. The search then has to kill those cells first, and it may find nothing. Try an earlier partial or plain recentering.
Split into branches, ? gap
Like the axis constraint mode, but stricter: the columns next to the axis stay empty, enough of them that the two halves never touch. The builder looks for the deepest stretch where those columns are already empty for at least a full period, cuts the partial there, and fills the rows after the cut with ?. It also writes the same pair of constraint files, which hold the gap open for the whole search, and uses a mirror edge (--left-edge odd or even).
Because it has to cut where the gap already exists, this mode usually keeps fewer rows than the axis constraint mode. On the 3c/7 test partial it keeps 13 rows against 19.
Start files made with this mode before 28 September 2026 had no constraint files and no mirror edge, so the gap only held inside the ? rows. Rebuild those files.
How wide is the gap? Two file columns, for either symmetry. With odd symmetry, file column 0 is the axis, and a cell in column k is 2k from its mirror image. With even symmetry the axis falls between file columns 0 and 1, which are copies of each other, so the distance is 2k − 1. Either way the two sides stop sharing a neighbour once the branch starts at column 2.
That is the narrowest gap that keeps the halves independent, so the branch can't be given more room toward the axis without letting the two sides touch. If you want them to interact, that is a different search: axis-constraint mode allows the branch within one column of the axis, and plain recentering puts no limit on it at all. With One branch only there is no other half, so the gap is a preference rather than a requirement.
One branch, or the symmetric whole
Both branch modes have two checkboxes.
- One branch only (asymmetric). Off (the default): the symmetric whole. The mirror edge (
--left-edge oddoreven) makes rlife extend both halves as mirror images. On: one branch alone. The mirror edge is dropped and rlife uses its default edge,pic(bg), which continues the picture and then the background. The other half is ignored, so the halves need not match. This is amling's "plan A" (his 27 September post). - Keep the columns beside the axis empty (constraint files). On by default for the symmetric whole, off by default for one branch alone. When it is off there are no constraint files and the command is amling's plain one, for example
rlife llsss-recentering 2c5-f2b 2c5.in 11. The branch can then come back toward the axis. Tick it if you want the branch kept off the axis anyway.
Why the default differs: for the symmetric whole the empty columns keep the two mirrored branches from touching. For one branch there is no other half, so the columns are only a preference, and in the thread the constraint was flagged as leaving almost no room near the axis and the aim was for the branch to be allowed back. The file itself still holds the two columns empty for the rows it writes, so the cut is unchanged.
This is not amling's method for 232P7H3V0-style branches. His command for the 3c/7 partial in that thread was rlife llsss-recentering 3c7-f2b p1.in --left-pad 09 --fuzzy-left-edge --right-pad 1 07, on a file cut narrowly around one branch. The fuzzy edge lets the search decide, at each depth, whether to include the sibling branch in the window. He also said that a mirror edge makes you pay for the sibling. The mirror edge plus constraint files in this mode and in axis-constraint mode were added by an AI model, not taken from him. Only Rebuild the outer branch writes --fuzzy-left-edge, and it needs an inner piece beside the outer one.
4. Options
- Search order
- Front to back, side to side, or back to front. The default detects it from which side of the partial is torn. Set it by hand only if the detection is wrong.
- Symmetry
- Detect, or ignore. Ignoring treats the partial as full width and asymmetric.
- Extra columns
- Room beyond the pattern. Fixed-board and outer-branch files start at 4. The ? gap file starts at 0: amling said an earlier file (12 root columns) was wider than he would have cut it (8), and 8 is the width of that pattern with no extra. He described the two as approximately the same search, with more spines deduplicating in the narrower one and features that key on unique roots showing less. Once you type a value it is kept when you change modes. Recentering widens by itself and doesn't use this.
- Back off (W rows)
- Keeps fewer rows of the partial, so the search redoes the last part. Use it when the rows just before the tear are valid but lead nowhere.
- File name
- The name of the start file. Constraint files are named after it (
p1.ingivesp1-pre.cstrandp1-axis.cstr).
5. Reading the result
The stats panel lists what was detected and how much of the partial was kept. Warnings appear above it in colour. Read them: most of them mean the search will fail or find something you don't want.
The preview shows the start file. Live and dead cells are what the search starts from, ? cells are left for the search to fill, and root labels are the letters on the first row that rlife uses to line up columns.
The output tabs:
- Command. The command to run, with the file names filled in.
- Start file. The file in rlife's grid format. One section per phase, separated by
|. - UWI view. The same cells in rlife's internal row order. Useful only for checking the geometry.
- Constraint files. Only in the two branch modes.
Each file has its own Save button. Browsers block several downloads from one click, so the builder no longer tries to save them together. Copy puts the current tab's text on the clipboard.
6. Running rlife
A typical command from the ? gap mode:
export LLSSS_HALT_ON_ENDS=true
./rlife llsss-recentering --rule 'B3/S23' --left-edge odd \
--constraint 'grid("p1-pre.cstr", grid_loop("p1-axis.cstr"))' \
3c7-f2b p1.in 08 > out.txt
LLSSS_HALT_ON_ENDS=truestops the search at the first step that finds a complete ship. Without it, the search keeps going after a result.- The single quotes around the
--constraintargument matter. They pass the double-quoted file names through the shell unchanged. The oldergrid:FILE:NEXTform no longer parses. 3c7-f2bis the geometry: speed and search order.- The last number is
mid_steps. The builder sets it from the width of the partial, and uses 8 for the ? gap mode. > out.txtsends the log to a file. rlife flushes every line, sotail -f out.txtshows it live.
Memory
Memory use grows as the search goes deeper. In the logs tested so far, each step briefly needed about two and a half times the memory shown between steps. If that peak doesn't fit in RAM, the machine swaps and a step that took seconds takes many minutes.
Add --pre-reify-autochoke with a size, written as 8GB (not 8G). Setting it to about a third of your RAM keeps the peak in memory. When the search would go over the limit, autochoke drops the partials furthest between the two edges, which in practice means the widest ones. Too low a limit throws away the partials you want. At 1GB on the 3c/7 partial, autochoke cut the width to 15 to 18 columns, about the width of the ship itself.
7. Reading the log
Each step ends with two lines:
Results: 0 normal Completed w_pos 245: 3.52 GB [+4.63%], 14.60752225s [-7.41%]
Results counts complete ships found so far. The completed line gives the memory and time for the step, and the change from the previous one.
After that come three pictures:
- Unique. Cells that are the same in every surviving partial.
?means the partials disagree. - Thinnest partial. The narrowest surviving partial. It is not the one closest to finishing.
- Random[ish] partial. One surviving partial picked at random.
The search is breadth first. Every partial is extended by one W row per step, and none is favoured. A branch that looks easy to finish counts only when a full neighbourhood's worth of rows at its back is empty in every phase and across the whole width. A back that has almost died out in one phase column usually still has cells in the other phases' rows.
Lines starting Autochoke SEMSV1 mean the memory limit was reached. The numbers after "rejecting" and "keeping" are the width cut-off it chose for that step.
Long pauses with no output
rlife writes every log line as soon as it happens, so a pause means it is working on something that doesn't log. Look at the last line before the pause:
- A memory line right after the expansion, before
Results. This is the end check, and it means a complete ship was found. Up to 29 September 2026 this hung forever: a bug amling introduced in early September (15957ed5125c) and fixed in 5c48bb53850d, which amling believes can only hang on a result, not hide one. If a search stalls here, update rlife and rerun. On a fixed copy the check printsEnd [thinnest] ...and the ship, thenResults: 1 normal, thenHalting (LLSSS_HALT_ON_ENDS). To check what a stalled run is doing, get its process id withps -axo pid,%cpu,comm | grep rlife, then runsample PID 5: the bug shows asrun_ssm_filter_endsandcol_join, though a slow but working end check would look the same. Autochoke SEMSV1 running. Autochoke is scanning every column to decide what to drop. This grows with memory use.- Anywhere, with the machine slow. Probably swapping. Check swap use in Activity Monitor or with
top -o mem, and lower the autochoke limit.
8. After a result
Open the Stitcher: stitcher.html in the llsss-tools zip, next to this file, or online. Paste the start file you searched from, and the search output: the log text works as it is, [INFO] prefixes included. If the output holds several grids, pick the one you want (the End [thinnest] block for a result). The Stitcher lines the two up, joins them, mirrors symmetric halves back to full width, and checks the result against the rule.
9. Problems
ParseError: UnrecognizedTokenon--constraint- Old constraint syntax, or missing quotes. Use the command from the Command tab as it is.
- A mode is greyed out
- Hover over it for the reason. Most often the partial isn't mirror-symmetric, or has no stretch where the columns next to the axis are empty.
- Only one file downloads
- Each file has its own Save button. Click each one.
- The search finds nothing for a long time
- Check whether autochoke is cutting the width below what the ship needs, and whether a constraint rules out the shape you expect. A branch search, for example, cannot find a ship whose back crosses the axis after the cut.
- The partials keep getting wider
- Recentering has no width limit of its own. Branches that drift sideways leave a trail that never ends and take most of the memory. A memory limit with autochoke, or a fixed-width search, stops this at the cost of excluding wider ships.