Atomica is a tiny, signal-first view library with fine-grained DOM bindings. Components are plain functions; state changes update only the nodes that depend on that state. No renders, no lifecycles, no hooks.
v0.3 semantics locked · Repository: github.com/xgeoff/atomica
() => expr); no hidden subscriptions.docs/samples/*.ts.atomica — public barrel, re-exporting DOM + signalsatomica/companion — optional channels, service wrapper, and registry helpers (opt-in)atomica/signals — signals, computed, effect, batch, untrack, resource, diagnosticsatomica/dom — VNode factory (h), renderer, bindings, context, mount/unmountatomica/shared — utilities and dev diagnostics plumbingInstall Atomica from npm in your project:
npm install atomica
# or: pnpm add atomica
# or: yarn add atomica
# or: bun add atomica
Then import what you need in your app entry file:
import { h, mount, signal, computed, effect } from 'atomica';
Or import explicit subpaths:
import { signal, computed, effect, resource } from 'atomica/signals';
import { h, mount, Fragment, context } from 'atomica/dom';
import { signal, computed, effect, batch, untrack, resource } from 'atomica/signals';
signal<T>(value) → { get, set, peek }computed(fn) → lazy memo { get, peek }effect(fn) → runs immediately, re-runs on dependency changes; returns dispose()batch(fn) → coalesces effect flushes until fn finishesuntrack(fn) → run without dependency collectionresource(producer, options?) → async state machine (manual or auto), latest-wins, abortableCore DOM helpers are exported from atomica/dom. See the API reference for complete props and diagnostics.
import { h, mount, Fragment, context } from 'atomica/dom';
h(type, props, ...children) creates a VNode (tag or component fn)fragment(...children) / Fragment groups childrentext(value) forces a text VNodemount(vnode | Component, container, options?) renders and returns dispose()context(defaultValue, options?) → lexical, synchronous context; not reactive unless you pass signals() => X becomes a live bindingh('div', { class: () => theme.get() })h('p', null, 'Value: ', () => count.get())key to preserve DOM identitywindow.__ATOMICA_DEV__ (dev builds) tracks:
examples/counter — minimal signal + binding demo. Run: pnpm --filter @atomica/example-counter dev.examples/playground — living spec proving invariants. Run: pnpm --filter @atomica/playground dev.examples/github-issues — real app with resource/context/diagnostics under v0.2. Run: pnpm --filter @atomica/example-github-issues dev.examples/search-widget — drop-in component with encapsulated HTML/CSS/JS. Run: pnpm --filter @atomica/example-search-widget dev.examples/bind-input — tiny demo of bindInput. Run: pnpm --filter @atomica/example-bind-input dev.pnpm build — builds all packages and examplespnpm test — runs Vitest suites (signals, dom)Semantics are frozen per docs/v0.2-design-contract.md; ergonomic tweaks must not violate invariants.