Concept
Importing a TrainController project is how most operators create their first RailCommand layout. You upload a .yrrg or .yrl file (up to 50 MB) and RailScanPro builds a brand-new layout from it: the track plan, switchboards, accessories, and — optionally — your roster and trains.
The mental model is derived-not-stored. Your file is parsed into a staged preview; nothing is saved until you press Create. The graph, signal topology, and block wiring are not copied verbatim — they are derived when the layout is created. In between, you review the decoded objects in per-type Transform Tables and resolve anything the decoder flagged instead of guessing. Import is web-only — it always happens in the browser.
On the Blocks table, a block that decodes with no occupancy source at all — no wired contact and no flagman (computed) member — shows a dark territory? suggestion (#1618). Checking it marks the block dark at commit: no detection by design, occupancy not tracked, the dark-neutral display. The importer only ever suggests; it never assumes a block is dark.
The importer also reads the connection labels TrainController draws beside a panel's contacts — the text on an AIU-pin panel, for example. These are not a reviewable Transform Table row: they materialize directly as text cells on the matching switchboard panel when the layout is created, so you see them on the schematic rather than in the review. A label whose decoded position falls outside its panel's grid, or onto a cell something else already occupies, is named in the create-time warnings and left unplaced rather than guessed onto a cell — its text was read correctly, its position was not. Because this decoding happens while the file is parsed, a layout imported before it shipped does not gain the labels by re-deriving: the file has to be imported again.
An address is an attribute of an object, never the reason it exists. The importer carries every switchboard object the file defines whether or not it is wired: a contact with no feedback address imports as an unwired contact (it activates by rules and operations), and the software-only objects (flagmen, counters, virtual contacts, pushbuttons and on/off switches) import as cells of their own kind with their names, positions and the operations TrainController bound to them. Those bindings are carried as documentation to re-author in the rules engine; nothing is executed from them. On the Sensors table the Kind column names each indicator's class. An object the file does not settle (its class could be more than one thing) asks you to pick the kind before you create the layout: on the Sensors table for an indicator (Contact, Flagman, Counter or Virtual contact), on the Controls table for a control (Push button or On/off switch). The choice is always yours; excluding the object is never the only way forward. A flagman or a counter TrainController put on no switchboard page still imports: it becomes a row in your Flagmen or Counters list, and the review says so on the row. Giving it a position adds a cell on a panel; it is not what makes the object exist. Every other kind still needs a position before it can be placed. Nothing is ever given a made-up address.
Counters import with the count your file had stored. A counter TrainController left at its own defaults gets RailCommand's default switching window; a counter whose stored Min / Max / Reset is anything else asks you for its start, switch-on and switch-off values, because how those three map onto RailCommand's window is not something the file settles. Answer them on the Sensors table, or exclude the row. The same question follows the kind you answer: if you settle an unsettled object's class as a counter, its window is asked for too, because nothing in the file typed that object a counter and nothing in it settles its start, switch-on and switch-off values either. Flagmen import with their name and the operations bound to them; their trigger and condition expressions and their memory mode do not decode yet, so those come across empty rather than guessed, and each row says as much.
Label decoding is calibrated on files from current TrainController versions. A file saved by an older one — the import names it as declaring the legacy v9 field marker rather than the modern marker — is read on the marker the file itself declares, but that vintage frames the label records differently, so some or all of its labels may still not decode. The import warns about this on the Warnings tab and reports how many it did decode. On such a file a low or zero label count means undecoded, never that the layout has no labels.
How To
Prerequisites: a TrainController .yrrg/.yrl export (max 50 MB); you own the file or are authorized to import it; you are signed in as the organization that will own the layout.
- From RailCommand Layouts (
/app/railcommand/layouts) click Import from TrainController, or go straight to/app/railcommand/layouts/import/traincontroller. - Drag your file onto the drop zone or use Browse Files. Tick "I own this layout file or am authorized to import it..." (required), then click Analyze File. The file uploads and is parsed server-side; nothing is written yet.
- Review the Transform Tables. One tab per object type: Turnouts, Toggles, Signals, Sensors, Blocks, Routes, Connectors, Controls, plus Roster/Trains when the file carries rolling stock, and Warnings. Each tab badge shows its count. The header's "Also in this file" panel lists decoded facilities (Single Track Lines, Gradients and Shunting Areas: each becomes a Facility row on the new layout; their gradient percentages and endpoints follow in a later release once those fields are decoded) alongside roster/consist/geometry counts. Your TrainController vehicle groups import too, as rolling-stock groups on the layout, keeping their tree and their membership.
- On each tab, use the include checkbox to keep or drop a row, edit fields inline (name, panel, DCC, aspects, speeds), fix a placement with the COL:ROW field, or use Add row to insert one. Panel and per-column filters narrow large tables; the footer flags any included row missing a position. Every count on this screen, tab badges included, is a count of the records decoded from your file, and the screen says so above the tabs: the configuration pages count the cells those records place once you create the layout.
- Resolve the flagged uncertainty. On Roster, each vehicle shows the Connection TrainController records for it: "TC bus 1"/"TC bus 2" for a driven locomotive, "Without connection" for a conventional one. A vehicle whose digital system the decoder could not determine shows a Needs a decision flag with the reason. Only a locomotive holds the create: untick Import for that row to leave it out, and the create unlocks. A flagged car is shown for information and can be left included; it has no decoder to drive, so it imports with no connection and does not gate. On Signals, any head whose facing the decoder could not determine shows a Needs direction flag: pick N/E/S/W (a suggestion is offered) or exclude the row. A signal whose decoded second DCC address breaks the consecutive pairing every TrainController file exhibits (addr2 = addr1 + 1) shows an Address pair? flag: keep the decoded pair (it is real, hand-authored hardware), edit the second address directly (an edit counts as an answer), or clear it to author later in the editor. On Trains, expand a flagged train and set the member's Dir to forward or reversed. A train can also name a vehicle you are not importing, either because the file has no roster row for it or because you left that row out: the member shows a needs a vehicle flag and its This vehicle column offers the two ways to settle it, point it at a vehicle you are importing or import the train without that vehicle. Every one has to be settled before create unlocks, because the alternative is a train quietly imported a vehicle short. Two answers are refused rather than taken quietly. If you leave out every vehicle in a train, the train would import with no vehicles at all: the flag stays, the row says so, and your way out is to point at least one member at a vehicle you are importing or to untick the train. And one vehicle is in one train: pointing two members at the same vehicle, in one train or in two, is refused with the reason, because the alternative is the same vehicle standing in two places at once. A vehicle here is the item itself, not the name a member looked it up under, so two roster rows that turn out to be the same vehicle count as one. The member that was refused is settled in its own This vehicle picker like any other: point it at another vehicle you are importing, or import the train without it. The picker only ever offers vehicles that are still free, which is neither a vehicle another train you are importing has nor one this train's own other members already name. On Controls, each imported turntable shows a Needs review flag for its ring size: set the track count (even 2 to 80 or odd 1 to 49) or exclude the row; the decoded fields are treated as unproven candidates, not defaults. On Turnouts and Signals, an accessory (DCC) address on one digital system that is claimed by included, wired rows of different kinds (a turnout and a signal) shows an Address conflict flag on each of those rows: one decoder output cannot drive both, and the importer never picks which one: change one address, mark one Without Connection, or exclude a row. Several turnout symbols on one address are one machine (a crossover pair) and are never flagged. (Feedback addresses are different again: a contact number is unrelated to an accessory number, and many contacts legitimately share one feedback address as a single detection section, so sensors never raise this flag.) An address the importer refuses is flagged too: a switch or signal whose decoded address sits outside the universal DCC accessory namespace 1 to 2048 (on any digital system), or a sensor whose feedback value sits outside an encoding proven for its digital system (LocoNet General Input and Plain Number, NCE AIU) or on a system with no proven feedback encoding at all (a Märklin Central Station, for example), is never treated as a live address. On Turnouts the same needs-answer picker appears and hand-thrown (manual) is the only importable answer; powered is rejected with the reason. On Signals and Sensors such a row can be re-addressed (proven systems only) or excluded. A resolved row imports with no live address, and the refusal is named in the create-time warnings. A block whose embedded contact is refused imports without that contact, and a block contact TrainController itself left Without Connection is never imported as a live sensor. An NCE contact stored in the Plain Number form is refused outright (Plain Number is a LocoNet-family encoding; NCE feedback is AIU General Input only) and goes live only when you give it a cab (1 to 63) and an input (1 to 14), which converts it to General Input. Clearing Without Connection on a row is judged the same way as any other address going live: if the stored address is outside the range, the change is refused until the address is edited into range in the same step. A signal the importer cannot attach to any track shows an attached to no track flag: TrainController draws a signal in its own cell beside the run it governs and records no association, so the importer adopts the track under the signal or the one cell perpendicular to its facing, and a signal with neither would import drawn on the page protecting nothing. Answer it one of two ways: place it on a track cell (the picker offers the track cells beside it, and the Position field takes any cell), or import it unplaced and marked. Answer the facing first, because the facing decides which sides the importer may adopt from. A mast imported unplaced is still imported: it is drawn where TrainController drew it and carries the flag on the layout's Signals configuration page, so a signal that protects nothing is never silent. The importer flags rather than guesses; every included flag must be cleared before you continue. Import warnings also call out off-page connectors that cannot pair: one with no branch label, or one whose label no other connector shares (a jump that goes nowhere until its mate is drawn). These do not block the import, but they are the list of panel joins your drawing still needs.
- Click Create layout (it shows the object count). The graph, signal topology, and block wiring derive at this step, and the summary reports what materialized. Its turnout and signal lines count the records decoded from your file. The Turnout Configuration and Signal Configuration pages count the cells those records placed on your switchboards, which is a different population, so the summary states both numbers and itemizes every difference between them: toggles, which materialize as on/off switches rather than turnouts; records that share a position with a cell already placed there; records the file gave no switchboard position; hand-thrown switches and turntables, which hold a turnout cell no record produced. A difference the import cannot account for is reported as not itemized rather than being given a reason it did not establish. The DCC addresses are counted and itemized the same way, because they are a population of their own: a switch the file marks Without Connection keeps a stored address the file itself calls stale, so the import never stamps it on a cell, a toggle's address belongs to the on/off switch it materializes in the Control band, and a record that got no cell had nothing to carry an address. That is why a summary can report 231 decoded addresses beside a Turnout Configuration page reading 180 addressed, with every one of the other 51 named. A switch whose stored address reads 0 has no address at all, because DCC accessory address 0 does not exist on any command station: it imports as a turnout like any other, it is not one of the decoded addresses the summary counts, and its cell shows no address until you set one. When some of the file's vehicles did not import, the roster line names how many the file carried beside how many were imported and itemizes the difference, so a small number is explained rather than surprising; when every row in the file imported there is nothing to explain and the line is not shown. A train the import could not build exactly as the file describes it is listed with the vehicles it matched, the vehicle it is short of, and what happened. That screen reports; it cannot take a decision. To create a refused train, import the file again and answer on the Trains tab, or build the train by hand on the Trains page. Each resolved turntable's ring materializes onto its placed cell as the turntable's behavioral config, flagged Needs configuration so you can finish it in the editor.
Troubleshooting
"Invalid file type" or "File size exceeds 50 MB" — Only .yrrg/.yrl files up to 50 MB are accepted. Re-export a fresh project from TrainController.
The file was refused for how far it expands: a .yrrg is a compressed archive, so a small upload can hold an enormous amount of data. The importer reads to a fixed budget and stops, rather than trying to hold whatever a file claims to contain, and a file past that budget is refused by name instead of failing partway through. No real TrainController layout comes close: the largest in our corpus decodes to about 7 MB against a budget of 128 MB. If you see this on a genuine export, the file is worth sending to support rather than re-exporting.
Create layout is disabled with a lock reason — An included signal still needs a facing or attaches to no track, or a train member, turntable, or row still needs attention. Follow the amber "Signals tab" / "Trains tab" / "Controls tab" link, pick a value or exclude the row, then create. The server re-checks these gates on create, so clearing them in the review UI is not optional.
Two of my signals share one mast, but they imported as two separate signals — That is correct and deliberate. TrainController has no multi-head mast: every signal in a TrainController file is a single head, and a two-head mast is drawn there as two separate signal objects in neighbouring cells. There is nothing in the file that says "these two are one mast", so import never guesses at it and never asks you about it — every imported signal arrives on its own. Building the mast is an editing step: select the heads in the layout editor and group them (and ungroup to split one again). A mast in RailCommand is one cell carrying several heads, which is a stronger model than the drawing trick it replaces.
I used to be asked a "Multi-head?" question during import — It is gone. That question assumed TrainController could express a shared mast; it cannot, so the question could never be answered from the file and has been removed rather than given a default. Nothing about your import is being silently decided instead: signals import solo, which is what the file actually says.
A turntable is locked "Needs review" — Its ring size was decoded as an unproven candidate, not confirmed. Set the track count (even 2–80 or odd 1–49) on the Controls tab, or exclude the turntable, to unlock create.
A locomotive is flagged "Needs a decision" on the Roster tab: TrainController records, per vehicle, which digital system drives it. That is what binds an engine to the right command station, so an engine whose system could not be read is never given one at random: untick Import for the row to leave it out, or fix the engine's Connection tab in TrainController and re-export. A car can carry the same flag: the connection is read the same way for every vehicle, so a car whose connection could not be read is flagged too. It never blocks the create, because a car has no decoder to drive and no output binding is written for it. Leave a flagged car included and it imports normally, with no connection and with the uncertain address dropped; only locomotives have to be answered or excluded.
My N-scale engines are on the wrong bus after import: Re-import the file. The import reads each engine's own Connection tab and binds it to the matching TrainController bus on this layout, and a re-import updates the existing assignments in place rather than duplicating them. The summary reports the result per bus ("4 locomotive(s) bound to TC bus 2"). If a bus connection was created by an earlier import and cannot drive locomotives, the re-import switches locomotive control on for it; nothing else about the connection changes, and it stays disabled until you enable it.
A refresh sent me back to Upload — The staged review lives only in your session, so refreshing or leaving discards it. Re-upload to restart — nothing was written to your account.
An included row didn't appear after Create — A row flagged "N need a position" does not materialize until it has a COL:ROW placement.
A sensor is locked with "Imported with block" — Expected: block-embedded contacts import their occupancy with the block, not as standalone sensors.
A contact drawn as its own cell now imports its full addressing — since 2026-08-27 a feedback contact TrainController drew as a separate cell carries its board, its input and its flat LocoNet value onto that cell, so its address shows everywhere the block's other sensors do. Layouts imported before that date pick the addressing up at their next connected sign-in; there is nothing to re-import and nothing to migrate.
Cross-checking a sensor against a BDL168 sheet or JMRI — the Sensors tab's read-only LocoNet column shows the flat address as imported (LS1731), the same number JMRI displays and BDL168 planning sheets print. Address and Input are the same sensor in board/channel form: LS1731 is board 109, input 3. The column shows — for a Plain-Number contact, which has no flat LocoNet address.
My AIU pin panel imported, but none of the pin names came with it — the pin addresses have always imported; what was missing was the labels TrainController draws next to them, and those now decode. If your layout was imported before that shipped, re-import the file — a re-derive cannot add them, because the labels are read while the file is parsed. If a fresh import still brings no labels, check the Warnings tab for the legacy-field-marker warning below: on an older file the labels may not decode yet, and that is a gap in our decoder, not an empty panel.
The import warned about a "legacy v9 field marker" — the file was saved by an older TrainController than the label decode is calibrated on. The decoders read the marker from the file itself, so the file is scanned on its own marker; what is not yet calibrated for that vintage is the record layout the switchboard text and connection labels sit in, so they may come back partly or entirely undecoded. The warning states how many labels decoded. Nothing here is the operator's mistake: report the count as what we read, treat it as undecoded rather than absent, and escalate the file.
A decoded label is missing from the panel after create — check the warnings reported with the create result. Two cases are named there: the label's decoded cell fell outside that panel's grid (the cell offset is not yet decoded for the Symbol/Image label variants, so the text is right but the position is not), or it collided with a cell already on that square. In both cases nothing is guessed onto the canvas; place the label yourself in the layout editor. A label that never appears in either warning may not have decoded at all — that shows up earlier, as a parse warning on the Warnings tab, not with the create result.
A turntable in my file isn't on the Controls tab — If the decoder could not recognize a turntable-shaped object it surfaces it on the Warnings tab rather than dropping it silently. Recognized turntables import per-instance, so a multi-turntable file yields one reviewable row each.
The import summary and the configuration page report different counts (for example 231 turnouts on the summary and 226 on the Turnout Configuration page): both numbers are right, and they count different populations. The summary counts the turnout and signal records decoded from your file; the configuration pages count the cells those records placed on your switchboards. They are not meant to be equal, and the import does not force them: the summary's turnout and signal lines state each count and itemize the difference reason by reason. A toggle is a decoded turnout record that materializes as an on/off switch, so it is never a turnout cell. Two records drawn at one position share one cell. A signal the file gave no switchboard position cannot be placed on a panel at all. In the other direction a hand-thrown switch and a turntable each hold a turnout cell no record produced. Read the itemized line on the create-time summary before treating a difference as a loss; anything the import cannot account for is named not itemized there.
The summary says 231 DCC addresses and the Turnout Configuration page says 180 addressed: same shape, one level down. The summary counts the addresses your file holds; the page counts the addresses standing on cells. A switch TrainController marks Without Connection carries a stored address the file itself treats as stale, so it is imported as a hand-thrown switch with no address, which is also why the page's Manual count rises by the same switches. A toggle's address goes to the on/off switch it materializes in the Control band, and a record that got no cell had nothing to carry an address at all. The create-time summary states both numbers and names each of these groups by count. To make a Without-Connection switch live, clear Without Connection and give it an address in range on the Transform Tables before you create the layout, or set its address on the Turnout Configuration page afterwards. A switch whose stored address reads 0 is counted on neither side: 0 is not a DCC accessory address, so the switch imports with no address, and the Turnout Configuration page's address editor is how you give it one.
The layout imported, but the desktop engine reports 0 signals and 0 turnouts: since 2026-08-28 the import also derives a hardware binding for every addressed element, each on its own decoded digital-system bus (never a guessed slot), which is the shape the operating engine mounts signals and turnouts from. A fresh import needs nothing extra. A layout imported before that date does not need a re-import: applying the bindings step re-reads the same .yrrg and writes only the missing bindings, so post-import edits are kept. Elements TrainController stored as "Without Connection" or with no address stay unbound on purpose; they exist, display, and compute, and can be bound by hand later. A bus whose TrainController driver had no confident RailCommand mapping leaves its elements unbound with a named warning instead of guessing.
Signals imported, but some of them protect nothing: a signal only protects a block when the importer can attach it to the track graph, and TrainController records no association between a drawn signal and the run beside it. Any signal the importer could not attach is flagged at review, and any signal that is attached to no track carries an attached to no track flag on the layout's Signals configuration page, whether the import left it that way or an edit detached it later. Place it on the run it governs in the Layout Editor, or import the file again and place it 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.
Only a few roster items imported, and a train is missing: the summary's roster line says what the file carried and where the rest went (not selected, ambiguous, deleted while the import ran, failed). A train imports only when every vehicle it names is a vehicle you are importing: if one is not, the train is listed as needing review with that vehicle named, and it is not created until you point the member at a vehicle you are importing or import the train without it. Two more cases are listed the same way and refused the same way: a train you left every vehicle out of would import with no vehicles at all, and a vehicle another train in the same import already has cannot be in this one too. The completion screen reports these; it cannot settle them. Import the file again and answer on the Trains tab, or build the train by hand on the Trains page.
Rolling stock is missing — Confirm "Import rolling stock & trains with this layout" is on, or import it later from Asset Management at /app/asset-management/import.
Safety Notes
Import is a web-only authoring action. The ownership attestation is required for legal reasons, and the whole flow runs in the browser — it never actuates hardware. Creating a layout writes a definition; it does not energize track, throw a turnout, or drive a command station. The DCC addresses, aspect counts, and switch times you enter are stored configuration only.
Running the layout happens later on the RailCommand desktop, which presents state and forwards operator intent; the local/UE5 runtime owns all safety-critical execution — interlocking, movement authority, and emergency stop. Correct addresses and facings at import make that runtime correct, but neither the web nor the desktop UI actuates hardware itself.