Product tour The tool, not a mock-up One project, every screen size

The tool, before you install it.

Every shot on this page is the software itself — the editor, the pickers, the datasource browser, the project manager — working on one project: a bottling line called Aquavane, against a live OPC-UA server. The operator screens at the end are what came out of it.

Click any shot to open it full size.

Authoring

The editor is the same browser tab.

Tree on the left, the real page in the middle, the selected widget's properties on the right. The preview is the runtime — same renderer, same live tag values — so the thing you are dragging around is already reading the machine.

The NEXT HMI page editor: a page tree expanded down to Station 2 inside a filling-line schematic, the live Line page in the centre canvas at 80 percent zoom with viewport and mode switches above it, and a property panel on the right showing bound properties and switch expressions for card background, card border, severity dot colour and glow.
Three panes, one project. Viewport switches (desktop, laptop, tablet, phone) and a zoom control sit over the canvas; the toggle beside them flips the same page between edit and run. The header, sidebars and footer are branches of the same tree as the pages, so a change to the shell lands on every screen at once.
One project, every house style

The same page, any house style.

Nothing below is a redraw. It is the built-in widget page from that editor — same page file, same bindings, same live tags — rendered under different themes. Colour roles, type family, corner radii and shadow all come from the token file, so a customer's brand is a theme you add, not a project you fork or a stylesheet you maintain.

The built-in widget page under the Aquavane theme: a soft off-white background, rounded cards, a teal accent through the segmented control, switch, gauges, progress bar and trend lines, and a geometric sans across every label and readout.
Aquavane. The house theme this demo project ships with — teal accent, generous radii, Manrope.
The same built-in widget page under a dark theme: near-black background, dark surfaces, a blue accent running through the segmented control, switch, gauges, progress bar and trend lines, and light text on every label and readout.
Dark. For the panel at the machine, where a white screen is the thing the operator complains about first.
The same built-in widget page under the Centris theme: a cooler grey-blue background, a cyan-blue accent, tighter corner radii and a different type family across every label, value and control.
Centris. A second brand on the same platform — another accent, another type family, tighter radii.

The theme is picked per project and can be switched at runtime, so the same build serves the plant's own palette and a machine builder's white label without a second deployment.

Widget catalog

Your widgets sit next to the built-ins.

Drop a .tsx into custom-widgets/ and it hot-compiles into this catalog — description, icon, typed properties and all. No Node toolchain, no rebuild of the core, and no second-class treatment: a house widget you wrote three projects ago is offered on the same dialog, in its own category, as the containers and buttons that ship with the platform.

  • Categories, not one long list — layout, content, navigation, inputs, and one per widget pack the project carries.
  • Every entry describes itself, because the description comes from the widget's own schema.
  • Reuse across projects is a folder copy, and the properties come with it.
The add-widget dialog: categories for Layout and structure, Content and controls, Navigation, Aquavane, Centris, Examples, Inputs and Other, with the Aquavane category showing project widgets including AlarmStrip, BatchList, Conveyor, StationGlyph, TankLevel, Card, KPI Cell, OEE Row, Readout Tile, Stat Tile, Station Link, Station Node and Trend Legend, each carrying a Custom or Component badge and a one-line description.
The Aquavane pack, in the catalog. Thirteen project entries — five compiled widgets and eight components — beside the built-in ones, each described by its own schema.
Property sources

Any property. Any source. No scripting.

Every property has a type and a source. Leave the source as a literal and you have typed a number in a box; swap it and the same property now reads a tag, branches on a comparison, resolves through a dictionary, or answers differently on a phone than on a panel PC.

The sources nest, so a colour can switch on a live tag, inside a label that resolves through a translation, inside a layout that branches by viewport. One idea, learned once, and it covers every property on every widget — including the ones on the custom widgets you write yourself.

$var $if $switch $compare $loc $viewport $recipe $user $time $http + 13 more
The Select source drawer for a widget property, split into flexible sources — HTTP Request, If Condition, Switch / Case, Variable, Exported Property and Static Value — and fixed-type ones below them — Comparison, Device Info, Localizable Text, Page Metadata, Page Active, Recipe, String Expression, Current Time, URL Parameter, User Data, User Groups and Viewport — each card carrying its $key and a one-line description.
The same picker on every property. Twenty-three sources in the catalog; the picker offers the ones this property's type accepts, wherever a value is expected — including inside another source's slots.
Value pickers

Every property type, its own picker.

A source that points at a variable, an image or an icon opens a picker built for what it holds — filtered, searchable, and previewed at the size the operator will actually see it. Drop your own SVGs and images into the project and they show up in these pickers alongside the built-ins.

The variable picker: a datasource tree with Machine expanded to Tanks showing T1Level, T1Volume, T1Temp, T2Level and CIP nodes with their data types and RW badges, a required-type chip reading Integer / Float / Boolean, and the selected variable summarised on the right.
Variable picker. Typed and access-aware — the chip at the top states what the property will accept, and a read-only node cannot be bound to something that has to write.
The image picker showing a grid of project SVGs — a CIP skid, a PET bottle, and station glyphs for capper, conveyor, date coder, labeler, mix tank, palletizer and rotary filler — with a search box and a preview-size slider.
Image picker. Everything in the project's image folder, searchable, with a size slider so you judge the glyph at the size the operator sees.
The icon picker showing a grid of 59 built-in line icons — home, gauge, chip, thermometer, droplet, wave, bolt, warning, play, gear, wrench, database, chart, clock, user, eye, lock, bell and more — with Built-in and Custom tabs and a search box.
Icon picker. 59 built-ins on one tab, your own SVGs on the other, and the same picker wherever an icon property exists.
Responsive by project

One project. Panel PC, tablet, phone.

Not three projects kept in step, and not a desktop layout squeezed onto a handset. Every layout property — direction, size, spacing, whether a widget is on the screen at all — takes the same $viewport source as any other property, so one page file serves the panel at the machine, the tablet in the QA office and the phone in the maintenance engineer's pocket.

The same Aquavane dashboard rendered at three widths side by side: on a laptop at 1440 pixels with a full navigation sidebar, a five-tile KPI strip and six line-flow stations in a row; on a tablet at 900 pixels with the sidebar reduced to an icon rail and the stations wrapped into a three-by-two grid; and on a phone at 390 pixels with a hamburger button, two KPI tiles and the cards stacked one per row.
The same dashboard, three widths, one page file. On the laptop the navigation is a full sidebar and the line runs left to right through six stations. On the tablet the sidebar drops to an icon rail and the stations wrap to a 3 × 2 grid. On the phone the KPI strip keeps the two numbers that matter, the cards stack, and the navigation moves behind a hamburger.
How it is authored

The viewport class — phone, tablet, laptop — is just another value to switch on. Bind a container's direction to it and a row becomes a column below a breakpoint; bind a widget's visible to it and the detail that would not survive the shrink is simply absent instead of unreadable.

  • The shell branches too — the sidebar's overlay and expanded properties turn the navigation into a dismissable drawer on a phone and an icon rail on a tablet.
  • No CSS, no media queries — it is the same binding language as every other property, edited in the same panel.
  • Check it before you ship it — the editor's canvas has laptop, tablet and phone presets, so the branch is verified in the same tab that authored it.
pages/dashboard.json
// stack the cards on a phone, keep the row on a laptop
"direction": {
  "$switch": {
    "value": { "$viewport": { "field": "size" } },
    "cases": [
      { "when": "phone",  "then": "column" },
      { "when": "tablet", "then": "column" }
    ],
    "default": "row"
  }
}
Alarms

An alarm that tells you what to do about it.

Every alarm carries a code, a severity, a plain-language explanation and a list of resolutions — authored once, shown wherever that alarm surfaces. The night-shift operator gets the same three steps the process engineer would have given them.

The alarm editor: an alarm tree on the left, the live popup and detail-dialog preview in the centre, and the property panel on the right carrying the alarm code, severity, trigger condition, description and the numbered resolutions.
Alarms are authored in the same three panes. Code, severity, trigger condition, description and resolutions on the right; the popup and the detail dialog the operator will actually see, previewed live in the centre as you type them.
  • Toast, list and dialog are three views of one definition. Change the text once.
  • Acknowledgement is per alarm, with an acknowledge all for the shift handover.
  • An illustration slot takes a project image, so the dialog can point at the actual head that jammed.
  • The event log keeps the pairs — raised at, cleared at, and whether anyone ever acked it.

Both previews in the centre pane above are the real widgets, not a rendering of them — the popup and the detail dialog the operator will get, redrawn as you type the description and the resolutions.

The Alarms and Events page: filter tabs for All, Alarms, Warnings and Info, a list of five active alarms each with an ACK button and a timestamp, an acknowledge-all button, and a recent-events column pairing raised and cleared times with a NOT ACKED marker.
Active alarms beside the event log. The badge in the sidebar counts unacknowledged, not active — so a cleared-but-unseen fault still asks for attention.
Historian

Logging is a list of tags, not a second product.

Pick the variables worth keeping, set how often and for how long, and the trend widgets have something to draw. It is in the open-source build — no historian add-on, no separate time-series database to stand up and back up.

The Trends page: signal cards for fill rate, fill volume, cap torque and product temperature down the left, and a multi-series time chart with range buttons from 1 minute to 30 days and a hover tooltip reading Machine:Process/FillVolume 495.07.
And what it feeds. Ranges from one minute to thirty days off the same store, with a crosshair that names the variable it is reading.
Across the whole project

Recipes, language and theme are editors, not exports.

Three things every plant asks for late in the project, and all three are first-class here — stored as JSON and CSV beside the pages, so they diff, review and travel with the rest of the project.

The Recipes editor: a Product recipe type with five datasets — Citrus 500 mL, Berry 500 mL, Citrus 330 mL, Cola 500 mL and Lemon 1 L — and the Citrus 500 mL dataset open, listing typed parameters such as target fill volume, fill speed, foam settle delay, cap torque and torque tolerance, each with its stored value next to the live value read back from the machine.
Changeover in one row. A recipe type defines the parameters once; each dataset is a product. The Live column reads the machine back, so you can see the moment the line has actually taken the recipe — and Save dataset captures a hand-tuned line as the new standard.
The Translations editor: a dictionary table with EN-EN and DE-DE columns, rows pairing English UI strings such as Active alarms, Air pressure, Cap torque and CIP cycle with their German equivalents, an add-translation row and a search box.
One dictionary, one column per language. Every string that went through $loc is here, searchable, with a column you add rather than a project you clone. The runtime switches language without a reload.
The Themes editor: four themes listed — aquavane, centris, dark and light — with the aquavane colour tokens shown as editable swatches for background, surface, raised surface, text, muted text, accent, border, OK, warn and fault, contrast badges reading AA and AAA, and a typography section previewing the Heading style with font, size, weight, letter spacing and case.
Tokens with the contrast maths done. Ten colour roles and seven text styles per theme; each swatch prints its measured contrast against the background and surface, so a customer's brand colour fails here rather than in a plant audit.
Getting it onto the machine

Several projects, one server, one page to run them from.

The manager is the front door of the installation. Projects live in ordinary folders, start and stop independently, and move between installations as a zip or straight over the LAN.

The project manager: buttons for Import zip, Add existing, Pull from peer and New project, above four project cards — a running Default project and three stopped ones for Aquavane Blow Moulder, Aquavane Packing Hall and Water Treatment Skid A — each showing its folder path and per-project actions to open, edit, rename, export, transfer, stop or remove.
Every project is a folder you can point at. Run one on a panel PC, four on an office server. Each carries its own operator accounts, and the MCP checkbox decides per project whether an AI agent may touch it.
The Transfer to a peer dialog: destination host 192.168.4.31, protocol HTTP, port 8000, a destination device-admin password field, a note that the password is used once for pairing and never stored, and a Pair and continue button.
Laptop to panel, over the LAN. Pair once with the destination's device-admin password — it is used for pairing and never stored; the peer keeps only a revocable token hash. Or take the zip, if the panel is on an island network.
Diagnostics

What the server is doing, while it is doing it.

Two questions come up on every commissioning day — is it actually subscribed to that tag, and did my widget compile. Both have a page rather than a log file.

The Admin page: a Fast Subscriptions card for the Machine datasource marked Connected and BG On, listing 45 tags currently on the fast subscription as individual chips; below it a Custom Widgets table with one row per project widget showing an OK status, whether it has CSS, the compile timestamp and a per-widget Recompile button.
Fast subscriptions, per datasource. The pool promotes the tags that are actually on screen — 45 of them here — and demotes the rest, so a project with ten thousand nodes does not poll ten thousand nodes. The connection state and the background-polling flag are the same two chips your OPC-UA server sees. Underneath, every custom widget's compile status, timestamp and a Recompile button — a red row here is the answer to "why is my widget a blank box", and it is on the same page rather than in a terminal.
Open source · AGPL-3.0 licensed

Same screens, on your machine, this afternoon.

Both the Docker image and the portable zip boot with a seeded example project, so there is something to click before you have a PLC connected. No trial to request, no quote to wait for.