A day that behaves like a ward
The simulation is written to tell a ward's afternoon: discharges cluster late in the morning and admissions arrive through the evening, so beds sit dirty, then in cleaning, then ready and waiting. Rooms warm through HVAC faults, the family lounge gets stuffy in visiting hours, pumps run low until someone plugs them in, and call lights wait longer at shift change. Each of the 36 wings runs from its own seed, so every visitor replays the same day and one wing's day never shifts another's; wing 4A, where the demo opens, keeps a scripted story on top. It all runs in a Web Worker, and the wing on show arrives first, in under 30 ms, with the rest of the hospital under a second behind.
From one wing to the whole hospital
The model works at three scales. A wing is two wards and an ICU, close enough to read a bed. A level puts its six wings on one plate, joined by glazed links. All levels draws the six floors apart, an exploded section of the building, each coloured by the same layer, so a warm room shows from across the hospital. A map of the building sits beside the model, every wing shaded by how full it is and marked where something critical is open; a click on a wing flies into it, and a trail above the panel leads back up. The camera fits each scale by projecting its corners through a trial camera, so the model always clears the overlays, and the address bar keeps the scale, view, layer, time and selection, so every view is a link.
The drawing and the model are one scene
Plan view does not swap in a flat map. Every wall sinks to a section cut 15 cm above the floor and darkens to ink, so the model turns into the architect's drawing and back, for a wing or a whole level, and the first load plays the same move the other way: the plan rises into the building. List view carries the same data as a table, for keyboards, screen readers and anyone who wants to scan.
A real building, from its BIM model
Every wing of the demo hospital is built to one plan, and no real building is. So the twin also reads one: buildingSMART's Medical-Dental Clinic, a real two-storey clinic published for testing as a 13 MB IFC file. At build time the IFC is read in Node and each room's outline is cut from its own mesh, with its name, its category and the area the model states; the page loads 34 kB of outlines, walls and doors, and never the parser. The check is the model's own figures: the model measures a room to the middle of its walls, and once that half wall is counted, 258 of the 259 rooms are within 5% of the area it states. The clinic opens from a link with the same layers, views, alerts and languages, and a simulated day on its own rooms, replayed or live: the integration server serves it as a building of its own, under its own topics, by its own rules, on a feed of its own.
The nearest free pump, and the walk to it
From any bed, Nearest free finds the infusion pump, wheelchair or bladder scanner, or from an ICU bay the ventilator, that is quickest to reach on foot anywhere in the hospital. The walk runs on a graph of the building, 4,296 points: every room and its door, both corridors of each wing, the crossing through the core, the glazed links and the lifts. Costs are seconds, 1.2 m/s on foot and a lift as a wait plus a few seconds a floor. The question has many possible answers, so one Dijkstra search from the room reaches them all, where A* would need a search for each pump; a search takes 2 to 11 ms. The walk is drawn over the walls, the view widens to the level or the building to hold it, and the search loads only when someone first asks, as its own 1.4 kB file.
Alerts that know only the present
An alert keeps only what was known when it opened, and it is worded at the minute on the timeline: pressed at 14:21, nine minutes without an answer. Scrub to any time and nothing gives away what happens next. Severity is read at that minute too, so a warming room turns critical only once it passes 26.5 °C.
Alerts someone can answer
An operator acknowledges an alert and sends it to the team that owns it: facilities for a warm room, nursing for an unanswered call light, housekeeping for a bed waiting to be cleaned, bed management for a clean bed with no patient. The alert still clears only when its condition does. In alarm management, acknowledging belongs to the operator and clearing to the process, so no button pretends to cool a room. Each action joins the day with its minute: scrub back before an acknowledgement and the alert is new again, and each room keeps a log that says when an alert cleared before anyone acknowledged it. Live, an action goes to the server and comes back to every screen as an event. One taken while the server is down waits in an outbox and arrives once the connection is back, logged once however often it is sent, which a browser test checks through the demo's own outage.
The next four hours of ward beds
Every overview forecasts how many ward beds will be free in the next four hours, net of the patients waiting for one: a likely number, and a range meant to hold four times in five, drawn beside the last four hours. It is made only from what is known at that minute, the beds being cleaned, the discharges the morning round planned and the usual pace of admissions, and a test checks it: built from the live feed up to a minute and from the whole recording, the two forecasts must match. A backtest makes it every half hour in every wing and compares it with what the day went on to do. The first version looked right on screen and held its range half the time; the backtest found the two faults behind that.
In English or Arabic
A switch in the top bar turns the whole interface to Arabic, right to left, and a link can open it that way. The layout mirrors, the panel moving to the left of the model and the overlays trading sides, while time and scales keep running left to right, as in a media player: the timeline, the charts, the colour ramps and the map of the building. The alerts are worded in Arabic with its six plural forms, and the room names are set in Arabic on the floors. Vazirmatn was chosen by setting the interface's own text in six Arabic faces beside Schibsted Grotesk. It and the Arabic catalogue load only for an Arabic visit, and a test that parses the source fails if the catalogue misses a string the interface says.
Live, from a stream of events
Live mode builds the hospital from events as they arrive instead of from a recorded day. A mock server in a Web Worker plays the day over the JSON protocol a real integration server would use, a simulated minute each second, and the page folds each event into the same day the views already read, so none of them had to change. Sequence numbers keep the stream whole: when the connection drops, the page says the floor is stale, waits longer before each retry, and asks for only the events it missed, from the last 2,000 the server keeps. A test replays the whole day as events and checks that it reads exactly like the recording at every five-minute reading.
From a hospital's own systems
A hospital's systems do not speak the twin's feed: building sensors, bed status, nurse call and location tags each speak their own protocol, and most can reach MQTT through a gateway. So an integration server stands between them. It subscribes to one topic per room, asset and flow, checks every message, gathers readings into one frame every five minutes and works out every alert itself, by the same limits the simulation uses, then serves the feed the page already reads. One command runs a whole simulated hospital on one machine, and the clinic beside it: a broker, the systems publishing the day as raw messages, a server for each building and the twin. A test publishes the whole day, 1,005,153 messages, and the server must turn them into exactly the recorded 21,904 events with all 881 alerts, which it is never given.
Inside another dashboard
A twin rarely has the screen to itself, so any page can embed this one: one script of 1 kB and one tag, <cutaway-twin at="level-4">. The page talks to the twin in the words a link already uses. It opens a room, a layer or a minute and plays the day, and it hears what someone selects, the alerts open and each alert as it opens, worded in the twin's language. The twin runs in an iframe, so its React, three.js and WebGL never meet the host's own framework or styles, and after a handshake it takes commands from that one origin and reports only to it. Every command is checked by the same function that reads a link, and one it cannot take comes back as an error by name. A mock operations page shows it working, and a browser test embeds the twin in a page on another origin, moves it and listens to it.
By keyboard and screen reader
The model is one stop in the tab order. The arrow keys move between rooms, or between wings in a level or the whole hospital, by what lies that way on screen, so they mean what the eye sees however the camera has turned; Enter opens one and Escape steps back out. The cursor lights the floor and shows the tag a pointer would, and each move is said aloud: Patient room 4A09, occupied. Alerts that open while the day plays or streams live are said too, gathered a few seconds at a time so a fast replay does not bury the listener. The list view carries the same floor as a table. On every push, axe-core checks eight views a link can open against WCAG 2.2 A and AA at desktop and phone size; its first run found one violation, repeated on every view, and it was fixed.
Fast because it draws less
The canvas renders only when something changes, so an idle hospital costs no GPU time. Every wing is built to one plan, so each part of the shell is one instanced mesh for all 36 wings, and the 1,368 room floors are one more, which is also the pick target. Only what is in view is packed into what the GPU draws: the first build of the hospital hid the other wings but still sent them to the GPU, 207,000 triangles for one wing, and packing brought that back to 15,000. Beds, patients, bedside furniture and equipment are glTF models, 17,208 triangles compressed to 129 KB, drawn as instances with a shader that tints only the parts that carry state, such as a blanket or a pump's housing. Each switches to a plain proxy by its distance from where the camera looks, and to a box in the whole-hospital view, which draws in 33 draw calls, fewer than one wing up close. The corridors' temperature and air are estimated in the fragment shader, from each wing's 38 doors weighted by how wide they are, with isolines and the alert limit drawn from screen-space derivatives; switching that layer on costs 1 or 2 fps.
It adapts, recovers and is tested
Quality adapts to the device: four levels, from ambient occlusion with SMAA down to plain rendering at a lower pixel ratio, stepped by the frame rate measured while the scene moves. If the graphics driver resets, the view says it has paused and rebuilds itself, tested both with the effects already running and with them arriving after the loss, a race CI caught. Every push runs 113 unit tests, 30 browser tests with real WebGL at desktop and phone size, accessibility checks of twelve views, lint, types and a size budget for each bundle, and a failure stops the deploy.