Skip to content
LevFendi edited this page Mar 3, 2026 · 6 revisions

Syntrax Language

Note: This page may contain inaccuracies. If you spot something wrong or out of date, please let us know on the Discord server.

Prerequisite: Syntrax builds directly on the virtual train builder. If you have not yet unlocked trains and worked through the Trains page, start there first — Syntrax will not make sense without that foundation.

Syntrax is a text language for building rail layouts. It lets you write down what you would otherwise do step by step in the virtual train builder, and adds constructs for repetition and branching that would be tedious to do by hand. It is designed so that knowing the virtual train is enough to reason about a Syntrax program, but it is nonetheless a programming language.

Syntrax has two kinds of users. The first are train power users who write programs to lay out large or complex rail networks. The second are players who receive Syntrax strings from others — from the community or from guides — and paste them into the train builder as custom items. You do not need to write Syntrax to benefit from it.

Syntrax only covers rail layout. Stations and schedules are outside its scope and must be handled in-game.

Note on errors: Syntrax error messages are not particularly helpful. This is a known limitation that cannot be easily improved. When a program fails, check for typos in command names, unmatched brackets, or missing whitespace.

Basic Commands

A Syntrax program is a sequence of words separated by whitespace (spaces or newlines). For example, s s s places three straight rails. Whitespace between words is always required except in chords (see below).

Block comments are supported: /* this is a comment */.

The following commands correspond directly to virtual train actions:

  • l — left
  • s — straight
  • r — right
  • f / flip — flip
  • sigleft, sigright — place a normal signal to the left or right
  • chainleft, chainright — place a chain signal to the left or right

These are shorthand structures that Syntrax adds:

  • l90, r90 — 90-degree left or right turn (equivalent to l x 4 and r x 4)
  • l45, r45 — 45-degree left or right turn (equivalent to l x 2 and r x 2)
  • sig — a pair of regular signals (left and right)
  • chain — a pair of chain signals (left and right)

Repetitions

Repetition takes two forms:

  • word x number — run a single command multiple times: s x 5 places five straight rails
  • [program] x number — run a bracketed sequence multiple times: [l r] x 3 runs l r three times

Repetitions nest: [l x 2] x 2 is the same as l x 4.

The un-bracketed form word x number is only supported for: l, s, r, l45, r45, l90, r90.

Chords

Typing spaces everywhere is slow. Syntrax supports chords — sequences of words written without spaces between them.

Only certain words can appear in a chord: l, s, r, their 45 and 90 variants, f, x, and ;. In a chord, f cannot be spelled as flip and ; cannot be spelled as reset. mark cannot be in a chord, and bracketed subprograms cannot be in a chord.

The semicolon ; in a chord acts as reset (see below). So l90;r90;sx4 is a valid chord meaning: turn left 90, reset, turn right 90, reset, go straight 4.

Heavy use of chords makes programs hard to read. Use them when typing fragments quickly; prefer spaced-out form for programs you want to share or revisit.

Mark and Reset

mark and reset provide a simple bookmark mechanism, most useful for building forks — a main line with branches off it.

  • mark — records the current position and facing direction. Running mark again overwrites the previous mark.
  • reset (or ;) — returns to the last mark without clearing it.

A simple fork, taking a left branch and a right branch before continuing straight:

l90 reset r90 reset s x 4

Two forks stacked:

l90 reset r90 reset s x 4
mark
l90 reset r90 reset s x 4

The same program using chords:

l90;r90;sx4
mark
l90;r90;sx4

Since Syntrax does not restrict what gets repeated, this is also valid:

[
   l90;r90;sx4
   mark
] x 2

This produces the same layout, with an extra mark at the end that has no effect.

Rail Stack: rpush and rpop

mark and reset have a side effect: running mark anywhere in a program overwrites the shared mark. You cannot safely embed one mark/reset sequence inside another — the inner one will clobber the outer one's mark.

rpush and rpop solve this with a proper stack. They behave like mark and reset but push and pop from a stack rather than overwriting a single slot. An inner rpush/rpop pair does not affect the outer one, as long as the inner program runs a balanced number of each.

The sequence rpush program rpop is essentially mark program reset, but nestable.

When to use which:

  • mark/reset — "I am done with this branch forever; go back to the junction"
  • rpush/rpop — "I am done with this substructure but may need to return to an outer context"

Syntrax does not require programs to end with a balanced count of rpush and rpop.

Further Reading

For the complete language reference, see FA Docs: syntrax.md.


See also:

External links:

Clone this wiki locally