pocopine-codec

Shared encoding/codec utilities (base64, percent-encoding, serde adapters) for the pocopine workspace.


Licenses
MIT/Apache-2.0

Documentation

pocopine mascot

pocopine

A full-stack Rust application framework — reactive Rust/WASM UI, type-safe server functions, a local-first data layer, auth, storage, background jobs, and one-command deploy. One language, end to end.


pocopine is a full-stack application framework written in Rust. The front end is a directive-driven Rust/WASM UI layer: a Vue-3-style reactive core (real Proxy traps, auto dep-tracking) wired into compiled .poco template plans, with tag-based components and a built-in SPA router. The back end is reached through a type-safe server-function bridge — write an async fn, call it from the client as a typed stub. Around that core sits a set of opt-in crates for the rest of an application: a query-centric data layer, auth, object storage, live updates, background jobs, observability, and deploy adapters.

Templates live in plain HTML files (.poco), styles in plain CSS files, logic in plain Rust files. No mixed-language SFCs, no virtual DOM, and no JavaScript toolchain unless you opt into Pocopine-managed typed .client.ts modules. One canonical way per decision — the framework is opinionated so application code stays small.

Status: pre-1.0 / experimental. The API is still moving; every breaking change lands in an RFC under rfcs/.

// examples/counter/src/lib.rs
use pocopine::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Default, Serialize, Deserialize)]
#[component]
pub struct Counter { pub count: i32, pub label: String }

#[handlers]
impl Counter {
    pub fn increment(&mut self) { self.count += 1; }
    pub fn decrement(&mut self) { self.count -= 1; }
}

#[wasm_bindgen(start)]
pub fn main() { App::new().register::<Counter>().run(); }
<!-- examples/counter/src/Counter.poco -->
<div>
  <p><strong pp-text="count"></strong> <span pp-text="label"></span></p>
  <button pp-on:click="decrement">-</button>
  <button pp-on:click="increment">+</button>
</div>
<!-- examples/counter/index.html -->
<body>
  <counter label="clicks"></counter>
  <script type="module">
    import init from "/pkg/counter.js";
    init();
  </script>
</body>

That's the whole counter. No virtual DOM, no build step beyond pocopine dev, no Rc<RefCell<_>> in the author's code.

Get started in 60 seconds

1. Install the CLI

The pocopine CLI handles building, serving, and hot-reload — one install covers all three.

cargo install pocopine-cli

From a source checkout, use the repo helper:

./install.sh
pocopine doctor --path .

2. Scaffold an app

A pocopine app is a regular Rust library crate. Add pocopine (runtime) and, optionally, pine (UI primitives).

cargo new --lib hello-pine
cd hello-pine
cargo add pocopine pine

3. Write your first component

A component is a Rust struct plus a sibling .poco template.

// src/lib.rs
use pocopine::prelude::*;

#[derive(Default, Serialize, Deserialize)]
#[component(template = "Counter.poco")]
pub struct Counter { pub n: u32 }

#[handlers]
impl Counter {
    pub fn bump(&mut self) { self.n += 1; }
}

#[wasm_bindgen(start)]
pub fn main() {
    App::new().register::<Counter>().run();
}
<!-- src/Counter.poco -->
<button @click="bump">
  clicked <strong pp-text="n"></strong> times
</button>

4. Run it

pocopine dev builds the wasm bundle, serves it on a local port, and rebuilds on save.

pocopine dev
# → listening on http://127.0.0.1:5243

Ship with pocopine build --release, then pocopine deploy.

The stack

pocopine is a Cargo workspace. Apps depend on the pocopine façade crate (runtime + prelude) and add only the modules they need. Each module is documented under docs/.

Core & rendering

Crate What it does
pocopine The façade crate apps depend on: runtime re-exports + prelude.
pocopine-core Reactive runtime — signals, effects, component scopes, directives, router. A Rust/WASM port of Alpine.js.
pocopine-macros #[component], #[handlers], #[store], #[server].
pocopine-template-parser Host-only .poco parser (html5ever); shared by the macros and Stylekit. Never linked into wasm.
pocopine-expr Pure-Rust template-expression grammar (RFC 012), shared by the runtime evaluator and compile-time validation.
pocopine-stylekit Pine Stylekit — a Pocopine-native, Tailwind-shaped utility-CSS compiler. Build-time only, no browser runtime.

Pine — UI primitives

Crate What it does
pine Unstyled, accessible UI primitives (Button, Dialog, Popover, …) ready to style.
pine-icons Tabler Icons as a tree-shaken Pine component.
pine-charts SVG-first chart primitives.
pine-motion Motion.dev-style animation — springs, gestures, drag, scroll, shared-layout (FLIP).
pine-richtext Rust-native rich-text document model + editor state, with an optional browser view.

Server & types

Crate What it does
pocopine-server Host-side helpers for #[server] functions: axum integration + static-file serving.
pocopine-client-codegen Discovery + typed-facade generation for managed .client.ts modules.
pocopine-ts-rs Rust → TypeScript DTO generation (a Pocopine-owned fork of ts-rs).

Data & sync

Crate What it does
pocopine-sync-query Query-centric, local-first data layer: filtered subscriptions, predicate-routed mutations, reactive selectors, typed writes.
pocopine-sync Sync protocol + server plugin the query layer rides on.
pocopine-sync-sqlite / -indexdb Local-store backends (server/native and browser).
pocopine-storage Object-storage protocol + server-mediated uploads, with -s3, -gcs, and -azure backends.

Auth

Crate What it does
pocopine-auth Auth contracts + server-function guards.
pocopine-auth-credentials First-party email + password (argon2id, signup/login/logout as a ServerPlugin).
pocopine-auth-jwt JWT verification for Firebase, Clerk, Auth0, Supabase, custom OIDC, and pocopine-issued tokens.
pocopine-auth-client Wasm-side bearer-token bridge + fetch middleware.

Realtime & background work

Crate What it does
pocopine-live Browser live-invalidation streams (SSE) for collection/query refresh.
pocopine-events Event envelopes, cursors, and backends for live features.
pocopine-jobs Background jobs — Redis Streams + scheduler, periodic firings, reclaim, in-memory backend.

Observability

Crate What it does
pocopine-observe Shared observability event contract for logging, tracing, and analytics.
pocopine-logging Logging adapters for server and browser.
pocopine-analytics Analytics + telemetry adapters.

Deploy & ops

Crate What it does
pocopine-cli pocopine build | run | dev | deploy.
pocopine-deploy Deploy contract + adapters (RFC 080), with -railway and -render. Host-API-direct; no host CLIs.
pocopine-launcher Procfile-style entrypoint for the production OCI image.

Shared utilities

Crate What it does
pocopine-crypto Centralized hashing + checksum primitives (sha2, hmac, crc32c).
pocopine-codec Shared encoding (base64, percent-encoding, serde adapters).

Documentation & tutorials

Full guides and tutorials live under docs/. Start here:

Concepts & guides

Tutorials (build something end to end)

Examples

Drop into any one with pocopine dev --path examples/<name>:

Example What it shows
counter Single component, basic directives
todo Multi-component, slots, stores
blog App + #[server] + axum server bin
spa Router + <pp-outlet> + pp-route
hn Full SPA — routing, server fns, transitions, pp-for
sync Query data layer + pocopine-live wake-ups
live SSE live invalidation + collection/query refresh
charts pine-charts primitives
richtext pine-richtext editor
file-browser Storage browser shell for S3/MinIO
website Pine UI — every primitive, side-by-side
site The marketing page, dogfooded
tailwind Tailwind v4 + .poco scanning (fallback styling)

Architecture

Three layers you can reach for independently, with the application modules layered on top:

  1. Runtime — reactive engine, component scopes, directives, and the adopted-DOM bridge for dynamic HTML. No virtual DOM; mutations happen in place against real DOM nodes.
  2. Templates.poco files are pure HTML with pp-* directives. The #[component] macro wires them to Rust structs, emits static template metadata, and specializes eligible binding/listener installs at compile time.
  3. Server functions#[server] async fn on the backend; the client gets a typed stub that POSTs to /_pocopine/<fn_name> and deserializes the response. Works with any serde-compatible type.

On top of those sit the opt-in application modules — data/sync, auth, storage, live, jobs, observability — most of which install as app plugins (browser) or server plugins (host) through a single lifecycle boundary. See docs/guides/plugins/app-plugins.md.

Authoritative design decisions live in rfcs/; narrative design notes live in docs/.

Directives

pp-text, pp-html, pp-bind:<attr>, pp-on:<event>, pp-show, pp-model, pp-init, pp-for, pp-if, pp-cloak, pp-transition:*, pp-teleport, pp-ref, pp-route. Component templates and lifted pp-if / pp-for / pp-teleport bodies install through macro-generated closures rather than a generic runtime applier.

Performance

The js-framework-benchmark keyed-table action plan, run locally under headless Firefox against pinned Rust/WASM and JS competitors. Numbers are wall-clock geometric means (lower is better); vanilla is the control because browser timing drifts between runs.

framework geomean (ms) vs vanilla
vanilla JS 185.41 1.00×
Vue 3 202.17 1.09×
pocopine 215.92 1.16×
Yew 225.07 1.21×
Leptos 281.45 1.52×

No virtual-DOM diff runs in the hot path; generated template code and fine-grained Proxy reactivity mutate real DOM nodes in place. Reproduce locally with the harness under jsbench/:

./jsbench/benchmark.sh pocopine --browser firefox --no-build
./jsbench/benchmark.sh --all --browser firefox

Styling

Pine Stylekit is the default way to style pocopine apps — a native utility-CSS compiler with Tailwind-shaped classes, compiled in-process at build time (no external watcher, no Node). It runs by default: write utility classes in .poco templates, declare colours in an @theme block, link /pkg/stylekit.css, and pocopine build/dev does the rest. It parses .poco with the real compiler (not text scanning) and fails loud on typos with source spans. See docs/guides/styling/stylekit.md.

<link rel="stylesheet" href="/pkg/stylekit.css" />

Prefer Tailwind? It stays a first-class fallback — add a [package.metadata.pocopine.tailwind] block (with no [stylekit] block) and Stylekit defers to it; the CLI downloads the standalone binary and runs it alongside the build. DaisyUI works as a plugin. See docs/guides/styling/stylekit.md for both paths.

Development

# cross-target checks (apps build for wasm32)
cargo check --workspace --target wasm32-unknown-unknown
cargo clippy --workspace --all-targets -- -D warnings

# core unit tests
cargo test -p pocopine-core --lib

PRs welcome — non-trivial features should open an RFC first (or be paired with one in the same PR). See rfcs/README.md for the convention.

Inspiration

  • Alpine.js — the directive model and author ergonomics.
  • Vue 3 — the Proxy-based reactive core.
  • Headless UI — the <Transition> API that pp-transition:* mirrors.
  • Solid / Leptos — fine-grained reactivity references.

License

Dual-licensed under either of

at your option.