Traluno▶ Play Traluno

A Desk, Not a Menu

Traluno's model railway control desk is levers, toggles and buttons on the front of the table, worked with the mouse. What it cost, and what it taught.

Traluno's control desk along the front of the table, seen from the left: an ammeter, three throttle levers, four toggles, four push buttons and a red emergency stop, with the layout behind it.

Every setting that changes how the layout runs could have been a slider in a panel: train speed, clock speed, which way the yard turnout lies, whether the street lamps are lit. Panels are quick to build, easy to lay out, and legible at any resolution.

Instead, Traluno has a model railway control desk along the front edge of the table. It has three throttle levers you drag (MAIN LINE, YARD and CLOCK), four toggles you flip (YARD ROUTE, SIDING, LAMPS and ROOM LIGHT), four push buttons (HORN, NIGHT, CRANE and WHEEL), a latching EMERGENCY STOP, and an ammeter. All of it is worked with the mouse, and none of it is a menu.

Why a control desk

Because a model railway has one.

That is the whole justification and it is stronger than it sounds. The subject matter of this game is not "trains". It is "a model railway in a hobby room", and a model railway's controller is a physical object that sits on the baseboard where the operator stands. Replacing it with a menu would be modelling the trains and not the hobby.

There is a second reason that only became clear later. A lever has a position, and the position is visible from across the room. You can see at a glance that the clock is running fast because the CLOCK lever is forward, and the ammeter, labelled MAIN LINE LOAD, repeats the main-line lever on a dial. A slider inside a panel you have closed communicates nothing at all, and it is closed most of the time. (What the clock and the lamps then do to the layout is in when the lights come on.)

Close-up of the MAIN LINE LOAD ammeter and the MAIN LINE, YARD and CLOCK levers, each with a scale from 0 to 10 beside its slot; CLOCK is pushed fully forward and YARD is at zero
Three throttles at three settings: CLOCK pushed all the way forward, YARD at zero.

What it cost

Hit testing. A button in a UI layer is a rectangle in screen space. A button on the desk is a small three-dimensional object seen at an angle, and clicking it means casting a ray from the cursor into the scene and finding what it hit. That machinery had to exist anyway for placing track, so this was cheaper than it might have been. What the desk added is a hit box for every control, invisible and a good deal bigger than the control itself, so a click that only nearly lands on a toggle's thin bat still throws it.

Drag semantics in three dimensions. A lever moves along an arc, and the mouse moves in a plane. Mapping one to the other so that dragging feels like pulling the lever, rather than like solving a geometry problem, took several attempts. The version that stayed throws the geometry away: a lever follows the cursor's vertical travel on screen, up for faster, about 110 pixels from 0 to 10, whatever angle you are looking from.

Legibility at distance. In the Stand view, which puts you at the front edge of the table at standing height (the table post explains why), the desk is at the bottom of the screen, small, and seen at a shallow angle. It leans back towards you by about twenty degrees, like a lectern, which helps, and there is a Desk view in the Views menu for when you want it close. Neither helps enough to print anything small. Colour has to work at that size too: the emergency stop once sat on a wide gold plate, and from across the desk the whole control read yellow, when an emergency stop has to read red. It now has a thin collar.

The whole layout seen from the front edge of the table at standing height, with only the tops of the desk's controls showing along the bottom of the picture
From the Stand view the desk is a strip along the bottom edge of the screen.

Labels in front, always

The single most useful thing learned from building it: a label behind a control is invisible.

The levers stand about seven and a half units above the desk face. Anything printed on the desk behind a lever is hidden by the lever itself from every viewpoint above the desk, which is every viewpoint a standing player has. This is not a subtle occlusion issue. The label is simply gone, at all times, and it took an embarrassingly long time to work out why the labels I had definitely drawn were not there.

So labels go in front of their control, between the control and the player. The nameplates run in a row in front of the controls, the lever scales are printed beside each slot where nothing stands, and each toggle's indicator lamp is set in front of its bat so the bat never hides it. The brand and the zone captions are on the front apron: TRALUNO CONTROL DESK at the left, then "THROTTLES · push forward for faster", "TURNOUTS & LIGHTS" and "ACTIONS" over their sections. It is the one face of the desk that nothing can stand in front of, and the desk's tilt turns it up towards you.

A low view along the desk: the nameplates MAIN LINE LOAD, MAIN LINE, YARD and CLOCK sit in front of their controls, and the apron below reads TRALUNO CONTROL DESK and THROTTLES · push forward for faster
Each nameplate sits in front of its control, and the brand and zone caption are on the apron.

The general form of this rule, for control panel design in three dimensions: the question "where does this text go" has a different answer than in a flat interface, and the answer is always "on the surface facing the viewer", not "next to the thing it describes".

The canvas colour trap

The desk's labels are drawn on a canvas and used as a texture. Colours in the rest of the engine are numbers, because that is what the renderer wants for a material.

Assigning a number to a canvas fill style does nothing. It does not throw and it does not warn. The number is turned into a string of digits, the digits do not parse as a CSS colour, and the setter returns without changing anything, exactly as the HTML specification says it should. The labels came out in whatever colour had been set last, which was usually black on a dark desk.

Canvas wants CSS colour strings. The two systems look interchangeable at the call site and are not, and the failure is silent. So the desk keeps a second palette for its artwork, written as CSS strings, with a comment above it saying why.

What stays off the desk

Not every control belongs on the desk.

Camera views live in the top bar, under Views. Choosing a view is not something a railway operator does. It is something a player does, and a small physical button for something you want instantly is a button you fumble for.

That is the line. Controls that belong to the layout go on the desk. Controls that belong to the game (camera, saving, the shop, help) go in the interface, because they are not part of the fiction and dressing them up as part of it makes them harder to use for no gain.

Getting that boundary wrong in either direction is worse than picking one style and applying it everywhere. A game where everything is diegetic is a game where saving requires walking to a filing cabinet.

Where the desk runs out

The desk drives the layout as a whole, and that is also its limit. MAIN LINE moves every main-line train at once, YARD every shunter, and the two route toggles throw two particular turnouts. A layout with more trains than levers and more turnouts than toggles outgrows it.

Since this post was first written, per-train and per-switch control has arrived, and it went into the interface: the Control menu in the top bar opens a Trains window with a throttle for each train, a Switches window listing every turnout, and a Track plan. Control trains and switches covers all three.

What keeps the desk honest is that the windows are a second face on the same controls, not a second set. A train follows its desk lever until it is given a throttle of its own, and one button hands it back. Throw the YARD ROUTE turnout from the Switches window and the toggle's bat moves on the desk. If the two could disagree, one of them would be lying, and the one that lies would be the one you can see from across the room. The same holds for the tools an AI agent drives in the browser: their set_desk works the same levers, toggles and buttons.

  • design
  • ui
  • control desk

◀ All postsMore on running trains