Hanabi Developer Hub
/ Get started / Learn by example
Get started

Learn by example

A runnable catalog of sample modules — one capability each, plus full worker demos.

Sample-module gallery
Foundations
hello-world-webpage browser
A module is just a webpage in a window
svelte-scratchpad svelte
Build a module UI with Svelte + the bundler
One capability
demo-files browser
Read picked files; write outputs
files.read · files.write
desktop-integration-demo browser
VFS management, place on Desktop, theme
files.manage · desktop.*
demo-notifications browser
Toast + taskbar badge
notifications
demo-settings browser
Durable per-user key/value
settings.self
demo-storage browser
Read storage usage / quota
storage.read
demo-media browser
Range-streamed media
openMedia
demo-office browser
Edit .csv/.xlsx in place
readOffice · saveOffice
demo-inter-module browser
Discover + hand off a file
modules.use
inventory-tracker browser
Collections of JSON docs — the workhorse
data.store
demo-scheduler browser
Interval / cron jobs
jobs.schedule
demo-client-webgl browser
WebGL + the client.* flags
client.webgl
broad-reader svelte
Consent-gated broad read
files.read.all
Workers
demo-worker-basic worker
The run() worker contract
worker.execute
demo-streaming-worker worker
Large files, streamed by path
run_streaming
demo-task-queue worker
Background enqueue / poll / cancel
jobs.queue
demo-fetch-worker worker
Declared-origin egress
network.fetch
media-toolkit-worker worker
ffmpeg + broad fetch
worker.native · network.fetch.broad
Combined
capability-demo browser
The core bridge, many calls
kitchen-sink
advanced-capabilities-demo browser
Data / queue / scheduler, gates shown
kitchen-sink

The fastest way to learn the module platform is to read (and run) the samples in examples/modules/. They're ordered here from "hello world" to a full native-compute worker, and every browser sample is one HTML file with no build step — copy it and start changing things.

How a module works (the 30-second version) #

A module's UI runs in a sandboxed, opaque-origin iframe. It can't touch the platform directly — it can only postMessage the parent window, which runs the trusted capability bridge. Every request is gated by the module's declared permissions. That's the whole security model: declared → (approved) → scoped → audited.

So every browser module starts with the same tiny client:

js
// The entire bridge client. `call(type, payload)` sends one request and resolves
// with the reply (correlated by a request id). Copy this verbatim.
const PROTOCOL = 1, pending = new Map(); let counter = 0;
function call(type, payload = {}) {
  const rid = `r${++counter}`;
  return new Promise((resolve, reject) => {
    pending.set(rid, { resolve, reject });
    parent.postMessage({ v: PROTOCOL, type, rid, ...payload }, '*');
    setTimeout(() => { if (pending.has(rid)) { pending.delete(rid); reject(new Error('timed out')); } }, 15000);
  });
}
window.addEventListener('message', (e) => {
  const m = e.data; if (!m || !m.rid || typeof m.type !== 'string') return;
  const s = pending.get(m.rid); if (!s) return; pending.delete(m.rid);
  m.ok ? s.resolve(m.data) : s.reject(new Error((m.error && m.error.message) || 'failed'));
});
Prefer types? The published `@hanabi/module-sdk` wraps these messages in typed methods (client.data.put(...), client.queue.enqueue(...)). Same protocol, nicer ergonomics — see capability-api.md.

The samples, easiest first #

Foundations

ModuleTeachesBuild step?
hello-world-webpagea module is just a webpage in a windownone
svelte-scratchpadbuilding a module UI with Svelte + the bundlerSvelte

Single-task demos — one capability each

Each of these is focused on exactly one capability so you can read it in a minute and copy just the part you need. Every browser demo is one ui/index.html with the same inline bridge client above; each README also shows the SDK equivalent.

DemoCapabilityKind
demo-filesfiles.read + files.writebrowser
desktop-integration-demofiles.manage + desktop.* (VFS management, place on Desktop, shortcut, theme)browser
demo-notificationsnotifications (toast + badge)browser
demo-settingssettings.self (durable KV)browser
demo-storagestorage.read (usage/quota)browser
demo-mediaopenMedia (range streaming)browser
demo-officereadOffice / saveOffice (in-place .csv/.xlsx edit)browser
demo-inter-modulemodules.use (discover + handoff)browser
inventory-trackerdata.store (collections of JSON docs)browser
demo-schedulerjobs.schedule (interval/cron)browser
demo-client-webglclient.webgl (+ the client.* flags)browser
demo-pixiclient.webgl (PixiJS renderer, bundled + inlined)Svelte
broad-readerfiles.read.all (consent-gated broad read)Svelte
demo-worker-basicworker.execute (the run() contract)worker
demo-streaming-workerrun_streaming (A3 — large files, by path)worker
demo-task-queuejobs.queue (background enqueue/poll/cancel)worker
demo-fetch-workernetwork.fetch (declared-origin egress)worker
media-toolkit-workerworker.native (ffmpeg) + network.fetch.broadworker
worker.service (persistent services) is admin-only — there's no module-facing demo; see worker-guide.md and capability-api.md.

Combined references (kitchen-sink)

If you'd rather see many capabilities exercised in one place: capability-demo (the core bridge) and advanced-capabilities-demo (the newer data/queue/scheduler messages, with their security gates shown).

A suggested path

  1. Read `hello-world-webpage`, then any one demo-* — you now understand the iframe, the bridge, and one capability end to end.
  2. Build something with `inventory-tracker` — the data store is the workhorse for app-like modules (inventory, libraries, task managers). Baseline — declare it and go.
  3. Reach for the worker demos (demo-worker-basicdemo-task-queuemedia-toolkit-worker) when you need real compute — that's where the admin-HIGH grant flow becomes concrete.

Package & install a sample #

A module package is just a zip with hanabi.module.json at its root.

bash
# from the repo root
npm --workspace packages/module-cli run hanabi -- module pack examples/modules/inventory-tracker --out inventory-tracker.zip     # → a .zip

Then in the Toolbox: Module Store → Upload, choose the zip, install, and launch. First-party-style samples with only baseline/consent capabilities (1–5 above) run immediately. Samples that declare admin-approved or admin-HIGH capabilities (#6) must be published and granted first — that's the platform working as designed.

Where to read next #