A core that never breaks.
Widgets that just plug in.

Stactora isn't a monolithic app; it's an ecosystem. Built on a resilient core API and a modular widget registry, it adapts to your workflow without bloating.

0
Framework dependencies
1
Event bus binds them all
0+
Pluggable widget types
0%
Offline-capable

Trace a call through the bus.

[ hover / tap a module ] watch the route light up

Everything a widget ever sees.

my-first-widget.js — simplified registry surface
// The core never imports you. You introduce yourself.
Stactora.registerWidget({
  id:     'reading-list',       // unique, namespaced
  name:   'Reading List',
  icon:   'book',
  mount(ctx)  { ctx.render('<p>hello</p>') },   // build UI
  onEvent(e)  { if (e.type === 'timer:tick') {} },
  storage:    ctx.store('reading-list')         // private sandbox
});

Names trimmed for legibility — the shape is the point: you bring behavior, the core brings guarantees.

Built on solid foundations.

Widget Registry Pattern

Widgets aren't hardcoded. They register themselves through a central API. The core only knows the interface, never the specific widget logic.

Consequence: the core contains zero imports of any widget file.

Independent State

Every widget owns its data, storage keys, and UI subtree. The shared API handles drag, resize, autosave, and import/export automatically.

Consequence: one crash never takes your workspace down.

Local-First Storage

Powered by IndexedDB. Your data lives in your browser, not on a remote server — instant loads, full offline capability, absolute privacy.

Consequence: reads resolve faster than any cloud round-trip.

Failure drill: if a widget throws during an event, the bus quarantines it — suspends its subscriptions while the remaining modules continue uninterrupted. Reload the page and healthy widgets come back exactly as you left them.

From UI to storage.
Four layers. Zero leaks.

Data flows cleanly downward through isolated boundaries, keeping the UI reactive and storage safe.

01User Interaction

You drag a widget or check a task. The UI Canvas layer registers the input instantly and fires an event up to the Core API.

emit('drag:start', { id:'widget-tasks' })

Asked by people who read source maps.

Can I build my own widget?
Yes — that's the entire point of the registry. A widget is a self-describing object registered through the public API: it declares an ID, mounts its UI, optionally listens to bus topics, and gets its own sandboxed storage namespace. The loader discovers widget folders automatically; the core never learns your internals.
What happens if a widget crashes?
The bus quarantines it: failing handlers are suspended rather than propagated, and error metadata lands on the diagnostics topic. Your other widgets keep rendering, autosave keeps firing, and a reload brings everything back except the misbehaving module.
Where does my data physically live?
In IndexedDB — an origin-scoped database inside your browser on your disk. Writes are structured clones, reads are asynchronous and local. There is no upload path in the product; the only way data leaves your device is you pressing Export.
Does the architecture depend on CDNs or the internet?
No. Core, tools, and widgets ship as plain local JavaScript — no framework runtime fetched at boot, no bundled megabytes pulled from a vendor edge. Google Fonts are the only remote nicety, and pages degrade gracefully to system fonts offline.

Inspect. Extend. Own it.

An architecture designed to adapt to you — not the other way around.

Start Free Widget Guides
No signup·Works offline·Your data stays local·Export anytime