Poi

The Rust of frontend

Solid reactivity.
Honest states.
Cost that never climbs.

Poi is a language where store is solid (leaf updates, not tree re-renders), ADTs are exhaustive (missing UI state = compile error), and fine-grained sinks keep runtime cost flat as the app grows. Constraints are the product — convenience is a side-effect.

store
signal graph, not hooks
match
exhaustive ADTs
O(1) leaves
mount once, update sinks
no off-switch
foreign stays unknown
01 · REACTIVITY

Solid store

Global dependency graph. Read = subscribe. get is lazy + cached. Component functions mount once; JSX sinks re-read. No useMemo lies.

02 · STATES

Exhaustive ADTs

Option · Result · Async · View sums. Missing empty / error / loading is a compile error — not a blank screen at 3am.

03 · SCALE

Never degrades

Fine-grained by default. One cell write → one leaf. List of 10 or 10,000: the write budget does not become O(N) re-renders.

Solid store

A real dependency graph — not a pretend tree re-render.

React re-renders the component (and often its children) on every setState. Poi tracks which cells each leaf reads. Write count → only count sinks fire. Sibling state stays cold.

Interactive · store write → who updates?

Left: typical React tree blast · Right: Poi graph + leaf sinks

React-style tree nodes/write0
App
Header
Sidebar
Counter
TodoList
Filters
Footer
Poi graph + leaves nodes/write0
atom0
get0
atomall
atom3
get3
JSX {'{count}'}
JSX {'{doubled}'}
badge {'{filter}'}
rows mapList

Click an action. Watch React light up the whole tree while Poi pulses only the dependency cone.

Algebraic data types

UI states you cannot forget to handle.

Fold loading / empty / error / rows into one View sum. The component only matches. Drop an arm — the program does not compile. No “blank panel until a user finds it.”

Interactive · CatalogView ADT

Current tag: Loading

Loading catalog…
LoadingView
CatalogRows(ps)
EmptyCatalog
ErrorView(msg)

            
Performance ceiling

Fine-grained by default — cost stays flat as N grows.

Scale the list. Tick a single cell write. React-style work units climb with N. Poi updates one leaf — always. That is not a clever memo trick you might forget; it is the language default.

Interactive · update budget vs list size

Work units per write · cumulative after ticks

React-style re-render work 64
Poi leaf update 1
Cumulative React work0
Cumulative Poi leaves0

Scale N, then tick. Orange flash = whole-tree simulation. Mint cell = the single Poi leaf that actually updates.

Mount once. Track what you read. Never pay for what you did not touch.

Why a language

Libraries can suggest. Languages can refuse.

Signals exist in JS. ADTs exist in TS. The difference is enforcement: Poi makes the solid path the only path that compiles.

Library world

  • Forget a dep array → silent stale UI
  • Miss an empty state → blank until prod
  • Trust JSON with as → runtime crash later
  • Performance is a discipline you might skip

Poi world

  • Deps are the read set — automatic
  • Non-exhaustive match → compile error
  • Foreign is unknown until match
  • Fine-grained leaves are the default, not a skill check

TS habit → Poi path

You reach forPoiWhy it stays solid
useState / zustand field store({ n: 0 }) Cell graph · read = subscribe
useMemo([deps]) get x() { … } Auto deps · lazy · cached · pure
Component re-render Leaf sinks / mapList Mount once · O(1) text updates
Scattered UI ifs View sum + match Missing arm = compile error
JSON.parse + cast parseJson + field match No as wash on unknown

Correct is downhill.
Fast is the default.

Shape the terrain so humans and AI both flow toward low entropy.