npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pict-externalui

v1.0.0

Published

Host a pict application over a socket-first external UI protocol, so native providers (Godot, Tauri, and others) render its views.

Readme

pict-externalui

Host a pict application over a socket-first external UI protocol, so native providers (Godot, Tauri, and others) render its views. The exact sibling of pict-terminalui: it swaps the pict ContentAssignment seam, but instead of writing to blessed widgets in-process, it projects an addressable widget tree to one or more providers over a socket and routes addressed events back. The pict application is unchanged; this is a third consumer of the ContentAssignment hook, alongside the browser DOM and blessed. Base pict is never modified.

Architecture

A pict app runs in Node with pict-externalui attached. Every view render, which pict would normally write to the DOM, becomes a projection message: an addressable widget tree. A provider, a thin generic client, builds native widgets from that tree and sends event messages back when the user interacts. The host marshals a value event to the control's own data address and dispatches a command event to the control's own registered action, then the resulting re-render projects again. All application logic stays in the host; the provider holds no application state, so one provider renders any pict app, and a late or reconnecting provider is caught up by a replay of the current tree.

    Node (the host)                              the provider
    +-------------------------------+            +--------------------------+
    | pict app: views, AppData,     |            | build native widgets     |
    | actions                       |            | from the projected tree, |
    |   |                           |            | report addressed events  |
    |   | render (ContentAssignment |  ws / json |                          |
    |   v  seam, swapped)           | =========> | Godot (native)           |
    | projection {op,address,widget}| projection | web (Tauri/Electron/     |
    |                               |            |      Sciter)             |
    | event {address,kind,value}    | <========= | NodeGui (Qt)             |
    |   ^  marshal / dispatch       |   event    |                          |
    +-------------------------------+            +--------------------------+

The transport is swappable behind a small interface (WebSocket is the reference). The wire contract is versioned and schema-backed: every message family has a JSON Schema in schemas/, and the host validates every inbound message against it. See docs/PROTOCOL.md for the contract and docs/TRANSPORTS.md for the transport interface.

Thirty-second quick start

Attach the host to a pict app, register the actions its command controls invoke, and start the socket:

const libPictExternalUI = require('pict-externalui');

let tmpUI = new libPictExternalUI(pict, { Port: 8090 });
tmpUI.registerAction('addTask', (pBinding, pEvent) => { /* mutate AppData, re-render */ });
tmpUI.start((pError, pAddress) => { /* pAddress = { host, port, url } */ });

Views emit a JSON widget descriptor as their rendered content (see conformance/fixtures/Fixture-Todo.js for a complete, runnable example), and the host turns each render into a projection.

Then point a provider at it. The shared web client needs no build:

# from this module, serve the client and drive it once a browser connects
node conformance/run-conformance-web.js
# open the printed URL in any browser

Or run the native Godot provider (with Godot installed):

node conformance/run-conformance.js godot

Trust model

The host binds to loopback (127.0.0.1) by default. Binding to a non-loopback address exposes the app to the network and requires an explicit opt-in (options.AllowRemote = true); without it the host refuses to start. The event channel is untrusted: every inbound message is validated against its schema, an event's address must resolve to a binding the host actually projected before any value is marshaled, and only a control's own registered action is ever dispatched. A malformed or hostile message is logged and dropped, never thrown. The full trust model is in docs/PROTOCOL.md.

Writing a provider

A provider is a generic client that renders any pict app. It speaks the protocol in docs/PROTOCOL.md; the shortest path is to copy the closest reference provider under providers/ and adapt the widget building. The contract:

  1. Connect and send hello once, before anything else, with your protocol version, a name, the controls you can render, and a driver flag:

     { "type": "hello", "protocol": "1.0", "provider": "mykit",
       "capabilities": { "controls": ["text","select","number","checkbox","button","label","list"],
                         "escapeHatch": "webview" | "native" | false, "driver": true } }

    The host replies welcome, then replays the current tree (and the theme, if any).

  2. Handle projection, a patch to the widget tree at an address. op is replace (the default: clear the region, then build), append, prepend, or remove. widget is a node tree (Form, List, Container, Row, Field, Button, Label, Escape); map each control kind on a Field to a native widget. Tolerate a node type or control kind you do not understand by skipping it, so a projection you cannot fully render does not fail the whole tree.

  3. On a real widget signal, send an event by the control's address:

     { "type": "event", "address": "#Form/Name", "kind": "value", "value": "Water" }
     { "type": "event", "address": "#Form/Add",  "kind": "command" }

    A value event carries the control's new value; a command event carries none. Do not put a data address in the event; the host uses the descriptor's own binding.

  4. Handle drive (test only, gated on your driver flag) by firing the addressed widget's real signal path, not by sending the event directly. That is what makes a passing conformance run certify your wiring rather than a mock.

  5. Handle theme by mapping the toolkit-neutral tokens to your theming, or ignore it if you cannot theme. Handle an Escape node by rendering its html in an embedded webview (advertise escapeHatch: "native" if you are a browser, "webview" if you can embed one), or show a placeholder that keeps the region's address.

  6. Reconnect if the socket drops, re-sending hello. The host replays the tree, so you survive starting before the host or a host restart.

The schemas in schemas/ are standard draft-07, so you can validate messages in any language while building a provider.

Providers and conformance

Each provider under providers/ is generic (renders any pict app) and passes the same conformance scripts. A provider is certified by driving its real widgets, so a green run proves the wiring, not a mock.

| Provider | What it is | Run / certify | | --- | --- | --- | | mock | headless, in-process | npm test (every run) | | web | shared client (Tauri, Electron, Sciter host it) | npm run conformance:web, then open the URL; providers/web/docs/HOSTING.md | | godot | native Control nodes, desktop and mobile | node conformance/run-conformance.js godot; providers/godot/docs/PACKAGING.md | | tauri | shared web client in the OS webview | providers/tauri/docs/PACKAGING.md | | nodegui | real Qt widgets | HOST_PORT=8091 npm run conformance:external, then run the provider windowed; providers/nodegui/docs/PACKAGING.md |

The web and NodeGui runs use a host that waits for the provider to connect, because a browser cannot be spawned and NodeGui's qode launcher re-execs a native Qt binary that does not complete its socket when spawned as a child. In CI, set BROWSER_BIN (for example chromium --headless=new --disable-gpu) so conformance:web launches a headless browser itself.

Testing

npm test        # host unit tests + transport + validator + in-process conformance (mock) + provider smoke
npm run coverage
npm run smoke   # load every provider as far as this machine allows

npm test runs fast and headless: the host, transport, and schema validator unit tests (including the malformed and hostile input cases), both conformance fixtures driven through the in-process mock provider over the real socket, and a smoke pass that parses the JavaScript providers and checks the native providers' project files. The real-GUI providers are certified by the documented commands above.

Layout

source/
  Pict-ExternalUI.js                 the host
  Message-Schema-Validator.js        runtime validation against schemas/
  transports/WebSocket-Transport.js  the reference transport
schemas/                             draft-07 JSON Schema per message family
docs/
  PROTOCOL.md                        the versioned, schema-backed wire spec
  TRANSPORTS.md                      the swappable transport interface
  DESIGN.md                          sequence diagrams of the flows
conformance/
  fixtures/                          real pict apps used by the suite
  Mock-Provider.js                   a headless provider for testing the host
  Conformance-Harness.js             drives a provider through a script, asserts
  scripts/                           the canonical conformance scripts
  run-conformance*.js                runners for out-of-process providers
  smoke.js                           the CI smoke check
providers/
  godot/  tauri/  web/  nodegui/     the reference providers, each with docs
test/                                mocha TDD unit and conformance tests