Core Concepts
Core Concepts
Five ideas underpin everything in protokit. Understanding them makes the rest of the docs straightforward.
1. The schema is the single source of truth
A PrototypeSchema object controls every aspect of a prototype:
PrototypeSchema
├── fields → form inputs rendered by ProtoForm
├── sections → grouped form inputs (tabs or collapsible panels)
├── collections → CRUD lists (tasks, records, entries…)
├── derived → computed values recomputed on every change
├── results → badge + stat cards shown below the form
├── visualizations → charts, tables, timelines
├── cards → summary cards for dashboard views
├── actions → copy, export-markdown, reset with confirmation
├── produces → keys this prototype writes to the shared output map
├── consumes → upstream prototype.field paths this prototype reads
└── layout → custom dashboard layout (tabs, rows, columns)
You define the schema once. Every component — form, results, visualizations, CRUD modals — reads from it at runtime. Changing a field label is one line.
2. Every prototype lives in a Y.js document
Every prototype is backed by a Y.js document (Y.Doc). Y.js is a CRDT library that provides:
- Shared data types:
Y.Map(key-value),Y.Array(ordered list),Y.Text(plain text) - Local-first storage: changes go to IndexedDB immediately, before any network round-trip
- Automatic merge: concurrent edits in multiple tabs or devices merge without conflicts
When you write <ProtoTool :schema="mySchema" doc-key="my-tool" />, the module:
- Opens (or reuses) a
Y.Docidentified bydoc-key - Attaches
IndexeddbPersistence— the doc survives page reloads - Starts syncing to the server when connectivity is available (via the
yjs-syncmodule)
Y.Doc "my-tool"
┌──────────────────────────────┐
│ Y.Map "fields" │ ← form state
│ Y.Map "outputs:my-tool" │ ← produces values
│ Y.Array "collection:items" │ ← CRUD items
│ Y.Map "draft:item-abc" │ ← modal draft
└──────────────────────────────┘
│ ▲
IndexedDB server sync
(always) (when online)
3. Derived values are pure functions
Derived values are synchronous, side-effect-free functions that transform the current state into a new value:
derived: {
monthlyCost: {
compute: ({ fields }) => fields.seats * fields.pricePerSeat,
format: { type: 'money', currency: '€' },
},
annualCost: {
compute: ({ fields, derived }) => derived.monthlyCost * 12,
format: { type: 'money', currency: '€' },
},
}
The compute function receives a ComputeContext:
| Property | Type | Contains |
|---|---|---|
fields | Record<string, any> | Unwrapped current field values |
derived | Record<string, any> | Previously computed derived values (definition order) |
connections | Record<string, any> | Data flowing in from upstream tools |
collections | Record<string, any[]> | CRUD collection items |
Derived values are computed in definition order. A derived value may reference earlier ones via derived.earlier, but referencing a later key returns undefined.
4. Produces / Consumes — the data graph
Prototypes can share computed data without tight coupling via produces and consumes:
// Prototype A — writes to a shared output map
produces: {
unitCost: 'derived.unitCost',
margin: 'derived.contributionMargin',
}
// Prototype B — reads from Prototype A's output map
consumes: {
upstreamUnitCost: 'prototype-a.unitCost',
}
Internally:
produceswrites values into aY.Mapnamedoutputs:{schemaKey}consumesreads from the source tool'soutputs:map, exposing values inctx.connections
When both prototypes share the same Y.Doc (the recommended pattern), data flows instantly and offline. When they use separate documents, useProtoConnections observes the source document reactively.
5. Collections are Y.Arrays with schema-driven CRUD
A collection is a persistent, offline-capable list of structured items:
collections: {
tasks: {
label: 'Tasks',
fields: {
title: { type: 'text', label: 'Title', required: true },
priority: { type: 'segmented', label: 'Priority',
options: [
{ value: 'low', label: 'Low' },
{ value: 'medium', label: 'Medium' },
{ value: 'high', label: 'High' },
] },
done: { type: 'toggle', label: 'Done', default: false },
},
searchable: true,
editMode: 'modal',
}
}
The useProtoCollection composable wraps the underlying Y.Array and provides reactive items, add, update, remove, move, search, filtered, sorted, and count — all working offline automatically.
Introduction
What protokit is, what problems it solves, and how it fits into a Nuxt 4 project.
Quick Start
Build your first tool in under 10 minutes — a resource cost estimator with form inputs, derived values, a result badge, and automatic offline persistence.