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.

Quick Start

This guide builds a resource cost estimator from scratch. By the end you have a fully working tool with reactive computed results and automatic IndexedDB persistence — in about 30 lines of schema code.

Step 1: Add the module

nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    './websideproject/modules/protokit',
    // Optional: add yjs-sync to enable cross-device sync and server-side backups
    // './websideproject/modules/yjs-sync',
  ],

  // protokit options (all optional — defaults shown)
  protokit: {
    // serverSync: true,  // default: enabled (no-ops gracefully if yjs-sync is absent)
    // serverSync: false, // disable entirely — no HTTP requests, purely local
    // serverSync: { baseUrl: '/api/yjs' }, // custom server base URL
  },
})
serverSync defaults to true. If yjs-sync (or a compatible server) is not present, sync calls fail silently — local IndexedDB still works. Set serverSync: false to skip the HTTP calls entirely.

Step 2: Define the schema

Create a schema file anywhere in your project:

composables/schemas/resourceEstimator.ts
export const resourceEstimator = definePrototype({
  key: 'resource-estimator-v1',   // unique — also the IndexedDB key
  title: 'Resource Cost Estimator',

  fields: {
    teamSize: {
      type: 'number',
      label: 'Team Size',
      default: 3,
    },
    avgMonthlySalary: {
      type: 'number',
      label: 'Avg. Monthly Salary (€)',
      default: 4500,
    },
    toolingCosts: {
      type: 'number',
      label: 'Monthly Tooling Budget (€)',
      default: 300,
    },
    projectDurationMonths: {
      type: 'range',
      label: 'Project Duration (months)',
      min: 1,
      max: 24,
      step: 1,
      default: 6,
    },
    overheadPercent: {
      type: 'range',
      label: 'Overhead / Benefits (%)',
      min: 0,
      max: 60,
      step: 5,
      default: 25,
    },
  },

  derived: {
    monthlySalaryCost: {
      compute: ({ fields }) => fields.teamSize * fields.avgMonthlySalary,
      format: { type: 'money', currency: '' },
    },
    monthlyOverhead: {
      compute: ({ fields, derived }) =>
        derived.monthlySalaryCost * (fields.overheadPercent / 100),
      format: { type: 'money', currency: '' },
    },
    monthlyTotal: {
      compute: ({ fields, derived }) =>
        derived.monthlySalaryCost + derived.monthlyOverhead + fields.toolingCosts,
      format: { type: 'money', currency: '' },
    },
    projectTotal: {
      compute: ({ fields, derived }) =>
        derived.monthlyTotal * fields.projectDurationMonths,
      format: { type: 'money', currency: '' },
    },
  },

  results: {
    badge: ({ derived }) => {
      const cost = derived.projectTotal
      if (cost < 50_000)  return { label: 'Small Project',  color: 'primary' }
      if (cost < 200_000) return { label: 'Medium Project', color: 'warning' }
      return                    { label: 'Large Project',   color: 'error' }
    },
    stats: ({ derived }) => [
      { label: 'Monthly People Cost', value: derived.monthlySalaryCost, format: 'money' },
      { label: 'Monthly Overhead',    value: derived.monthlyOverhead,   format: 'money' },
      { label: 'Monthly Total',       value: derived.monthlyTotal,      format: 'money' },
      { label: 'Project Total',       value: derived.projectTotal,      format: 'money' },
    ],
  },

  visualizations: [
    {
      type: 'bar-chart',
      label: 'Monthly Cost Breakdown',
      items: ({ fields, derived }) => [
        { label: 'Salaries',  value: derived.monthlySalaryCost },
        { label: 'Overhead',  value: derived.monthlyOverhead },
        { label: 'Tooling',   value: fields.toolingCosts },
      ],
      format: 'money',
    },
  ],
})
definePrototype is a no-op identity function — it exists only for TypeScript inference. You can omit it and use a plain object if you prefer.

Step 3: Render it

pages/estimator.vue
<script setup lang="ts">
import { resourceEstimator } from '~/composables/schemas/resourceEstimator'
</script>

<template>
  <div class="max-w-2xl mx-auto p-6">
    <ClientOnly>
      <ProtoTool :schema="resourceEstimator" />
      <template #fallback>
        <div class="animate-pulse space-y-4">
          <div class="h-10 bg-muted rounded" />
          <div class="h-10 bg-muted rounded" />
        </div>
      </template>
    </ClientOnly>
  </div>
</template>

Step 4: See it work

npm run dev

Visit /estimator. Adjust the sliders. The derived values update instantly. Refresh the page — your values are still there, loaded from IndexedDB. No server call was needed to save them.

What you got for free

FeatureSource in schema
Form with labels and default valuesfields
Range sliders for duration and overheadtype: 'range' fields
Reactive computed totalsderived
Project size badgeresults.badge
Four stat cards below the formresults.stats
Bar chart of monthly breakdownvisualizations
IndexedDB persistence (survives refresh)Automatic via Y.js
Server sync when onlineAutomatic when protokit.serverSync is enabled + yjs-sync is installed
Corruption recovery modalAutomatic via useProtoDoc

Multiple independent instances

Provide a custom doc-key to run multiple instances of the same schema with separate storage:

<ClientOnly>
  <ProtoTool :schema="resourceEstimator" doc-key="estimator-project-a" />
</ClientOnly>
<ClientOnly>
  <ProtoTool :schema="resourceEstimator" doc-key="estimator-project-b" />
</ClientOnly>

Local-only / demo tools

Add disable-sync to any tool that should never push to the server — regardless of the global config. Useful for public demo pages where you don't want to accumulate server snapshots per visitor:

<ClientOnly>
  <ProtoTool :schema="resourceEstimator" disable-sync />
</ClientOnly>

The tool still saves to the user's local IndexedDB — inputs survive page refresh. Only the server push is suppressed.

Next steps

Need a Landing Page?

Modern landing pages with optional modules (blog, docs, forms, i18n). Let's discuss your project.

Build Your MVP

Full-stack SaaS development. Expert in database design, multi-tenancy, and scalable architecture.

Deployment Help

Dockerize your backend, set up CI/CD pipelines, deploy to Cloudflare or Hetzner. Early-stage setup.

Suggest a SaaS Tool

Missing a calculator or tool? Suggest what you'd like to see on our site.