One binary.
Native reach.

ArdaPlayer is the program that turns a Linux box into your product. It boots, shows your logo before the system has finished starting, opens your sealed application in memory, paints it straight on the display with no desktop underneath, and hands the page a controlled door into the hardware. You write the page; ArdaPlayer looks after the machine.

One Go binaryWebKit on the bare displayNo X, no desktopSealed app loadingwindow.Arda bridgeOne outbound connectionSelf-updating
01 / Cold start

What happens
when it boots.

There is no desktop, no window manager to fight and no browser chrome for a customer to poke at. The machine powers on and the application is simply there — with your logo on the panel from about a second in.

  1. 01
    LogoOn the screen at roughly 1.3 seconds, before the system has even finished loading (it is drawn from the initramfs). No scrolling boot text ever reaches the panel.
  2. 02
    DisplayYour page is drawn straight onto the screen by WebKit — WPE through cog, on the DRM card. No desktop, no window manager, nothing else running.
  3. 03
    IdentityThe device makes its own key the first time it starts (an Ed25519 keypair) and the private half never leaves it. Everything it stores on disk is locked with a key derived from it and from the board.
  4. 04
    Dial homeIt connects out to ArdaForm (one WebSocket), says what hardware it is, and checks in every 30 seconds. If the line drops, it keeps trying until it is back.
  5. 05
    DataA boot screen with one bar shows the app's data and files arriving. The app starts the moment the data it said it needs to begin with is current; pictures keep landing behind it.
  6. 06
    RunThe sealed .arda is opened into memory — never onto the disk — and window.Arda is in the page before your first line runs.
journalkiosk
[ 1.28 ] splash logo on simplefb [ 2.21 ] splash redrawn on vc4drmfb [ 19.7 ] ardaplayer v1.2.3 linux/arm64 · kiosk [ 19.8 ] screen DSI-1 1280x800 · touch · no keyboard [ 19.9 ] viewer cog opened platform=drm renderer=gles [ 20.0 ] identity 7c2e9a41… stores sealed ARDS2 [ 20.4 ] control dialling wss://connect.ardaform.net [ 20.9 ] control welcome · partition 7 · gzip [ 21.0 ] sync 8 datasets at head · 2,749 files present [ 21.1 ] app running · main @ 3f9c2a1
arda-tabletONLINE
02 / Positioning

Conceptually like Electron.
Built for a different job.

Electron is an excellent way to ship a desktop application to people who own their computers. An appliance in a shop is a different problem, and the trade-offs go the other way.

ConcernTypical Electron appArdaPlayer
Rendering enginePrivate Chromium bundled per applicationWPE WebKit through cog on the fleet; the system WebKitGTK on a Linux desk
Display stackA desktop session underneathThe bare DRM card. No X, no compositor, no desktop to escape to
Application codeASAR archive — readable and extractableA sealed .arda packed by ArdaForm, opened in memory only
Native accessFull Node.js API surface in the main processwindow.Arda — a narrow bridge over loopback, a fixed list of things a device does
Target hardwareDeveloper and consumer machinesRaspberry Pi, low-power x86 terminals and panel PCs
UpdatesPer-application updater the user consents toPushed as a signed instruction; the app picks the moment; the player updates itself the same way
Fleet managementNot in scopeRegistry, snapshot, log capture, screen view, console and SSH built in
i
Not a competition ArdaPlayer is not a drop-in Electron replacement and doesn't try to be. It has no desktop integration, no menus and no Node.js in the page. If you're shipping a desktop app, use Electron. If you're shipping a device, keep reading.
// window.Arda is there before this line runs — no import
const d = await Arda.device()
console.log(d.hostname, d.model, d.can)
// 'arda-tablet' 'Raspberry Pi 4 Model B'
// {screen: true, touch: true, keyboard: false, …}

// Settings the operator set in the portal — a plain object
const currency = Arda.config.currency ?? 'GBP'

// Lay the screen out for the machine it is on
if (d.can.touch && !d.can.keyboard) {
  const pin = await Arda.keyboard({ layout: 'pin', title: 'Staff PIN' })
  if (pin !== null) unlock(pin)
}

// The hardware, through the same object
const [printer] = await Arda.printers.list()
await Arda.printers.print(printer.id, escpos(receipt))
03 / The bridge

A narrow door,
not an open one.

Your page gets one extra object, window.Arda, and through it a fixed list of things a device does: its data, its settings, its printers and serial ports, its screens and speakers, its cameras, its readers, its Wi-Fi, its power — and webhooks to your own servers, which ArdaForm calls on its behalf. It does not get free access to the disk, a shell, or raw network sockets: on the page's behalf the player connects only to ArdaForm and to the cameras the app names. A third-party script bundled into your app cannot quietly do something to the hardware the app itself cannot.

Under the hood there is exactly one definition of window.Arda, injected before the page's own scripts. It rides a loopback server rather than engine bindings, which is why the API is identical in developer mode, in the kiosk, and with no screen at all — ardaplayer -headless evaluates the same source with no DOM. arda.dev.json sits beside app/: plain JSON, read only in developer mode, never packed.

04 / Staying current

The app updates.
So does the player.

Both arrive the same way — a signed instruction addressed to that one device, naming the fingerprint (SHA-256) of what to fetch — and both are checked on the device before anything changes. There is nothing for you to schedule.

Staged, then negotiated

A new app is fetched, hash-checked, opened to prove the key agrees, and staged. The page is told. Five seconds of silence and it reloads; an app mid-sale can pause it for a minute, five times, and the update waits for the next restart if it never agrees.

The player smoke-tests itself

A new player binary is fetched, checked against the signed hash, run once to prove it starts, and armed for the next restart. Three starts that die in a row put the previous binary back.

Nothing to schedule

A branch can be set to apply at once, inside a time window in the device's local time, or only when the app asks. The device decides the moment; the operator can override it from the portal.

05 / Where it runs

Hardware
independence.

One pure-Go binary per architecture, cross-compiled in seconds. If Linux boots on it and the kernel can drive its display, ArdaPlayer draws on it. On Android it is an app: the same player inside a small shell, one download for every box.

x86-64

Mini PCs, box PCs and repurposed point-of-sale terminals — a Bay Trail till is the reference machine. Installed from the USB stick or the PC image.

amd64Working

Raspberry Pi

Pi 3 and Pi 4, HDMI or DSI. One image serves both: it probes for the panel at boot. The DSI tablets are in production.

arm64Working

Touch terminals

Capacitive panels, customer-facing displays, cash drawers and thermal printers on an AURES till and the Pi tablets.

peripheralsWorking

Your desk

A Linux desktop build with the inspector, and Windows and macOS builds that open the app in your browser — the same API, for building the page.

-devWorking

Android tablets

The same player as an Android app, Android 7 or newer: a tablet beside the till, activated with the same code, its Wi-Fi printers and battery in the portal — and kiosk mode when the player is the box’s device owner.

apkWorking

Displays and TV boxes

Many commercial screens and most TV boxes run Android: the player runs on the screen you already have, with no Raspberry Pi behind it — 64-bit and 32-bit ARM and x86-64 in one app. Installing it.

arm64 · armv7 · x86-64Working
1ArdaForm binary on the devicePure Go, statically linked
0Inbound portsA firewall; SSH only when you open it
~1.3 sTo your logoDrawn from the initramfs
WPEWebKit, on the bare cardNo X, no desktop
Next

See what your
page can reach.

Datasets, the outbox, settings, the on-screen keyboard, screens and audio, cameras, printers, serial, readers, Wi-Fi, power and webhooks — all from ordinary JavaScript.