DevelopersQuickstart

Quick start

Get up and running with PWFabric in under 5 minutes.

Prerequisites

  • Node.js 22.0 or later
  • pnpm 10+ (this monorepo and its SDK are pnpm-only — npm and yarn are not supported)
  • A PhiWebs account at account.phiwebs.com/signup — you’ll need a worldId and an API token from World settings → Developers.
  • Basic TypeScript or JavaScript

1. Install the SDK

pnpm add @pwfabric/sdk

2. Create a client

createClient() returns a fully-typed PWFabricClient. Configure it with your World’s API base URL and the bearer token you minted in World settings.

import { createClient } from '@pwfabric/sdk'
 
const client = createClient({
  baseUrl: process.env.PWFABRIC_BASE_URL ?? 'https://api.phiwebs.com',
  token: process.env.PWFABRIC_TOKEN,
})

All client methods return a discriminated-union result ({ ok: true, data } | { ok: false, error }) so you pattern-match instead of try/catch.

3. Create your first Surface

client.surfaces.create() mints a new draft Surface inside your World. The blocks below all come from the first-party block catalog — container, heading, text, button, grid. (See the blocks reference for the full 45-block list.)

const result = await client.surfaces.create({
  name: 'My Landing Page',
  slug: 'landing',
  blocks: [
    {
      type: 'container',
      props: { maxWidth: 'lg', padding: 'lg' },
      children: [
        { type: 'heading', props: { content: 'Welcome to PWFabric', level: 1, align: 'center' } },
        { type: 'text', props: { content: 'Build beautiful Surfaces in minutes.', align: 'center', color: 'muted' } },
        { type: 'button', props: { label: 'Get started', href: '/developers/quickstart', variant: 'primary' } },
      ],
    },
    {
      type: 'grid',
      props: { columns: 3, gap: 'md' },
      children: [
        { type: 'text', props: { content: 'Fast — build in minutes' } },
        { type: 'text', props: { content: 'Flexible — customise everything' } },
        { type: 'text', props: { content: 'Composable — 45 block types' } },
      ],
    },
  ],
})
 
if (!result.ok) {
  throw new Error(`Surface create failed: ${result.error.message}`)
}
 
const surface = result.data

4. Render the Surface

The renderer lives in @pwfabric/runtime, not the SDK package. getBlockRegistryForWorld(worldId) loads the block registry the World has installed (per ADR-131 / ADR-122 the default registry is empty).

import { SurfaceRenderer } from '@pwfabric/runtime'
import { getBlockRegistryForWorld } from '@pwfabric/runtime/blocks'
 
async function Page() {
  const registry = await getBlockRegistryForWorld(surface.worldId)
  return <SurfaceRenderer surface={surface} registry={registry} />
}

Next steps