Using the library directly

Three levels, in increasing order of how much you want to own.

One package, three doors

The library is one package with three entry points, not three packages. They share one install and one version number, so they never drift out of step. The door you pick only decides how much comes with it:

Import What you get Pulls in

@promethist/kiosk-tablet/protocol

Message and state types. No runtime code at all.

nothing

@promethist/kiosk-tablet/core

KioskClient — socket, reconnect, staleness, state mirror, throttle. Touches no DOM.

nothing

@promethist/kiosk-tablet/ui

<pk-button>, <pk-slider> — presentational only.

lit

@promethist/kiosk-tablet

All three.

lit

Drawing your own interface means /core and nothing else. Writing a host in another engine means /protocol and nothing else. Note that this layer is types, not documentation: the wire protocol is the prose, and protocol.ts is the same thing your compiler can check.

Button names, the commands they send, and the keys they read are in none of the three. They live in the app (apps/tablet/src/tablet.ts). This lets you use our components without inheriting our opinion about your protocol.

How to get it

This repository is private, so the first step is to ask us. Your Promethist contact gives you one of two things: read access for your own GitLab account, or a read-only deploy token — a username and password pair that needs no account at all. Either one lets you clone. The deploy token is also what npm install authenticates with, so ask for one if you want the library from the registry rather than from the source tree.

You do not fork it on our GitLab. Clone it and push it wherever you work — your own GitLab, GitHub, anything. Nothing links back to us afterwards, which is the point: your tablet is your repository. Replace apps/tablet with your own interface and leave packages/kiosk-tablet alone, so our client fixes stay a version bump away rather than a merge.

git clone git@gitlab.com:promethistai/promethist-touch.git

Inside an unmodified checkout you need no registry and no token. npm workspaces resolve @promethist/kiosk-tablet to the folder next door, so the reference app builds against the source in the same tree. Only once your app lives in its own repository, away from ours, does it need the package.

Installing the library from the registry

Each release tag publishes the library to this project’s GitLab package registry. To install it, put the deploy token we gave you in an .npmrc beside your package.json. The project id below is already correct; we send you the token:

@promethist:registry=https://gitlab.com/api/v4/projects/82305249/packages/npm/
//gitlab.com/api/v4/projects/82305249/packages/npm/:_authToken=<deploy-token-password>

Then npm install @promethist/kiosk-tablet works as normal, and npm update picks up our fixes. Keep the token out of your repository: most CI systems read it from an environment variable, and npm expands ${NPM_TOKEN} inside .npmrc.

Versions follow the company YYYY.ww.index scheme — the ISO week-year, the ISO week, and the build’s order within that week, counting from zero, with no v prefix. packages/kiosk-tablet/package.json is the source of truth for the version, and the release job refuses to publish if the tag and the file disagree. The tag is the library’s version, not the reference app’s: the two move independently, and the changelog for 0.5 and 0.6 explains why the library deliberately sat still.

If you only want one layer, the three entry points above are separately importable from the same package. Nothing obliges you to take the components or the client.

The three levels

Restyle ours. Every visual is a CSS custom property:

pk-button { --pk-accent: #c8102e; --pk-radius: 8px; --pk-control-min-height: 120px; }

Colour

--pk-accent, --pk-surface, --pk-surface-active, --pk-text, --pk-ripple

Shape

--pk-radius, --pk-shadow, --pk-shadow-active, --pk-control-min-height, --pk-control-padding

Type

--pk-font, --pk-font-size, --pk-font-weight, --pk-label-display

Icons

--pk-icon-size, --pk-icon-gap, --pk-icon-display

Pending spinner

--pk-spinner-width (it fills the icon’s box and takes --pk-accent)

Round variant

--pk-round-size, --pk-round-padding, --pk-round-shadow, --pk-round-icon-radius, --pk-round-glyph-size, --pk-round-label-size

Slider

--pk-track-height, --pk-track-color, --pk-track-fill, --pk-thumb-size, --pk-thumb-color, --pk-thumb-border, --pk-thumb-shadow, --pk-value-width, --pk-value-weight, --pk-slider-hit-height, --pk-gap

Behaviour

--pk-press-scale, --pk-disabled-opacity

The components read these properties. --pk-accent-strong and --pk-danger belong to the reference app (apps/tablet/src/app.css), not the library, so setting them on pk-button does nothing. Three properties in the table are read by one component each: pk-button reads --pk-icon-display, while pk-slider reads --pk-label-display and --pk-gap. The --pk-gap property defines the space between the slider’s caption, value, and track; setting it on a pk-button does nothing. The padding inside a control is --pk-control-padding, which replaced that conflation in 0.2.

Borrow a component. <pk-button> and <pk-slider> are purely presentational. They take a label, an icon, and a disabled flag, and emit an event. They do not know KioskClient exists and read no state, so they carry no opinion about your protocol:

<pk-button id="btnPause"></pk-button>
const el = document.getElementById('btnPause') as PkButton;
el.addEventListener('pk-activate', () => {
    // Send the opposite of what the host last CONFIRMED, compared with `=== true` and never
    // coerced. `!state.paused` looks equivalent and is two bugs: on a key the host has not
    // published yet it sends `!undefined === true`, claiming to know which way an unknown toggle
    // moves; and against a host publishing the string "false" it sends `!"false" === false`,
    // i.e. "no change", so the button does nothing at all.
    client.send('pause', client.get('paused') !== true);
});
client.subscribe(({ phase, state }) => {
    el.active = state.paused === true;
    // `!('paused' in state)` is not belt-and-braces: a flip button whose key has never been
    // published must stay disabled, because there is no honest value to send.
    el.disabled = phase !== 'ready' || state.agentUnready === true || !('paused' in state);
});

This matches the shape of bindButtons() in the reference app, explaining why it lives there instead of the library: it is a pattern to copy, not a dependency to inherit.

Two HTML attributes — not CSS variables, and not shown above — control buttons. variant="round" turns a button into the icon-only circle the corners use, which is what makes every --pk-round-* variable do anything. icon-src is how a button gets artwork, as the components ship none. <pk-slider> takes label, value, min, max, step, and disabled, and emits pk-change with the new number in event.detail.

Draw your own. Take the client and ignore the components entirely:

import { KioskClient } from '@promethist/kiosk-tablet/core';

const client = new KioskClient();
client.subscribe(({ phase, state }) => render(phase, state));
client.connect();

client.send('pause', true);

@promethist/kiosk-tablet/core pulls in no UI framework at all.