Concept
RailCommand gives every layout a set of JMRI-style object tables — one per object type: Signals, Turnouts, Sensors, and Toggles. Each is the authoritative list of that object's addresses and settings for the layout. You reach them per layout at /app/railcommand/layouts/{LayoutId}/signals, /turnouts, /sensors, and /toggles.
The most important idea is what is derived versus authored. Signal aspects are data-driven: the aspect a signal shows is computed from the layout's derived graph topology, not from anything you set by hand. Each signal cell maps to a mast, the mast maps to a derived SignalingRelation naming its protected block(s) and the next block, and block occupancy resolves the aspect — Stop when a protected block is occupied, Approach when the next block is occupied, otherwise Clear. When a signal has no derived relation it stays dark/unknown — it never falls back to a proximity guess. What you author is the signal's identity and wiring: name, style, signaling system, DCC addresses, aspect colours, and — in the Layout Editor — its facing.
A signal's facing is the way its face points. A signal governs the trains coming toward its face and protects the track behind it: a TrainController signal drawn facing west governs eastbound trains. Each signal also belongs to something, never to bare track: a block end, as the signal trains pass to leave the block (Exit) or to enter it (Entry), or a switch it protects (Approach). RailCommand works that out from the drawing: looking the way the signal faces, a block before any switch makes it that block's exit; otherwise, looking the way it protects, a block first makes it that block's entry, with the switch on its face side as its approach; otherwise it approaches the first switch it protects. What a signal belongs to is what its aspect, routes, the CTC board and automation read. And each signal says how its aspects are decided: Imported logic, where the rules imported from TrainController set it green, yellow, white or red exactly as TrainController did (the default for a TrainController import, so the layout behaves as it did): the signal is looked at all the time, its states with rules in TrainController's order (green, red, yellow, white), and the first whose rule holds is shown; when none holds it shows its state with no rule (usually red), also as soon as a rule stops holding; a signal whose every state has a rule shows red when none holds, or RailCommand signalling, where RailCommand works the aspects out as described above and the signal's imported rules are kept but not run.
Every block has its own exit signal at each end. Each block whose two ends the drawing orders has its own exit signal at each end, the signal a train leaving the block by that end passes. TrainController has no entrance signals, so neither does RailCommand. The block's own signals follow RailCommand's internal rules: RailCommand signalling works their aspect out from the blocks and route beyond them. A signal you placed yourself is never taken over: it follows its imported logic or the rule set you chose for it, and the block's own exit signal stands beside it. Where the block's own signal has no hardware it is virtual. "Virtual" only means the signal has no hardware connected: it is an ordinary signal in every other way, and rules, routes, the CTC board and automation use it like any other signal. Give it hardware (an address) and it stops being virtual. Virtual signals are drawn in RailCommand's own small symbol, a hollow dashed ring beside the track with the aspect as a small inner lamp, so no one mistakes one for a real signal, and each person can hide them. On the desktop, each block end's entry and exit can be locked, as in TrainController: a locked entry keeps at Stop the exit signal of every block whose route runs over that entrance, until the lock is released, and no route, dispatch or automation may bring a train into the block at that end; a locked exit holds that end's exit signal at Stop and refuses leaving by that end.
Which RailCommand computers get them. Virtual signals, the routes that start or end at one, and block end locks reach RailCommand on a computer only when it runs a version that reads them (rule schema 25). An older version downloads the layout without them, laid out as it was before block end signals, so its blocks, starting positions and routes between real signals work as they did.
How To
- Open Signal Configuration at
/app/railcommand/layouts/{LayoutId}/signals. The summary cards show Signal Cells, Configured, Bound To Hardware, Missing DCC Address, and By Type. Signal Cells counts the signal cells standing on this layout's switchboard panels, which is not the same population as the decoded signal records a TrainController import reports: a record the file gave no switchboard position can never be a cell here, and the import summary itemizes every difference between the two counts. Every object table names its population the same way (Signal Cells, Turnout Cells, Sensor Cells and Block Sensors, Toggle Cells), each says the cells it counts are those placed on a switchboard panel, and each carries a line under its summary cards saying what the import counts instead. The Sensor table is the one whose population is not cells alone: a sensor a block owns has no contact cell of its own, so that table names both halves and counts them apart. Use the Status, Type, Style, and Connection filters to narrow the list. Configured is layout knowledge (address and aspects on the cell); Bound To Hardware is what the operating engine will actually drive (a live hardware binding exists). An addressed signal with no binding shows an Unbound chip: re-import the layout, or apply the import's bindings step, to create the missing bindings. A signal that is on a panel but attached to no track shows an attached to no track chip: it is drawn and its head can be driven, but it protects no block, because nothing on the graph tells it which run it governs. Place it on the run it governs in the Layout Editor, or import the file again and answer the question on the Signals tab. The chip is a live reading of the layout rather than a record of the import: it clears once the signal attaches, and it appears on any signal that is detached later.
A "to become an indicator" chip appears: at import you told RailScanPro this signal is a lamp on your fascia, not a track signal. A layout imported now converts it into an indicator lamp as the layout is created, so the chip is left only on a layout imported before indicators existed. There a banner above the table offers Convert marked signals, which turns every marked signal, and only those, into an indicator lamp (step 10 says what that does). There is nothing to attach.
2. Click a signal row to open its inline editor. Set Signal Name, Signal Style (Color Light, Searchlight, Position, Semaphore, Dwarf), and Signaling System (Default, NORAC, GCOR, CROR, and the European/Japanese presets).
3. Enter DCC Address 1, and DCC Address 2 for 4-aspect signals; tick Stop Restricted Mode if the signal drops to restricting rather than stop. Since 2026-08-29 the Layout Editor's signal dialog also shows the Aspect outputs grid: per aspect, which Thrown or Closed state each of the two addresses is set to. TrainController imports fill it automatically; author it here for hand-built signals. A connected multi-aspect signal whose map is missing, short, or names Address 2 with no second address stored shows a Map incomplete chip on the Signal Configuration list until it is finished.
4. Under Signal Aspects, set each aspect's colour and name. Restricting shown as picks how this mast displays a Restricting indication — the system default, flashing red, red over yellow, or flashing yellow (railroads legitimately use any of these; heads without a lunar lamp, like the SE8c's, can never show steady lunar). Choosing a non-default forks a tenant mast type carrying the choice. Use the Aspect Output Map (Index / Name / Addr 1 State / Addr 2 State) to name the decoded head wiring so the colour ordering matches the physical head. Click Save.
5. For Turnouts / Sensors / Toggles, open the matching table and click Add: the add-at-position form takes Panel, Type, Position (row/column), typed as TrainController shows it (row/column, counting from 1, for example 23/02), Orientation (0-7), Name, and DCC Address (turnouts also take a Normal route, which starts at Not set). Placement is collision-guarded and re-derives topology. On the Turnout table the Addressed card counts the addresses standing on cells, not the addresses a file held: a switch TrainController marks Without Connection keeps its stored address in the file and is imported with none, because that stored value is stale by the file's own account.
A turnout's Ownership says who directs it: the Dispatcher or Local crews. Left on Auto, it is worked out from the blocks the turnout serves, meaning the first block along each of its legs, past any plain track, stopping at the next turnout: when every one of them is local track (yard, siding, industry and the like) the turnout is local, and when any is on the main it is the dispatcher's. The Auto choice names the answer, for example Auto (Local, from the blocks it serves). When the blocks disagree, for example a switch between the main and a yard lead, or local track beside a block with no class, the turnout goes to the dispatcher and shows Set ownership in the table and under the Ownership box: choose Dispatcher or Local and it stops asking. A block drawn over a turnout no longer decides anything, because no block spans a turnout.
A turnout's normal position, switch time, motor type (Pulse mode) and Send OFF after the switch time are kept in one place, so the Turnouts table, the Layout Editor's turnout dialog and what RailCommand downloads always agree. The normal position is one of the positions the turnout's type has (Straight or Diverging; for a three-way Straight, Left or Right; for a single slip Straight A, Straight B or Crossed; for a double slip Straight A, Straight B, Crossed A or Crossed B), or Not set: a turnout imported from TrainController shows Not set until you choose, because RailCommand never guesses a position. Send OFF is only for coil decoders with no timer of their own. By default RailCommand sends one command for each turnout and no OFF; in the dialog a turnout can follow its connection's setting (set on Hardware Slots) or choose Yes or No. Saving a row in the Turnouts table writes its addresses and its hardware binding together, as the dialog does: the save is refused while an operating session holds the layout, and an address needs the hardware slot it rides.
Switch maintenance (the tile beside Turnouts on the layout's Objects tab, /app/railcommand/layouts/{LayoutId}/switch-maintenance) lists every switch by the throws counted since it was last serviced, with its lifetime throws, its last throw and who serviced it last and when. RailCommand on the desktop counts each throw it confirmed, in simulation and on the railroad (the command station's feedback reported the new position, the switch time passed after the command station took a command for a switch with no feedback, or a crew member reported throwing a hand-thrown switch), and sends the counts to the website when a simulation ends or it lets go of the railroad, and every five minutes while you are signed in with the layout open; sending them again never counts a throw twice. Set an Alert level for one switch or for every switch, and a switch whose count reaches it is marked due. After you service a switch press Serviced, then Yes, serviced: its count goes back to 0 and the page records who serviced it and when; its lifetime count keeps going. The same throws also reach Backshop's turnout counters, so a Backshop threshold on a switch sees them too.
6. Wrong aspect family on an imported signal? Reassign it in place — no delete-and-replace. On the web, open the signal on the Layout Editor canvas and set Element type / Aspect Family on the General tab. On the desktop, select the signal and use Aspect family in the cell-properties panel. The cell keeps its identity: name, DCC addresses, authored facing, and its physical head configuration all ride through (lamp count is not aspect count). Only the family-scoped parts re-gate — the stale aspect rows are cleared and re-prepopulated from the new family's preset, and the mast re-binds to the new family's default mast type. A signal carrying a specialized or regional type (searchlight, dwarf, position-light, semaphore, Ks, Hp0/Hp1/Hp2, or a British/French/Dutch/Italian/Japanese/Swiss type) is named as itself in the picker, and converting it to a plain 2/3/4-aspect family asks for confirmation first, because that replaces the specialized type and the glyph drawn on the switchboard.
7. Author signal facing in the Layout Editor: the Face points picker sets the way the signal's face points, and offers the real ports of the signal's graph node, each named by the direction it leaves the cell on your screen (Left, Upper right), with a turnout's legs keeping their role beside it (Normal (right), Reverse (upper right)). The signal protects the track on the other side. On a compact signal the stem points the way the face points.
See and change what each signal belongs to on the Signal Configuration page. The summary counts signals by what they belong to (exit of a block, entry to a block, approach to a switch, not attached) and lists the signal bridges, rows of signals across parallel tracks facing one way. The Belongs to column says it in words ("Exit of Seneca Track 08, left end"; "Entry to Canyon Run Track 04, right end; approached from East Yard Lead Switch, from its points"). Open a signal's row to change it: pick one of the block ends and switches drawn within about 20 cells and choose Use this, and the layout derives again so the signal protects what you chose. Your choice is marked Your choice and stays when the drawing changes; Work it out from the drawing again hands it back. On a two-head mast approaching a switch from its points, the top head speaks for the leg to the right and the lower head for the leg to the left. That includes a two-head exit signal whose far side runs straight into a switch's points: its Belongs to words name that switch too ("Exit of Seneca Track 08, left end; leading into Seneca East Switch").
Choose how each signal's aspects are decided in the Logic column: Imported logic or RailCommand signalling. Tick signals and use Selected: imported logic or Selected: RailCommand signalling, or change every signal at once with the All signals buttons. Moving a signal to RailCommand signalling keeps its imported rules on the layout, not run, with the reason on each rule; moving it back runs them again unless something else holds them.
See the virtual signals on the Signal Configuration page: a Virtual chip on the row, Virtual (no hardware) where the address would be, and a Hardware filter that separates virtual signals from signals with hardware. A block end's signal names its place in words, for example Block end slot: Siding 2 left end entry; it stays at that end, so its row offers no other attachment. Entering a DCC address (or an SE8c or accessory binding) on a virtual signal makes it a signal with hardware. In the Layout Editor, Show virtual signals in the display options shows or hides them for you only; hidden virtual signals are not drawn and cannot be clicked, and they keep working.
Lock a block end on the desktop, as TrainController does: right-click the block on the operating diagram or the CTC board and lock its entry or its exit at either end, with a reason if you like; the lock shows at that end with who set it, why and when, and the same menu releases it. Rules can test a lock (
BLOCK_ENTRY_LOCKED,BLOCK_EXIT_LOCKED) and set or release it (LockBlockEntry, UnlockBlockEntry, LockBlockExit, UnlockBlockExit). A lock stays through restarts and sessions until someone releases it.Driving heads from a Digitrax SE8c? Use SE8c Board Setup (button in the Signal Configuration header, or
/app/railcommand/layouts/{LayoutId}/se8c-setup) before binding: it walks the board's factory reset, Board ID, head wiring types, and the required 4th-aspect-Dark option switches — automated (RailCommand sends every switch command through the running operating session's layout host) or guided (it shows the exact throttle commands). The final step drives the test mast and asks what you see; the Dark answer is the proof the board is configured for RailCommand.Record where a signal or a turnout stands with its Milepost: on the signal's inline editor here and on the General tab of the Layout Editor's signal dialog, and for a turnout (Milepost at the points, where its switch points are) on the Turnouts table's inline editor and the General tab of the turnout dialog. A milepost is up to three letters, then miles from 0 to 99999.99 with no more than two decimal places: type
123.4,B123.4orMP 123.4and it is stored asB123.40. Text that is not a milepost is refused where you typed it and nothing is saved in its place; an empty box clears it. A siding has no milepost record of its own: the turnouts at its two ends carry it. The Mileposts page (/app/railcommand/layouts/{LayoutId}/mileposts) sets every signal's and turnout's milepost at once, in track order. A signal's milepost reaches RailCommand with the signal's mast, and a turnout's with the turnout, the next time the layout is downloaded; a signal or turnout without one downloads exactly as before.Turn a signal into an indicator when it is a lamp on your fascia rather than a track signal: open its row and choose Turn into indicator, or right-click it in the Layout Editor. The cell becomes an indicator lamp. It keeps its name, position and DCC addresses; its output hardware becomes the lamp's output, with each aspect mapped to the colour it shows, steady or flashing (a TrainController 4-aspect head becomes green, red, yellow and flashing yellow in its aspect order and starts red; change the map in the lamp's settings in the Layout Editor); and it leaves signalling entirely, so it is no longer calculated, interlocked, routed or reviewed as an orphan mast, and it leaves this table. Rules drive it on the desktop: SetSwitch turns it off or on (a coloured lamp comes on in the colour it starts in) and SWITCH_ON reads it, SetSignalAspect names it with a colour (for example Red, Yellow or Flashing yellow), Off, one of its aspect names, or Calculated to give it back, and a condition reads the colour it shows from the switch's
lamp(for exampleANY s IN switches WHERE s.lamp == 'Yellow'). Turn into signal in the lamp's settings, or on its right-click menu, reverses the conversion, and saving the layout derives its mast again.
Troubleshooting
A signal shows dark or "unknown": it has no derived SignalingRelation. Confirm it is placed on the graph and that the track behind its face (the side it protects) leads to a real block or switch; re-open the Layout Editor so topology re-derives.
A signal protects the wrong side: check the way its face points (the stem on a compact signal): it protects the track behind its face. Then check Belongs to on the Signal Configuration page, and choose the right block end or switch there if the drawing misleads the rule.
Every signal, switch or sensor is listed twice: this was a layout with a CTC board, before 2026-09-27. The Signals, Turnouts and Sensors tables, and a signal's attachments, now read the layout's track plan only, so each device is listed once; a CTC board that draws the same devices adds no rows. The Toggles table still lists the levers and buttons drawn on a CTC board, because those are controls of their own.
An "attached to no track" chip appears: this signal is on a panel but attached to nothing on the track graph, so it protects no block. TrainController records no association between a drawn signal and the run beside it, so an import attaches a signal to the track under it or the one cell perpendicular to its facing, and one with neither is imported flagged rather than quietly. Move it onto the run it governs in the Layout Editor, then re-open the editor so topology re-derives. The chip is a live reading of the layout rather than a record of the import: it clears once the signal attaches, and it appears on any signal that is detached later.
A block has no exit signals of its own: its drawing gives it no two ends (it branches, or has one end only), so RailCommand cannot tell its ends apart. Draw it with two ends, or split it, and save; its two signals appear.
Two signals hold one block end part: two real signals both play, for example, the exit at a block's left end. Both stay and the page warns on each; choose another block end for one of them in its row.
Virtual signals crowd the drawing: turn off Show virtual signals in the Layout Editor's display options. It is your own view; the signals keep working and other people still see them.
"Missing DCC Address" count is red — One or more signals have no DCC Address 1. Open each and set the address, or mark it as a dispatcher-driven signal.
A "No conn" badge appears — That signal (or turnout) is Without connection: driven by the dispatcher group, not a LocoNet/DCC address. That is expected for virtual dispatcher objects.
Add-at-position rejects the cell — The position is occupied, or it is not written as row/column (23/02). Pick an empty cell; the form will not overwrite an existing object.
The Sensor table's count looks far too high, or shows hundreds of sensors "without connection". The sensor table counts feedback contacts plus the sensors each block owns; a block's occupancy marker is a block, not a sensor, and is counted in the Block Editor at /app/railcommand/layouts/{LayoutId}/blocks. A sensor a block owns is listed under its block's name, because TrainController decodes it as a block member and it has no contact cell of its own; its row links to that block's Block Detail panel, where its kind and its address (board, input and mode) are set, and where it can instead be placed on a contact cell of its own. Where the imported block sat on its own occupancy contact, the block took that contact's cell and its address: the detector is still listed, under its block, and its address is corrected on that row. Contacts whose occupancy is computed (a virtual contact, or a block's flagman) are shown as Computed with no address: they have nothing to wire, so they are never counted as missing a connection. A block member the import could not resolve to a contact or a flagman (for example a virtual contact kept in a block) is listed under its block with no address and its TrainController ID, and counts as not connected until it is resolved; so does a contact TrainController saved with no connection, which stays one of its block's sensors.
An imported signal has the wrong number of aspects — Reassign its aspect family in place rather than deleting and re-placing it (step 6). Deleting would mint a new cell and lose the anchors, facing, and wiring that hang off the old one.
A signal from a TrainController import shows as a lamp beside another signal, with no base of its own: that is a stacked head: TrainController draws a second head on the same physical mast with a stackable image in the cell beside the mast, and the import keeps it as the mast's second head. It keeps its own name, addresses and aspects, stays where TrainController drew it, and protects what its mast protects. Its lamp sits to the far side of its cell with a mast line joining the mast's cell; the mast's own cell keeps its lamp, mast line and base. Ungroup the mast in the Layout Editor to make it a signal of its own again.
The aspect family will not change on a head-extension cell — Head extensions belong to a multi-head mast, so the family is a property of the anchor. Change it on the anchor signal, or ungroup the mast first.
A specialized or regional signal type is not in the family picker — The picker offers the three plain families plus the type the cell already has. It converts away from a specialized type (with a confirmation), but it cannot convert into one: to change a signal to a regional type, place that type from the palette.
Safety Notes
These pages are authoring surfaces only. Editing a signal, adding a turnout, or naming an aspect updates the layout's stored configuration; it does not move hardware and does not change what a live signal is showing. During an operating session the local/UE5 runtime owns aspect resolution and any physical signal output — the web and the Avalonia desktop present state and forward intent, they never actuate hardware. Because aspects are derived from topology, an incorrect facing or a mis-placed block can change what a signal protects. Treat facing and block placement as safety-relevant: verify them in the editor before an operating session, and never hand-edit an aspect to "fix" a wrong indication — correct the topology instead.