WhiteLabelStory
Generated from front/ui/catalogue/examples/WhiteLabelStory.json
section · interactive (ships a small web component) · no children. All components: component playground.
Description for the model
Section titled “Description for the model”The white-label story of the product landing in four animated steps (an agent with the ulams CLI and a design tool’s MCP reads a brand and applies its tokens, or builds a custom front on the headless API; get a themed site on its own subdomain, bring content and get one course per source, see per-course learner analytics), with a short numbered list under the stage. Every name, colour and bar in the stage is an example. Mark steps and sources that are not shipped with status ‘coming’.
Live example
Section titled “Live example”Rendered from the example props below with the real component. Theme: coffee · oncall · nightsky · gravity · poland · ulam · platform · open on its own
Example
Section titled “Example”{ "component": "WhiteLabelStory", "props": { "id": "white-label", "eyebrow": "white label", "title": "Your brand, your academy, one course per source", "intro": "Bring your style and your content. ulams gives you a branded academy on its own subdomain, a separate cited course for every source, and the learner analytics for each of them.", "valueLine": "Your look, your subdomain, your content, and clear numbers per course.", "description": "An animated example in four steps. One: an agent such as Claude Code, with the ulams CLI and the Figma or Stitch MCP attached, reads a design (a Figma file, a Stitch DESIGN.md, a brand guide PDF or a logo and colours), extracts colours, fonts, logo and corner radius, and runs ulams theme set and ulams settings set; a custom front built on the headless API is shown as the alternative. Two: a themed academy appears on its own subdomain, acme.ulams.app, with a landing page, a course catalogue and an admin, all in the extracted brand. Three: documents, PDFs, a Git repository and a web page each become their own cited course, built by the course builder and kept in sync by Living Course. Four: a per-course dashboard shows learner progress, quiz performance, learners at risk and the sections that confuse people. All names and values are an example.", "exampleNote": "Example brand and data", "primaryCta": { "label": "Try a live demo", "href": "#demos" }, "secondaryCta": { "label": "Self-host it", "href": "#self-host" }, "steps": [ { "title": "Bring your brand", "text": "Attach the ulams CLI or MCP and your design tool's MCP to your agent. It reads your design and applies it to the theme, or builds your own front on the headless API.", "points": [ "Figma, Stitch (DESIGN.md), a brand guide PDF, or a logo and colours", "Colours, fonts, logo and radius become theme settings", "Or your own front on the API and @ulams/sdk" ], "today": "Works today through your agent. A built-in brand importer (no agent needed) is on the roadmap." }, { "title": "Get your academy", "text": "A themed site appears on its own subdomain, in your brand, with a landing page, a course catalogue and an admin.", "points": [ "One subdomain per customer, for example acme.ulams.app", "Landing, catalogue and admin share the brand" ] }, { "title": "Bring your content", "text": "Add documents, PDFs, a Git repo or web pages. Each source becomes its own course, built with citations.", "points": [ "One course per source", "Every generated element cites its source", "Kept in sync by Living Course" ], "today": "Upload, Git and web page sources work today. Keeping courses in sync automatically is on the roadmap." }, { "title": "See everything", "text": "Every course has its own learner analytics for the author and the admin.", "points": [ "Progress and completion", "Quiz performance", "At-risk learners", "Sections that confuse people" ], "status": "coming", "today": "On the roadmap: per-course analytics and at-risk learners are planned, not built yet." } ], "brand": { "agentLabel": "Claude Code · ulams CLI · Figma MCP", "sourcesLabel": "Your design", "sources": [ { "kind": "figma", "label": "Figma file", "file": "acme-brand.fig" }, { "kind": "stitch", "label": "Stitch design", "file": "DESIGN.md" }, { "kind": "pdf", "label": "Brand guide", "file": "acme-guide.pdf" }, { "kind": "logo", "label": "Logo and colours", "file": "logo.svg" } ], "alternative": { "label": "Or your own front", "text": "A custom template on the headless API and @ulams/sdk" }, "tokensLabel": "Tokens the agent extracts", "colors": [ { "name": "Primary", "value": "#0E7C66" }, { "name": "Secondary", "value": "#1B2A41" }, { "name": "Accent", "value": "#F5B841" }, { "name": "Surface", "value": "#F6F4EF" }, { "name": "Text", "value": "#16202B" } ], "fonts": [ { "role": "Headings", "name": "Fraunces" }, { "role": "Body", "name": "Inter" } ], "logo": "acme", "radius": 12, "commands": [ "ulams theme set --accent '#0E7C66' --json", "ulams settings set global companyName \"Acme Academy\" --json" ] }, "site": { "host": "acme.ulams.app", "pages": [ "Landing", "Catalogue", "Admin" ], "headline": "Learn the Acme way", "action": "Browse courses" }, "content": { "builderLabel": "Course builder", "citedLabel": "cited", "syncLabel": "Living Course keeps each one in sync", "syncStatus": "coming", "sources": [ { "kind": "doc", "label": "handbook.docx", "course": "Onboarding" }, { "kind": "pdf", "label": "safety.pdf", "course": "Safety basics" }, { "kind": "git", "label": "github.com/acme/docs", "course": "Product docs" }, { "kind": "url", "label": "acme.com/help", "course": "Help centre" } ] }, "dashboard": { "kpis": [ { "label": "Progress", "value": 64 }, { "label": "Completion", "value": 41 }, { "label": "Quiz average", "value": 72 } ], "quiz": { "label": "Quiz performance", "bars": [ { "label": "Module 1", "value": 85 }, { "label": "Module 2", "value": 70 }, { "label": "Module 3", "value": 48 } ] }, "atRisk": { "label": "At-risk learners", "learners": [ { "name": "Learner A", "reason": "Stalled in module 2" }, { "name": "Learner B", "reason": "Failed quiz twice" } ] }, "confusing": { "label": "Confusing sections", "sections": [ { "title": "Lesson 2.3", "level": 5 }, { "title": "Lesson 3.1", "level": 3 } ] } } }}| Prop | Type | Required | Notes |
|---|---|---|---|
id |
string | Anchor id for in-page links. max length 40, default "white-label" |
|
eyebrow |
string | Small label above the title. max length 80 | |
title |
string | Section title. max length 160 | |
intro |
string | One or two sentences under the title. max length 600 | |
valueLine |
string | One line of value copy under the list. max length 200 | |
description |
string | yes | Text alternative of the whole animation for screen readers. max length 1400 |
exampleNote |
string | Small label on the dashboard, e.g. ‘Example data’. max length 40 | |
primaryCta |
object | A link or call to action | |
primaryCta.label |
string | yes | Visible text. max length 80 |
primaryCta.href |
string (href) | yes | Target URL. max length 2048 |
secondaryCta |
object | A link or call to action | |
secondaryCta.label |
string | yes | Visible text. max length 80 |
secondaryCta.href |
string (href) | yes | Target URL. max length 2048 |
steps |
array of objects | yes | The four steps, in order. min 4 items, max 4 items |
steps[].title |
string | yes | Step title. max length 40 |
steps[].text |
string | yes | One or two sentences. max length 240 |
steps[].points |
array of string | Up to four short points. max 4 items | |
steps[].status |
"available" | "coming" |
Shipped today or on the roadmap; shown as Coming only in actual mode. default "available" |
|
steps[].today |
string | What exists today; shown only in actual mode. max length 200 | |
brand |
object | yes | |
brand.sources |
array of objects | yes | Sources dropped in (1 to 4). min 1 items, max 4 items |
brand.sources[].kind |
"figma" | "stitch" | "pdf" | "logo" |
yes | Kind of brand source |
brand.sources[].label |
string | yes | What it is, e.g. ‘Figma file’. max length 40 |
brand.sources[].file |
string | yes | Example file name. max length 40 |
brand.sources[].status |
"available" | "coming" |
Shipped today or on the roadmap. default "available" |
|
brand.agentLabel |
string | yes | Window title of the agent session, e.g. ‘Claude Code · ulams CLI · Figma MCP’. max length 60 |
brand.sourcesLabel |
string | yes | Caption over the sources. max length 40 |
brand.alternative |
object | yes | |
brand.alternative.label |
string | yes | The alternative, e.g. ‘Your own front’. max length 40 |
brand.alternative.text |
string | yes | One line. max length 100 |
brand.commands |
array of string | yes | One to three commands. min 1 items, max 3 items |
brand.tokensLabel |
string | yes | Caption over the extracted tokens. max length 40 |
brand.colors |
array of objects | yes | Five colours in the order primary, secondary, accent, surface, text. min 5 items, max 5 items |
brand.colors[].name |
string | yes | Role, e.g. Primary. max length 24 |
brand.colors[].value |
string | yes | Hex colour, #RRGGBB. min length 7, max length 7 |
brand.fonts |
array of objects | yes | Two fonts: headings, body. min 2 items, max 2 items |
brand.fonts[].role |
string | yes | Role, e.g. Headings. max length 24 |
brand.fonts[].name |
string | yes | Font name. max length 40 |
brand.logo |
string | yes | Placeholder wordmark of the example brand. max length 16 |
brand.radius |
integer | yes | Corner radius in px. ≥ 0, ≤ 32 |
site |
object | yes | |
site.host |
string | yes | Example subdomain, e.g. acme.ulams.app. max length 60 |
site.pages |
array of string | yes | Landing, catalogue, admin. min 3 items, max 3 items |
site.headline |
string | yes | Headline on the example landing. max length 60 |
site.action |
string | yes | Button on the example landing. max length 24 |
content |
object | yes | |
content.sources |
array of objects | yes | Sources, each becomes its own course (1 to 4). min 1 items, max 4 items |
content.sources[].kind |
"doc" | "pdf" | "git" | "url" |
yes | Kind of content source |
content.sources[].label |
string | yes | Source, e.g. ‘handbook.pdf’. max length 40 |
content.sources[].course |
string | yes | The course built from it. max length 40 |
content.sources[].status |
"available" | "coming" |
Shipped today or on the roadmap. default "available" |
|
content.builderLabel |
string | yes | Caption over the courses. max length 40 |
content.citedLabel |
string | yes | Chip on every course, e.g. ‘cited’. max length 24 |
content.syncLabel |
string | yes | Line about keeping courses in sync. max length 80 |
content.syncStatus |
"available" | "coming" |
Shipped today or on the roadmap. default "available" |
|
dashboard |
object | yes | |
dashboard.kpis |
array of objects | yes | Up to three measures. min 1 items, max 3 items |
dashboard.kpis[].label |
string | yes | Measure, e.g. Progress. max length 30 |
dashboard.kpis[].value |
integer | yes | Bar fill, 0 to 100 (illustrative). ≥ 0, ≤ 100 |
dashboard.quiz |
object | yes | |
dashboard.quiz.label |
string | yes | Panel title. max length 40 |
dashboard.quiz.bars |
array of objects | yes | Up to four bars. min 1 items, max 4 items |
dashboard.quiz.bars[].label |
string | yes | Quiz or module. max length 30 |
dashboard.quiz.bars[].value |
integer | yes | Bar fill, 0 to 100. ≥ 0, ≤ 100 |
dashboard.atRisk |
object | yes | |
dashboard.atRisk.label |
string | yes | Panel title. max length 40 |
dashboard.atRisk.learners |
array of objects | yes | Up to three learners. min 1 items, max 3 items |
dashboard.atRisk.learners[].name |
string | yes | Anonymous label, e.g. ‘Learner A’. max length 24 |
dashboard.atRisk.learners[].reason |
string | yes | Why, in a few words. max length 60 |
dashboard.confusing |
object | yes | |
dashboard.confusing.label |
string | yes | Panel title. max length 40 |
dashboard.confusing.sections |
array of objects | yes | Up to three sections. min 1 items, max 3 items |
dashboard.confusing.sections[].title |
string | yes | Section. max length 40 |
dashboard.confusing.sections[].level |
integer | yes | How confusing, 1 to 5. ≥ 1, ≤ 5 |
Text fallback
Section titled “Text fallback”What a text-only client, an unknown renderer or a plain-text channel shows for the example above.
Your brand, your academy, one course per sourceBring your style and your content. ulams gives you a branded academy on its own subdomain, a separate cited course for every source, and the learner analytics for each of them.An animated example in four steps. One: an agent such as Claude Code, with the ulams CLI and the Figma or Stitch MCP attached, reads a design (a Figma file, a Stitch DESIGN.md, a brand guide PDF or a logo and colours), extracts colours, fonts, logo and corner radius, and runs ulams theme set and ulams settings set; a custom front built on the headless API is shown as the alternative. Two: a themed academy appears on its own subdomain, acme.ulams.app, with a landing page, a course catalogue and an admin, all in the extracted brand. Three: documents, PDFs, a Git repository and a web page each become their own cited course, built by the course builder and kept in sync by Living Course. Four: a per-course dashboard shows learner progress, quiz performance, learners at risk and the sections that confuse people. All names and values are an example.Invalid props
Section titled “Invalid props”A node whose props fail the schema never breaks the page: the renderer shows the plain-text fallback instead (and logs the issues in development).
{ "steps": [ { "title": "Only one step" } ]}Issues:
/descriptionis required/brandis required/siteis required/contentis required/dashboardis required
Rendered as:
Nothing: this component has no text of its own.
Accessibility
Section titled “Accessibility”axe-core: 16 rules passed, 0 violations, 0 need manual review. Run at build time on the server-rendered HTML in jsdom. Colour contrast and layout rules need a browser and are covered by the Playwright axe scans of the reference frontend.