Skip to content

WhiteLabelStory

Generated from front/ui/catalogue/examples/WhiteLabelStory.json

section · interactive (ships a small web component) · no children. All components: component playground.

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’.

Rendered from the example props below with the real component. Theme: coffee · oncall · nightsky · gravity · poland · ulam · platform · open on its own

{
"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

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 source
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.
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.

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:

  • /description is required
  • /brand is required
  • /site is required
  • /content is required
  • /dashboard is required

Rendered as:

Nothing: this component has no text of its own.

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.