Skip to content
SLICES / TECHNICAL FOLIO Nº 001FULL-STACK ASSEMBLIES — OPEN SOURCE

Headless / Realtime

Collaborative canvas

Build collaborative whiteboard with the room's shared state and capability-aware controls.

32 public parts · 1examples

@slices.sh/realtime/headlessView as Markdown ↗

Your design. Our behavior.

Explore the tree to see what each part controls. Gates reveal the relevant state; roots outline their scope.

Behavior / inputGateGenericRenderer · not headlessScope
COMPONENT ANATOMYHover · focus · tap
ONE POSSIBLE DESIGNStatic preview

Room.Root · Scope

Room.RootThe room everything under here is in.

Installation

Choose what your component needs. Run these commands in an initialized Next.js app.

0

Before you start

The steps below run in a Next.js app with shadcn set up (it has a components.json). In an existing Next.js app, such as one from create-next-app, set shadcn up first:

npx shadcn@latest init -t next -b base -p nova

Or start fresh: the slices CLI creates the app and sets it up.

npx slices.sh install
1

Install the service registry

Adds services/index.ts, which import "@/services" loads. A provider setup writes the same file, so skip this if your app has one.

npx add services
2

Install the headless library

npm

Add the React parts to your app, then compose them with your own elements.

npm install @slices.sh/realtime@^0.1.6

Import from @slices.sh/realtime/headless.

3

Install the service

Connect the parts to a provider. Skip this step if this service is already configured in your app.

Provider
npx add realtime.p2p-mesh

Adds service configuration and API routes to your app, with the provider dependencies. For a headless composition, add import "@/services" after "use client".

The slices CLI installs the service and provisions its required resources in one command.

Provider setup notes

    Start small

    Parts bring the behavior. Use their default elements, or supply your own with render.

    example.tsx
    "use client"import "@/services"import { Room, Board } from "@slices.sh/realtime/headless"export function Example() {  return (    <Room.Root room="studio">      <Board.Root>        <Board.Tool tool="rect">Rectangle</Board.Tool>        <Board.Tool tool="select">Select</Board.Tool>        <Board.Surface>          <Board.Canvas>            <Board.Shapes>              <Board.Shape />            </Board.Shapes>          </Board.Canvas>        </Board.Surface>        <Board.Undo>Undo</Board.Undo>        <Board.Redo>Redo</Board.Redo>        <Board.Export>Export</Board.Export>      </Board.Root>    </Room.Root>  )}

    Configure realtime. Media, captions and moderation controls hide when the provider does not grant their capability.

    API reference

    Every public part used by this experience is listed below. Gates render children without adding an element. Element parts accept native element props and render; function children receive the state declared in their props. Scopes provide context rather than a visual element.

    Board.Rootscope

    A whiteboard in the room: an infinite surface of shapes everybody edits together, each person with their own view, tool, selection and history. `inks` says what each ink is on this screen and `outline` how a freehand line is shaped; both are looks, so both come from the screen. → hooks/realtime/board-look.ts Following somebody, from a face in a presence list or a `Room.Follow`, keeps their pointer in the middle of this person's view until this person takes the view back. → ./board-surface.tsx

    Required scope

    Board.Root must be inside <Room.Root>.

    Props

    2 documented props

    Board.Root props
    PropTypeDefault
    tools

    The tools this screen offers: the board starts on one of them and its keys pick no other, so no tool without a button can be in hand. Every tool when left out.

    readonly BoardTool[]—
    children

    Content rendered inside this part.

    ReactNode—

    Required props are marked. A dash means no explicit default is declared in this component.

    Also inherits Partial<BoardLook>. See TypeScript for the complete declaration.

    Source: @slices.sh/realtime/src/headless/board-root.tsx

    Board.Surfacecontent · <div>

    The board itself: where the pointer draws, pans and selects, and where the keyboard picks a tool — only while it has focus, so a letter typed in a chat beside it is a letter. The camera travels as `--board-x`, `--board-y` and `--board-zoom`, so a grid drawn in CSS moves with the board without a render per frame; `data-state` names the tool, for a cursor. A press, a wheel turn or Escape on it ends following somebody.

    Required scope

    Board.Surface must be inside <Board.Root>.

    Props

    2 documented props · Native <div> attributes supported

    Board.Surface props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode | ((state: { tool: string }) => ReactNode)—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-surface.tsx

    Board.Canvascontent · <svg>

    The drawing, in world units: an SVG whose one group the camera moves, so a pan is one attribute changing rather than every shape redrawn.

    Required scope

    Board.Canvas must be inside <Board.Root>.

    Props

    2 documented props · Native <svg> attributes supported

    Board.Canvas props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-canvas.tsx

    Board.Shapesscope

    Every shape on the board, bottom first, each in its own scope.

    Required scope

    Board.Shapes must be inside <Board.Root>.

    Props

    2 documented props

    Board.Shapes props
    PropTypeDefault
    group
    ComponentType<{ children?: ReactNode }>—
    children

    Content rendered inside this part.

    ReactNode—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-shapes.tsx

    Board.Shapecontent · <g>

    One shape, drawn. `data-state` is its type, `data-active` while it is selected; what it looks like is its own data and the screen's inks.

    Required scope

    Board.Shape must be inside <Board.Shapes>.

    Board.Shape must be inside <Board.Root>.

    Props

    2 documented props · Native <g> attributes supported

    Board.Shape props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode | ((state: { type: string }) => ReactNode)—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-shape.tsx

    Board.Selectioncontent · <g>

    The box around what is selected, with a handle on each corner and edge and one above it for turning — drawn in `currentColor` at the same size on screen however far the board is zoomed. The handles carry `data-handle` (`rotate` for the one above), which is how a drag on one resizes or turns rather than moves.

    Required scope

    Board.Selection must be inside <Board.Root>.

    Props

    2 documented props · Native <g> attributes supported

    Board.Selection props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-selection.tsx

    Board.TheirSelectionscontent · <g>

    What everybody else has selected: a dashed outline in their colour, their name on its corner — the same colour as their pointer, so a glance says whose hand is on what. Drawn at the same size on screen however far the board is zoomed.

    Required scope

    Board.TheirSelections must be inside <Board.Root>.

    Board.TheirSelections must be inside <Room.Root>.

    Props

    2 documented props · Native <g> attributes supported

    Board.TheirSelections props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-their-selections.tsx

    Board.Marqueecontent · <rect>

    The box a drag on empty board is drawing, in `currentColor`, while it is drawn.

    Required scope

    Board.Marquee must be inside <Board.Root>.

    Props

    2 documented props · Native <rect> attributes supported

    Board.Marquee props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-marquee.tsx

    Board.Laserscontent · <g>

    Everybody's laser: a line that fades from its tail, in `currentColor`, gone a second after the pointer stops. Nothing is written to the board.

    Required scope

    Board.Lasers must be inside <Board.Root>.

    Props

    2 documented props · Native <g> attributes supported

    Board.Lasers props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-lasers.tsx

    Board.Cursorsscope

    Everybody else's pointer on the board, each in the scope of the peer it belongs to.

    Required scope

    Board.Cursors must be inside <Board.Root>.

    Board.Cursors must be inside <Room.Root>.

    Props

    2 documented props

    Board.Cursors props
    PropTypeDefault
    perPerson

    One pointer per person — whichever of their tabs moved last — and none from your own other tabs, which are you. Off, every tab is a pointer of its own.

    booleanfalse
    children

    Content rendered inside this part.

    ReactNode—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-cursors.tsx

    Board.Cursorcontent · <div>

    One collaborator's pointer, placed on screen where it is on the board, with that person's colour as `--peer` and the ink that reads on it as `--peer-ink`. Just after somebody is picked to follow it says `data-state="pinged"` for a moment, for a skin to ring. It glides on the same spring as `Room.Cursor`, in board units, and the camera is applied as it is drawn: a pan or a zoom carries every pointer at once, while only a pointer's own samples move it along the board. → ./use-pointer-spring.ts

    Required scope

    Board.Cursor must be inside <Board.Cursors>.

    Board.Cursor must be inside <Board.Root>.

    Props

    2 documented props · Native <div> attributes supported

    Board.Cursor props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-cursor.tsx

    Board.TextEditorinput · <textarea>

    Typing into a shape: a text area laid exactly over it, at its size on screen. Every keystroke reaches the others as it is typed; leaving it — Escape, a click elsewhere — records one step of history, and a text left empty is taken away rather than left as an invisible shape somebody later cannot find.

    Required scope

    Board.TextEditor must be inside <Board.Root>.

    Props

    2 documented props · Native <textarea> attributes supported

    Board.TextEditor props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-text-editor.tsx

    Board.Emptygate

    Nothing on the board yet: where a first hint goes.

    Required scope

    Board.Empty must be inside <Board.Root>.

    Props

    1 documented props

    Board.Empty props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-empty.tsx

    Board.Summarygate

    What is on the board, in words, for somebody who cannot see it.

    Required scope

    Board.Summary must be inside <Board.Root>.

    Props

    1 documented props

    Board.Summary props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode | ((state: { shapes: number; selected: number }) => ReactNode)—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-summary.tsx

    Board.Toolaction · <button>

    Picks one tool. `aria-pressed` and `data-active` while it is the one in hand.

    Required scope

    Board.Tool must be inside <Board.Root>.

    Props

    3 documented props · Native <button> attributes supported

    Board.Tool props
    PropTypeDefault
    toolRequired
    "select" | "hand" | "pen" | "highlighter" | "eraser" | "laser" | "rect" | "ellipse" | "arrow" | "line" | "text" | "note" | "measure"—
    children

    Content rendered inside this part.

    ReactNode | ((state: { active: boolean }) => ReactNode)—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-tool.tsx

    Board.Stylinggate

    A style would change something: a shape is selected, or the tool in hand leaves one.

    Required scope

    Board.Styling must be inside <Board.Root>.

    Props

    1 documented props

    Board.Styling props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-styling.tsx

    Board.Styleaction · <button>

    One value of one style — an ink, a size, a dash, a fill — as a button. `aria-pressed` while it is the value in use; an ink carries its colour as `--ink`, for its swatch.

    Required scope

    Board.Style must be inside <Board.Root>.

    Props

    4 documented props · Native <button> attributes supported

    Board.Style props
    PropTypeDefault
    choiceRequired
    K—
    valueRequired
    ShapeStyle[K]—
    children

    Content rendered inside this part.

    ReactNode | ((state: { active: boolean }) => ReactNode)—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-style.tsx

    Board.Sizecontent · <div>

    The size of the next stroke, or of the selected shapes, as a slider with one stop for each size: arrows, Home and End step it, and pressing or dragging along it picks the nearest stop. The position travels as `--size-index` and `--size-at`, so a screen can draw a thumb and a filled track in CSS; the content function gets the stops, for drawing each one.

    Props

    3 documented props · Native <div> attributes supported

    Board.Size props
    PropTypeDefault
    labels

    What each size is called, for a screen reader to say as the slider's value.

    Record<InkSize, string>—
    children

    Content rendered inside this part.

    ReactNode | ((state: BoardSizeState) => ReactNode)—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-size.tsx

    Board.SizePreviewcontent · <span>

    What the size in use draws: its stroke width as `--size-dot`, in the ink in use as `--ink`. A screen makes a dot of it, which grows as the slider moves up.

    Required scope

    Board.SizePreview must be inside <Board.Root>.

    Props

    2 documented props · Native <span> attributes supported

    Board.SizePreview props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-size-preview.tsx

    Board.Opacityinput · <input>

    How opaque, from a tenth to whole, as a slider.

    Props

    2 documented props · Native <input> attributes supported

    Board.Opacity props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-opacity.tsx

    Board.Selectedgate

    Something is selected: what acts on a selection belongs here.

    Required scope

    Board.Selected must be inside <Board.Root>.

    Props

    1 documented props

    Board.Selected props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode | ((state: { count: number }) => ReactNode)—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-selected.tsx

    Board.Deleteaction · <button>

    Deletes what is selected, as one step you can undo.

    Required scope

    Board.Delete must be inside <Board.Root>.

    Props

    2 documented props · Native <button> attributes supported

    Board.Delete props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-delete.tsx

    Board.Arrangeaction · <button>

    Moves what is selected up or down the pile: `to` is `front`, `forward`, `backward` or `back`. Unavailable with nothing selected. Everybody sees the new order, and it is not a step of history — undo takes back what was drawn, not where it lies.

    Required scope

    Board.Arrange must be inside <Board.Root>.

    Props

    3 documented props · Native <button> attributes supported

    Board.Arrange props
    PropTypeDefault
    toRequired
    "front" | "forward" | "backward" | "back"—
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-arrange.tsx

    Board.Undoaction · <button>

    Takes back the last thing you did on the board — never anybody else's.

    Required scope

    Board.Undo must be inside <Board.Root>.

    Props

    2 documented props · Native <button> attributes supported

    Board.Undo props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-undo.tsx

    Board.Redoaction · <button>

    Does again what you last took back.

    Required scope

    Board.Redo must be inside <Board.Root>.

    Props

    2 documented props · Native <button> attributes supported

    Board.Redo props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-redo.tsx

    Board.Zoomaction · <button>

    Zooms the view, about its middle.

    Required scope

    Board.Zoom must be inside <Board.Root>.

    Props

    3 documented props · Native <button> attributes supported

    Board.Zoom props
    PropTypeDefault
    toRequired

    In, out, the whole drawing, or back to actual size.

    "in" | "out" | "fit" | "actual"—
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-zoom.tsx

    Board.ZoomLevelcontent · <span>

    The zoom as a person reads it: "100%".

    Required scope

    Board.ZoomLevel must be inside <Board.Root>.

    Props

    2 documented props · Native <span> attributes supported

    Board.ZoomLevel props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-zoom-level.tsx

    Board.Minimapcontent · <svg>

    The whole board small, with the part you are looking at outlined: press or drag on it to go somewhere else. Shapes are boxes in their own ink, which is all a map needs to be.

    Required scope

    Board.Minimap must be inside <Board.Root>.

    Props

    2 documented props · Native <svg> attributes supported

    Board.Minimap props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-minimap.tsx

    Board.Exportaction · <button>

    Saves the drawing as an SVG file: every shape, framed, with the colours the page is showing written into it — the inks are theme tokens, and a file opened elsewhere has no theme.

    Required scope

    Board.Export must be inside <Board.Root>.

    Props

    3 documented props · Native <button> attributes supported

    Board.Export props
    PropTypeDefault
    name
    string"board"
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-export.tsx

    Board.RulerToggleaction · <button>

    Rulers on or off. `aria-pressed` while they are shown.

    Required scope

    Board.RulerToggle must be inside <Board.Root>.

    Props

    2 documented props · Native <button> attributes supported

    Board.RulerToggle props
    PropTypeDefault
    children

    Content rendered inside this part.

    ReactNode | ((state: { on: boolean }) => ReactNode)—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-ruler-toggle.tsx

    Board.Rulercontent · <svg>

    A ruler along one edge of the board, in the unit chosen, following the camera. Ticks and numbers are `currentColor`; nothing while rulers are off.

    Required scope

    Board.Ruler must be inside <Board.Root>.

    Props

    3 documented props · Native <svg> attributes supported

    Board.Ruler props
    PropTypeDefault
    edgeRequired
    "top" | "left"—
    children

    Content rendered inside this part.

    ReactNode—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-ruler.tsx

    Board.Unitaction · <button>

    Measure in one unit. `aria-pressed` while it is the one in use.

    Required scope

    Board.Unit must be inside <Board.Root>.

    Props

    3 documented props · Native <button> attributes supported

    Board.Unit props
    PropTypeDefault
    unitRequired
    "px" | "cm" | "in" | "m"—
    children

    Content rendered inside this part.

    ReactNode | ((state: { active: boolean }) => ReactNode)—
    render

    Replace the default element with your own while retaining the part’s behavior and accessibility.

    ReactElement—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/board-unit.tsx

    Room.Rootscope

    The room everything under here is in. Joining happens in the provider's effect rather than here, so a component that renders twice before it commits does not put two peers in the roster for one tab. A root inside a root for the same room shares its connection, and its follow too: a presence list placed on a canvas has to move the canvas when somebody on it is picked, and two follows would be two lists of whom somebody is following. A root inside a root for the same room needs no service of its own, and says nothing when there is none. Optional with no service, or off, there is no room: its status is "off", so every gate stays shut and `Room.Present` hides what the room is drawn inside, and its sink is switched off, so a Composer inside renders nothing. → ../hooks/use-realtime-scope.ts

    Props

    8 documented props

    Room.Root props
    PropTypeDefault
    config

    The realtime config, a slug from the registry (services/realtime/<config>.config.ts). The nearest root's, else "default", when left out.

    string—
    enabled

    Left out or true: required, and a missing service throws. "optional": renders its children, its parts render nothing, and its sink is switched off. false: off. A capability name ("relay") requires the service and that capability.

    Enabled—
    roomRequired
    string—
    profile

    Who this browser shows itself as. Without one, a visitor gets an animal of their own; and somebody signed in is their session's name and picture whatever this says.

    PeerProfile—
    perPerson

    One person across this browser's tabs: every tab takes the same name, the one a screen that counts people shows once. Off, each tab is somebody of its own.

    boolean—
    media

    Off, the transport never asks for a camera or a microphone.

    boolean—
    captions

    Captions start shown; each person can still hide them for themselves.

    boolean—
    children

    Content rendered inside this part.

    ReactNode—

    Required props are marked. A dash means no explicit default is declared in this component.

    Source: @slices.sh/realtime/src/headless/room-root.tsx

    When something is missing

    No service configuration
    Install the realtime setup below and import "@/services". Required service roots report missing setup; gates do not replace that configuration.
    Missing capability or parent scope
    Follow each part’s context requirements and the example composition. Capability-aware controls hide when the provider cannot perform their action.
    Read the setup guide →