pyreon

signal-based · full-stack · ai-native

Reactivity that knows
exactly where to fire.

Fine-grained signal tracking — no virtual DOM, no diffing, no wasted work. When a signal changes, only the nodes that read it run again. Measured, not marketed — honest about the trade-offs.

Get started →$ npm create @pyreon/zero@latest my-app↗ docs

Synthetic row-list benchmark: ahead of Solid on most ops, behind it on deep-tree mount. Author-judged — no independent run yet.

LIVE · only the digit re-rendersfiring
count()42
// counter.tsx
const count = signal(0)
setInterval(() => count.update(n => n + 1), 2600)
<span>{count()}</span>

The wrapping component, the layout, the page — never re-render. Only the digit node is updated.

01 · benchmark · krausest-style row list (chromium / playwright)

The measured numbers. Read them as data.

Wall-clock milliseconds on a krausest-style row-list suite (Chromium via Playwright, lower = faster). These are synthetic workloads — every framework here optimizes for different real-world shapes. It's a data point, not a verdict.

frameworkcreate 1kreplace 1kupdateselectcreate 10k
●Pyreon8.838.640.6450.01588.31
Octane9.278.950.6750.02594.94
Solid9.479.301.300.02593.23
Vue 39.309.210.9900.30597.10
React 1911.2510.530.8550.185216.97

Source: BENCHMARKS.md §1 (2026-09-23 run). Select is below the clock resolution — no verdict. run yours · methodology in the repo.

METHOD

krausest-style row-list suite, Chromium via Playwright, wall-clock ms — same machine, same run, 100 pooled samples. Re-run it yourself; the config is in the repo.

SCOPE

We report our own measured numbers, losses included: Solid mounts a deep component tree 1.29× faster, and Octane ties us on partial update and swap. No independent run exists yet. Every framework here is good work by good people.

02 · mechanism · how it works

Signal reads in. Targeted re-runs out.

Four mechanisms, named the way the source names them — the words your profiler will print at 3am.

01~>
Value-level signal reads
Reading a signal inside an effect or template registers a dependency on that value. Writing notifies exactly those subscribers — never the component, never the tree.
02//
Compiled templates · _tpl / _bind
JSX compiles to static HTML templates plus per-signal bindings. Static parts hoist once at module load; only the bindings ever re-run.
03[]
Zero-alloc mount
Compiled templates allocate no virtual nodes and no diff array. Mount clones the template once and wires bindings straight to the DOM.
04>>
Streaming SSR + islands
Server renders to a stream with Suspense + async components. Islands hydrate independently — interactive before the tree settles.
03 · compat · use the api you know

React, Preact, Vue 3, SolidJS, or Svelte. Pick your dialect.

Compatibility layers compile each API down to Pyreon signals. Migrate one component at a time, or just write what your team already speaks.

React 18+↻ → signals
// useState → signal
const [c, setC] = useState(0)
useEffect(fn, [c])
Preact 10↻ → signals
// mirrors @preact/signals
const c = signal(0)
effect(() => log(c.value))
Vue 3.4↻ → signals
// composition · ref/computed
const c = ref(0)
const d = computed(() => c.value*2)
SolidJS 1.9↻ → signals
// createSignal / createEffect
const [c, setC] = createSignal(0)
createEffect(() => log(c()))
04 · zero · full-stack meta-framework

SSR · SSG · ISR · islands · SPA. One config.

Zero is the meta-framework atop Pyreon: file-system routing, API routes, server actions, every render strategy in one config.

vite.config.ts
zero({
  mode: 'ssr',
  ssr: { mode: 'stream' },
  routeRules: {
    '/':        { renderMode: 'ssg' },
    '/blog/**': { renderMode: 'isr' },
    '/app/**':  { renderMode: 'spa' },
  },
  isr: { revalidate: 60 },
  ai: { name, description, origin },
})
RENDER MODES
SSGPre-rendered at build to static HTML, then hydrated.
ISRServer-rendered, cached, revalidated after a TTL or on demand.
SSRRendered per request — as a string, or streamed with Suspense (ssr.mode).
SPAClient-only. Same component model, no server.
ISLANDSNot a mode: island() per component, in any mode. Hydrates independently.
05 · ai · for agents that read source, not guess it

First-class MCP + llms.txt.

Zero can generate an llms.txt for your app (zero({ ai })), and the scaffold can wire the @pyreon/mcp server, so agents query Pyreon's real API surface instead of guessing it.

llms.txt · auto-generated● in sync · CI-gated
# Pyreon
> Signal-based UI framework. Fine-grained, no VDOM.

## Core API
- signal: create a tracked reactive value
- computed: pure function of other signals
- effect: side effect, auto-tracked
- untrack: read without subscribing
MCP tool call · from your editor's agenttyped tools
→ get_api({ package: "reactivity", symbol: "createStore" })
← signature, example, notes, mistakes
  — generated from the package manifest,
  not a guess.
06 · ecosystem · counted, not exclaimed

77 packages. Routing, forms, data, devtools — already there.

Routing, state, styling, tooling, and native targets share the same reactive foundation.

core10
@pyreon/compiler · @pyreon/core · @pyreon/head · @pyreon/primitives · @pyreon/reactivity · @pyreon/router · @pyreon/runtime-dom · @pyreon/runtime-server · 2 more
fundamentals28
@pyreon/a11y · @pyreon/auth · @pyreon/charts · @pyreon/code · @pyreon/dnd · @pyreon/document · @pyreon/feature · @pyreon/flow · 20 more
native6
@pyreon/native-cli · @pyreon/native-compiler · @pyreon/native-router-kotlin · @pyreon/native-router-swift · @pyreon/native-runtime-kotlin · @pyreon/native-runtime-swift
tools16
@pyreon/atlas · @pyreon/cli · @pyreon/config · @pyreon/lathe · @pyreon/lint · @pyreon/loom · @pyreon/mcp · @pyreon/preact-compat · 8 more
ui-system11
@pyreon/attrs · @pyreon/connector-document · @pyreon/coolgrid · @pyreon/document-primitives · @pyreon/elements · @pyreon/kinetic · @pyreon/kinetic-presets · @pyreon/rocketstyle · 3 more
zero6
@pyreon/create-multiplatform · @pyreon/create-zero · @pyreon/meta · @pyreon/zero · @pyreon/zero-cli · @pyreon/zero-content
total · 77 packages · 6 categories