Lucentive Labs
Lucentive Labs Docs
Working with agents

Interactive tutorial

Edit a Loupe config in the browser, render it live, lock tiles, and watch the deterministic export brief recompute.

This is Loupe with the lid off. Edit the JSON config on the left and hit Render (or ⌘/Ctrl + Enter). A real <Loupe /> mounts below; lock tiles and the deterministic export brief on the right recomputes in real time — the same selectExportBrief derivation a build pass would call.

Everything runs in your browser. The config is parsed with parseConfig, checked with validateConfig, and any error shows under the editor — so you also get a feel for how the contract rejects bad input.

loupe.config (JSON)

config valid — rendered below

export brief (markdown)
My direction
2 of 2 locked
01
Color system
Which palette carries the brand?
02
Headline voice

Build brief

The deterministic handoff for the next build pass. Stays in sync with your locked tiles.

Banned

  • Generic SaaS gradient blobs.

Try these edits

Change a label and re-render

Change "label": "Bold sans" to something of your own, press ⌘/Ctrl + Enter, and watch the tile and the brief update together.

Add a third option to a group

Copy an option object inside an options array, give it a unique id, and re-render. A group allows 2–6 options.

{
  "id": "editorial",
  "label": "Editorial serif",
  "specimen": {
    "kind": "type",
    "family": "Georgia, 'Times New Roman', serif",
    "weight": 500,
    "sample": "A warmer way to ship."
  }
}

Add a whole new group

Add a layoutMock decision and watch it appear as a new section with a wireframe tile:

{
  "id": "hero",
  "title": "Hero layout",
  "prompt": "How does the first screen open?",
  "options": [
    { "id": "portrait", "label": "Statement portrait", "recommended": true, "specimen": { "kind": "layoutMock", "plan": "portrait" } },
    { "id": "sparse", "label": "Sparse, text-led", "specimen": { "kind": "layoutMock", "plan": "sparse" } }
  ]
}

Break it on purpose

Give two options the same id, or point a preview band at a group that does not exist, and re-render. The error panel shows the exact validateConfig message — the same gate the generator and the agent loop use.

Watch the brief, then lock by hand

After rendering, click tiles in the live picker. The brief on the right tracks your actual picks (not just the recommended defaults) via onLockChange — proving preview and brief never drift from the same selections.

Why is there an explicit Render button instead of live-parsing every keystroke? <Loupe /> owns a store keyed on config identity, so re-parsing on each character would reset your picks. The playground commits a new config only when you ask, and recomputes the brief live from your selections in between.

What just happened

The playground is ~80 lines and uses nothing the docs do not document:

  • parseConfig + validateConfig from loupe-schema to compile and gate the edited JSON;
  • <Loupe /> from loupe-react to render it, with onLockChange reporting selections;
  • recommendedSelections + selectExportBrief from loupe-core to derive the brief from those selections.

That is the entire contract. From here, the agent method is the same loop run headless: author the config, generate a portable artifact, screenshot-verify it, export the brief.