PulsePoint v2 is a backend-agnostic reactive engine: your server renders plain HTML, and one minified runtime adds fine-grained, component-scoped reactivity in the browser.
Introduction
Most stacks force a choice. A SPA gives you rich interactivity but splits your application into two projects, two languages of truth, and an API layer to keep them honest. Server-driven approaches keep one codebase but round-trip to the server for every interaction. PulsePoint takes a third path: the backend owns logic, data and templates; the browser owns interaction state. State lives in the browser where interaction happens, and updates hit only the DOM nodes that changed — no virtual DOM, no full-region swaps.
A complete component
This is not a fragment — it is the entire thing. No build step, no imports, no mounting call. The server prints it; the runtime finds it.
<div pp-component="hello_1">
<p>Count: {count}</p>
<button onclick="setCount(count + 1)">Increment</button>
<script>
const [count, setCount] = pp.state(0);
</script>
</div>
pp-componentmarks a reactive region with a unique id (your server generates it).{count}interpolates state into text or any quoted attribute.onclickis the native attribute — PulsePoint binds it to component scope.- The
<script>runs once per component instance with React-style hooks onpp.
How it compares
| SPA (React/Vue) | HTMX-style | PulsePoint | |
|---|---|---|---|
| Source of truth | Frontend app + API | Server | Server (logic/data) + browser (interaction state) |
| Build step | Required | None | None |
| Interaction latency | Local | One round-trip per interaction | Local; server only when you call pp.rpc() |
| Update granularity | VDOM diff | Region swap | Surgical DOM morph, keyed per row |
| Team surface | Two codebases | One | One |
Coming from React
The hook mental model transfers directly — and stops at the markup, which is plain HTML, never JSX.
| React | PulsePoint | Notes |
|---|---|---|
useState(0) |
pp.state(0) |
Identical [value, setter] tuple. |
useEffect(fn, deps) |
pp.effect(fn, deps) |
After-render effect with cleanup. |
useRef(v) |
pp.ref(v) |
Mutable { current } that never renders. |
useMemo / useCallback |
pp.memo / pp.callback |
Same dependency semantics. |
JSX |
Plain HTML |
No JSX. Lists use <template pp-for>, conditionals use hidden="{!cond}". |
Component function |
pp-component element + <script> |
The server renders the markup; the script holds the hooks. |
Where to go next
- Installation — one script tag, self-hosted or CDN.
- Plain HTML — a complete app in one static file, no backend.
- Directives & Public API — the complete, closed syntax surface.
- Implement In Your Backend — the wire contract for any server language.
- AI Integration — hand llms.md to your coding agent.