Advanced example · early experiment

From a request to a widget

One goal, three ways to build an interface.

An early attempt at dynamic widgets that needs work. Try these saved Luna outputs; this example does not generate live.

Help me choose between two storage plans. Local storage works offline and includes 10 GB at no monthly cost. Cloud storage syncs across devices and includes 100 GB for $8 per month. Make the differences easy to understand and compare.

3.63 s to source · 177 output tokens

Luna chooses from a small component catalog. A deterministic compiler supplies the markup.

Choose a storage plan

The main trade-off is offline access at no monthly cost versus more space that syncs across devices.

Feature Local storage Cloud storage
Storage 10 GB 100 GB
Monthly cost $0 $8 per month
Works offline Yes Not specified
Syncs across devices Not specified Yes

Quick guide

Choose local storage if offline access and avoiding a monthly fee matter most. Choose cloud storage if you need 10× the space and want files synced across devices.

Generated source and prompt

First generated source

{
  "components": [
    {
      "type": "text",
      "style": "heading",
      "text": "Choose a storage plan"
    },
    {
      "type": "text",
      "style": "paragraph",
      "text": "The main trade-off is offline access at no monthly cost versus more space that syncs across devices."
    },
    {
      "type": "table",
      "headers": [
        "Feature",
        "Local storage",
        "Cloud storage"
      ],
      "rows": [
        [
          "Storage",
          "10 GB",
          "100 GB"
        ],
        [
          "Monthly cost",
          "$0",
          "$8 per month"
        ],
        [
          "Works offline",
          "Yes",
          "Not specified"
        ],
        [
          "Syncs across devices",
          "Not specified",
          "Yes"
        ]
      ]
    },
    {
      "type": "text",
      "style": "subheading",
      "text": "Quick guide"
    },
    {
      "type": "text",
      "style": "paragraph",
      "text": "Choose local storage if offline access and avoiding a monthly fee matter most. Choose cloud storage if you need 10× the space and want files synced across devices."
    }
  ]
}

Prompt sent with the output schema

Return {components:[...]}, choosing a composition from the available component formats to serve the user's goal:
text {type:"text",style:"heading"|"subheading"|"paragraph",text}
options {type:"options",id,items:[{id,text}]} (mutually exclusive choices)
board {type:"board",id,columns:[{id,label,cards:[{id,title,text}]}]}
chart {type:"chart",id,label,xLabel,yLabel,rows:[{category,value}]} (this format renders a bar chart with numeric labels)
tabs {type:"tabs",id,tabs:[{id,label,components:[...]}]}
draft {type:"draft",id,text} (editable Markdown)
table {type:"table",headers:[string],rows:[[string]]}
All shown keys are required by the format. Text is literal, not markup. Assign unique IDs yourself and preserve the user's facts. Choose the components, organization and wording; the compiler supplies their installed behavior and presentation.

USER REQUEST:
Help me choose between two storage plans. Local storage works offline and includes 10 GB at no monthly cost. Cloud storage syncs across devices and includes 100 GB for $8 per month. Make the differences easy to understand and compare.

5.88 s to source · 325 output tokens

Luna writes the markup; Leaf supplies the styling and behavior.

Choose a storage plan

Both plans store your files. The main trade-off is paying for more space and automatic access across devices.

Feature Local storage Cloud storage
Storage 10 GB 100 GB
Monthly cost $0 $8
Works offline Yes Not specified
Syncs across devices Not specified Yes

Quick guide

  • Choose local storage if offline access and no monthly cost matter most, and 10 GB is enough.
  • Choose cloud storage if you want 100 GB and syncing across devices for $8 per month.
Generated source and prompt

First generated source

<section>
  <h2>Choose a storage plan</h2>
  <p>Both plans store your files. The main trade-off is paying for more space and automatic access across devices.</p>
  <table>
    <thead>
      <tr><th scope="col">Feature</th><th scope="col">Local storage</th><th scope="col">Cloud storage</th></tr>
    </thead>
    <tbody>
      <tr><th scope="row">Storage</th><td>10 GB</td><td>100 GB</td></tr>
      <tr><th scope="row">Monthly cost</th><td>$0</td><td>$8</td></tr>
      <tr><th scope="row">Works offline</th><td>Yes</td><td>Not specified</td></tr>
      <tr><th scope="row">Syncs across devices</th><td>Not specified</td><td>Yes</td></tr>
    </tbody>
  </table>
  <h3>Quick guide</h3>
  <ul>
    <li>Choose local storage if offline access and no monthly cost matter most, and 10 GB is enough.</li>
    <li>Choose cloud storage if you want 100 GB and syncing across devices for $8 per month.</li>
  </ul>
</section>

Prompt sent with the output schema

Return {"markup":string} containing a Leaf markup fragment for the supplied main element. No document wrapper, CSS, JavaScript, or new widgets.
Installed Leaf component API (choose the composition that serves the user's goal):
lf-options id choose contains lf-option id with each alternative's content. The choose attribute enables selection; chosen marks an authored selection.
lf-board id contains lf-column id label, containing lf-card id. Cards may contain a strong title and ordinary descriptive markup.
lf-tabs id contains lf-tab id label, containing ordinary markup. The first tab is initially shown.
lf-draft id contains pre with a leading newline and HTML-escaped Markdown. Leaf supplies editing and recorded state.
lf-chart id contains pre with an HTML-escaped Plot options object expression. Plot and width are in scope; the object requires ariaLabel. Leaf calls Plot.plot itself and supplies chart dimensions. Include the data in the expression and use Leaf theme colors such as var(--series-1).
Ordinary headings, paragraphs, sections and tables supply surrounding content. Assign unique IDs yourself. This path composes installed behavior; it does not introduce CSS, JavaScript modules or new widgets.

USER REQUEST:
Help me choose between two storage plans. Local storage works offline and includes 10 GB at no monthly cost. Cloud storage syncs across devices and includes 100 GB for $8 per month. Make the differences easy to understand and compare.

These examples illustrate API syntax, not a required design or component selection.
Literal Leaf API examples (replace IDs, text and data for the task):
```html
<lf-options id="delivery" choose>
  <lf-option id="standard">Standard delivery</lf-option>
  <lf-option id="express">Express delivery</lf-option>
</lf-options>
<lf-chart id="volumes"><pre>
({ariaLabel:"Orders by month",x:{label:"Month"},y:{label:"Orders",grid:true},marks:[Plot.barY([{category:"Jan",value:4},{category:"Feb",value:6}],{x:"category",y:"value",fill:"var(--series-1)"}),Plot.text([{category:"Jan",value:4},{category:"Feb",value:6}],{x:"category",y:"value",text:"value",dy:-10})]})
</pre></lf-chart>
```
The boolean `choose` attribute enables Leaf's selection controls. The chart's pre contains a Plot options object expression; Leaf calls Plot.plot itself. ariaLabel belongs inside that object.

17.00 s to source · 2,278 output tokens

Luna writes the HTML, CSS and JavaScript. This preview has its own temporary state.

Generated source and prompt

First generated source

/* HTML */
<section class="storage-compare" aria-labelledby="compare-title">
  <header class="compare-header">
    <p class="eyebrow">Storage, made simple</p>
    <h1 id="compare-title">Choose the plan that fits how you store</h1>
    <p class="intro">Compare what you get, then pick the option that suits your files and devices.</p>
  </header>

  <div class="plans" role="group" aria-label="Storage plans">
    <article class="plan-card" data-plan="local">
      <div class="plan-topline"><span class="plan-icon" aria-hidden="true">▣</span><span class="plan-label">On this device</span></div>
      <h2>Local storage</h2>
      <p class="plan-description">Keep your files right here, available even when you’re offline.</p>
      <p class="price"><strong>$0</strong><span> / month</span></p>
      <ul class="features">
        <li><span class="feature-check" aria-hidden="true">✓</span><strong>10 GB</strong> of storage</li>
        <li><span class="feature-check" aria-hidden="true">✓</span>Works offline</li>
        <li><span class="feature-dash" aria-hidden="true">—</span>Stays on one device</li>
      </ul>
      <button class="select-plan" type="button" data-choice="local" aria-pressed="false">Choose Local</button>
    </article>

    <article class="plan-card cloud-card" data-plan="cloud">
      <div class="plan-topline"><span class="plan-icon cloud-icon" aria-hidden="true">☁</span><span class="plan-label">Across your devices</span></div>
      <h2>Cloud storage</h2>
      <p class="plan-description">Sync your files so they’re available across your devices.</p>
      <p class="price"><strong>$8</strong><span> / month</span></p>
      <ul class="features">
        <li><span class="feature-check" aria-hidden="true">✓</span><strong>100 GB</strong> of storage</li>
        <li><span class="feature-check" aria-hidden="true">✓</span>Syncs across devices</li>
        <li><span class="feature-dash" aria-hidden="true">—</span>Requires a connection to sync</li>
      </ul>
      <button class="select-plan" type="button" data-choice="cloud" aria-pressed="false">Choose Cloud</button>
    </article>
  </div>

  <aside class="decision-note" aria-live="polite">
    <span class="note-mark" aria-hidden="true">i</span>
    <p><strong>Quick guide:</strong> Local is a no-cost fit for offline access on one device. Cloud gives you 10× the space and sync across devices for $8/month.</p>
  </aside>
  <p class="selection-status" id="selection-status" aria-live="polite"></p>
</section>

/* CSS */
* { box-sizing: border-box; }
.storage-compare { --ink:#172a3a; --muted:#687886; --line:#dce5e8; --teal:#087f78; --wash:#f4f8f7; max-width: 980px; margin: 0 auto; padding: clamp(1.25rem, 5vw, 3.5rem); color:var(--ink); font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
.compare-header { max-width:650px; margin:0 auto 2rem; text-align:center; }
.eyebrow { margin:0 0 .55rem; color:var(--teal); font-size:.75rem; font-weight:800; letter-spacing:.13em; text-transform:uppercase; }
.compare-header h1 { margin:0; font-size:clamp(1.9rem, 5vw, 3rem); letter-spacing:-.045em; line-height:1.08; }
.intro { margin:.9rem 0 0; color:var(--muted); font-size:1.05rem; line-height:1.55; }
.plans { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:1.1rem; }
.plan-card { display:flex; flex-direction:column; padding:clamp(1.25rem,3vw,2rem); border:1px solid var(--line); border-radius:20px; background:#fff; box-shadow:0 10px 30px rgba(27,57,69,.045); transition:border-color .2s, box-shadow .2s, transform .2s; }
.plan-card.is-selected { border-color:var(--teal); box-shadow:0 0 0 3px rgba(8,127,120,.14), 0 14px 34px rgba(27,57,69,.08); transform:translateY(-2px); }
.cloud-card { background:linear-gradient(145deg,#f7fcfb,#fff 58%); }
.plan-topline { display:flex; align-items:center; gap:.65rem; margin-bottom:1.1rem; }
.plan-icon { display:grid; width:2.5rem; height:2.5rem; place-items:center; border-radius:12px; background:#edf3f5; color:#466070; font-size:1.3rem; }
.cloud-icon { background:#e0f3f0; color:var(--teal); }
.plan-label { color:var(--muted); font-size:.8rem; font-weight:700; }
.plan-card h2 { margin:0; font-size:1.45rem; letter-spacing:-.025em; }
.plan-description { min-height:3.1em; margin:.55rem 0 1.1rem; color:var(--muted); line-height:1.55; }
.price { margin:0; padding:1rem 0; border-top:1px solid var(--line); border-bottom:1px solid var(--line); }
.price strong { font-size:2.3rem; letter-spacing:-.06em; }
.price span { color:var(--muted); font-size:.95rem; }
.features { display:grid; gap:.85rem; margin:1.25rem 0 1.5rem; padding:0; list-style:none; color:#405361; }
.features li { display:flex; align-items:center; gap:.55rem; line-height:1.4; }
.features strong { color:var(--ink); }
.feature-check,.feature-dash { display:inline-grid; flex:0 0 1.2rem; place-items:center; font-weight:800; }
.feature-check { color:var(--teal); }
.feature-dash { color:#9aa9b1; }
.select-plan { width:100%; margin-top:auto; padding:.82rem 1rem; border:1px solid #b8c9cf; border-radius:10px; background:#fff; color:var(--ink); font:inherit; font-size:.95rem; font-weight:750; cursor:pointer; transition:background .15s,color .15s,border-color .15s; }
.select-plan:hover { border-color:var(--teal); background:var(--wash); }
.select-plan:focus-visible { outline:3px solid #76c8c1; outline-offset:3px; }
.is-selected .select-plan { border-color:var(--teal); background:var(--teal); color:#fff; }
.decision-note { display:flex; align-items:flex-start; gap:.75rem; margin-top:1.2rem; padding:1rem 1.1rem; border:1px solid #d8ebe8; border-radius:14px; background:#f5fbfa; color:#405361; }
.note-mark { display:grid; flex:0 0 1.35rem; width:1.35rem; height:1.35rem; place-items:center; border-radius:50%; background:#d8efec; color:var(--teal); font-size:.82rem; font-weight:800; }
.decision-note p { margin:0; font-size:.9rem; line-height:1.55; }
.decision-note strong { color:var(--ink); }
.selection-status { min-height:1.25rem; margin:.65rem 0 0; color:var(--teal); font-size:.9rem; font-weight:700; text-align:center; }
@media (max-width:620px) { .storage-compare { padding:1.4rem 1rem; } .plans { grid-template-columns:1fr; gap:.85rem; } .plan-description { min-height:0; } .plan-card { border-radius:16px; } }
@media (prefers-reduced-motion:reduce) { *,*::before,*::after { transition:none !important; scroll-behavior:auto !important; } }

/* JS */
const planButtons = document.querySelectorAll('.storage-compare .select-plan');
const planCards = document.querySelectorAll('.storage-compare .plan-card');
const status = document.querySelector('#selection-status');

planButtons.forEach((button) => {
  button.addEventListener('click', () => {
    const choice = button.dataset.choice;
    planCards.forEach((card) => {
      const selected = card.dataset.plan === choice;
      card.classList.toggle('is-selected', selected);
      card.querySelector('.select-plan').setAttribute('aria-pressed', String(selected));
    });
    status.textContent = choice === 'local'
      ? 'Local storage selected: 10 GB, offline access, and no monthly cost.'
      : 'Cloud storage selected: 100 GB, device syncing, and $8 per month.';
  });
});

Prompt sent with the output schema

Return {"html":string,"css":string,"js":string}. HTML is a fragment inside host main; CSS and JavaScript are separate files. No document/main wrapper, script/style tags or inline handlers; attach listeners in js.
Return separate html, css, js string fields. html is a body fragment; put styling in css and behavior in js. No inline scripts, style elements or event-handler attributes: the host CSP refuses them. Use ordinary HTML/CSS/JavaScript without Leaf tags, imports or network dependencies. Design the presentation and interactions around the user's goal, preserving their facts. Make the result accessible and usable at narrow widths.

USER REQUEST:
Help me choose between two storage plans. Local storage works offline and includes 10 GB at no monthly cost. Cloud storage syncs across devices and includes 100 GB for $8 per month. Make the differences easy to understand and compare.
Help me decide how to roll out a software update. We could release to 5% of users today, release to everyone today, or postpone for more review. A small release limits initial exposure. I want to weigh the tradeoffs and record a decision I can revisit.

6.88 s to source · 333 output tokens

Luna chooses from a small component catalog. A deterministic compiler supplies the markup.

Software update rollout decision

Compare the three options, then record your choice and the conditions that would make you revisit it.

Option Potential upside Tradeoff / risk
Release to 5% today Limits initial exposure while getting real-world feedback. Some users receive the update today; issues may still affect that initial group.
Release to everyone today Makes the update available to all users right away. Exposes the full user base if a problem is found.
Postpone for more review Creates time for additional checks before release. Delays availability and may not surface every issue.
Release to 5% of users todayRelease to everyone todayPostpone for more review

Decision to revisit

Decision

[Record the selected option and date]

Why

[What tradeoffs or evidence mattered most?]

Check before proceeding

[What must be true before rollout, if anything?]

Revisit if

[What signal, issue, or new information would change this decision?]

Review date

[When will we check the decision again?]

## Decision
[Record the selected option and date]

## Why
[What tradeoffs or evidence mattered most?]

## Check before proceeding
[What must be true before rollout, if anything?]

## Revisit if
[What signal, issue, or new information would change this decision?]

## Review date
[When will we check the decision again?]
Generated source and prompt

First generated source

{
  "components": [
    {
      "type": "text",
      "style": "heading",
      "text": "Software update rollout decision"
    },
    {
      "type": "text",
      "style": "paragraph",
      "text": "Compare the three options, then record your choice and the conditions that would make you revisit it."
    },
    {
      "type": "table",
      "headers": [
        "Option",
        "Potential upside",
        "Tradeoff / risk"
      ],
      "rows": [
        [
          "Release to 5% today",
          "Limits initial exposure while getting real-world feedback.",
          "Some users receive the update today; issues may still affect that initial group."
        ],
        [
          "Release to everyone today",
          "Makes the update available to all users right away.",
          "Exposes the full user base if a problem is found."
        ],
        [
          "Postpone for more review",
          "Creates time for additional checks before release.",
          "Delays availability and may not surface every issue."
        ]
      ]
    },
    {
      "type": "options",
      "id": "rollout-choice",
      "items": [
        {
          "id": "five-percent",
          "text": "Release to 5% of users today"
        },
        {
          "id": "everyone",
          "text": "Release to everyone today"
        },
        {
          "id": "postpone",
          "text": "Postpone for more review"
        }
      ]
    },
    {
      "type": "text",
      "style": "subheading",
      "text": "Decision to revisit"
    },
    {
      "type": "draft",
      "id": "decision-record",
      "text": "## Decision\n[Record the selected option and date]\n\n## Why\n[What tradeoffs or evidence mattered most?]\n\n## Check before proceeding\n[What must be true before rollout, if anything?]\n\n## Revisit if\n[What signal, issue, or new information would change this decision?]\n\n## Review date\n[When will we check the decision again?]"
    }
  ]
}

Prompt sent with the output schema

Return {components:[...]}, choosing a composition from the available component formats to serve the user's goal:
text {type:"text",style:"heading"|"subheading"|"paragraph",text}
options {type:"options",id,items:[{id,text}]} (mutually exclusive choices)
board {type:"board",id,columns:[{id,label,cards:[{id,title,text}]}]}
chart {type:"chart",id,label,xLabel,yLabel,rows:[{category,value}]} (this format renders a bar chart with numeric labels)
tabs {type:"tabs",id,tabs:[{id,label,components:[...]}]}
draft {type:"draft",id,text} (editable Markdown)
table {type:"table",headers:[string],rows:[[string]]}
All shown keys are required by the format. Text is literal, not markup. Assign unique IDs yourself and preserve the user's facts. Choose the components, organization and wording; the compiler supplies their installed behavior and presentation.

USER REQUEST:
Help me decide how to roll out a software update. We could release to 5% of users today, release to everyone today, or postpone for more review. A small release limits initial exposure. I want to weigh the tradeoffs and record a decision I can revisit.

4.39 s to source · 362 output tokens

Luna writes the markup; Leaf supplies the styling and behavior.

Choose a rollout plan

A 5% release limits initial exposure while we monitor the update. Weigh that added caution against the speed of a full release or the assurance of another review.

Release to 5% today

Limit initial exposure and monitor for problems before expanding. Slower reach; requires watching results and deciding when to scale up.

Release to everyone today

Make the update available to all users immediately. Fastest rollout, but any issue could affect the full user base.

Postpone for more review

Gain time to investigate or test further. Delays the update and does not guarantee that review will uncover every issue.

Decision to revisit

Record the option selected above and why. Revisit after reviewing early rollout signals or completing additional review.

Rollout decision

Selected plan:

Why this plan:

What would change my mind:

Signals or review to revisit:

Revisit date:

## Rollout decision

**Selected plan:**

**Why this plan:**

**What would change my mind:**

**Signals or review to revisit:**

**Revisit date:**
Generated source and prompt

First generated source

<section>
  <h2>Choose a rollout plan</h2>
  <p>A 5% release limits initial exposure while we monitor the update. Weigh that added caution against the speed of a full release or the assurance of another review.</p>
  <lf-options id="rollout-plan" choose>
    <lf-option id="rollout-five-percent"><strong>Release to 5% today</strong><p>Limit initial exposure and monitor for problems before expanding. Slower reach; requires watching results and deciding when to scale up.</p></lf-option>
    <lf-option id="rollout-everyone"><strong>Release to everyone today</strong><p>Make the update available to all users immediately. Fastest rollout, but any issue could affect the full user base.</p></lf-option>
    <lf-option id="rollout-postpone"><strong>Postpone for more review</strong><p>Gain time to investigate or test further. Delays the update and does not guarantee that review will uncover every issue.</p></lf-option>
  </lf-options>
  <h3>Decision to revisit</h3>
  <p>Record the option selected above and why. Revisit after reviewing early rollout signals or completing additional review.</p>
  <lf-draft id="rollout-decision"><pre>
## Rollout decision

**Selected plan:**

**Why this plan:**

**What would change my mind:**

**Signals or review to revisit:**

**Revisit date:**
</pre></lf-draft>
</section>

Prompt sent with the output schema

Return {"markup":string} containing a Leaf markup fragment for the supplied main element. No document wrapper, CSS, JavaScript, or new widgets.
Installed Leaf component API (choose the composition that serves the user's goal):
lf-options id choose contains lf-option id with each alternative's content. The choose attribute enables selection; chosen marks an authored selection.
lf-board id contains lf-column id label, containing lf-card id. Cards may contain a strong title and ordinary descriptive markup.
lf-tabs id contains lf-tab id label, containing ordinary markup. The first tab is initially shown.
lf-draft id contains pre with a leading newline and HTML-escaped Markdown. Leaf supplies editing and recorded state.
lf-chart id contains pre with an HTML-escaped Plot options object expression. Plot and width are in scope; the object requires ariaLabel. Leaf calls Plot.plot itself and supplies chart dimensions. Include the data in the expression and use Leaf theme colors such as var(--series-1).
Ordinary headings, paragraphs, sections and tables supply surrounding content. Assign unique IDs yourself. This path composes installed behavior; it does not introduce CSS, JavaScript modules or new widgets.

USER REQUEST:
Help me decide how to roll out a software update. We could release to 5% of users today, release to everyone today, or postpone for more review. A small release limits initial exposure. I want to weigh the tradeoffs and record a decision I can revisit.

These examples illustrate API syntax, not a required design or component selection.
Literal Leaf API examples (replace IDs, text and data for the task):
```html
<lf-options id="delivery" choose>
  <lf-option id="standard">Standard delivery</lf-option>
  <lf-option id="express">Express delivery</lf-option>
</lf-options>
<lf-chart id="volumes"><pre>
({ariaLabel:"Orders by month",x:{label:"Month"},y:{label:"Orders",grid:true},marks:[Plot.barY([{category:"Jan",value:4},{category:"Feb",value:6}],{x:"category",y:"value",fill:"var(--series-1)"}),Plot.text([{category:"Jan",value:4},{category:"Feb",value:6}],{x:"category",y:"value",text:"value",dy:-10})]})
</pre></lf-chart>
```
The boolean `choose` attribute enables Leaf's selection controls. The chart's pre contains a Plot options object expression; Leaf calls Plot.plot itself. ariaLabel belongs inside that object.

41.20 s to source · 4,449 output tokens

Luna writes the HTML, CSS and JavaScript. This preview has its own temporary state.

Generated source and prompt

First generated source

/* HTML */
<section class="rollout" aria-labelledby="page-title">
  <header class="topbar">
    <div class="brand"><span class="brand-mark" aria-hidden="true">↗</span><span>Release planning</span></div>
    <span class="status-pill"><span class="status-dot" aria-hidden="true"></span>Decision workspace</span>
  </header>

  <div class="intro">
    <p class="eyebrow">ROLLOUT DECISION · 01</p>
    <h1 id="page-title">How should we ship this update?</h1>
    <p class="lede">Choose a rollout path, make the tradeoffs explicit, and save a decision you can revisit.</p>
  </div>

  <div class="workspace">
    <section class="choices-panel" aria-labelledby="options-heading">
      <div class="section-heading">
        <div><p class="eyebrow">YOUR OPTIONS</p><h2 id="options-heading">Pick a rollout path</h2></div>
        <span class="step-label">1 of 2</span>
      </div>
      <fieldset class="choice-list">
        <legend class="sr-only">Select a rollout option</legend>
        <label class="choice-card">
          <input type="radio" name="rollout" value="5% today">
          <span class="radio-ui" aria-hidden="true"></span>
          <span class="choice-copy"><span class="choice-title">Start with 5% today</span><span class="choice-desc">Limit initial exposure while you observe the release before expanding.</span></span>
          <span class="choice-tag tag-cautious">Staged</span>
        </label>
        <label class="choice-card">
          <input type="radio" name="rollout" value="Everyone today">
          <span class="radio-ui" aria-hidden="true"></span>
          <span class="choice-copy"><span class="choice-title">Release to everyone today</span><span class="choice-desc">Make the update available to all users at once; widest immediate exposure.</span></span>
          <span class="choice-tag tag-fast">Fastest</span>
        </label>
        <label class="choice-card">
          <input type="radio" name="rollout" value="Postpone for review">
          <span class="radio-ui" aria-hidden="true"></span>
          <span class="choice-copy"><span class="choice-title">Postpone for more review</span><span class="choice-desc">Take additional time to review before choosing a release path.</span></span>
          <span class="choice-tag tag-review">More review</span>
        </label>
      </fieldset>

      <div class="tradeoffs" aria-live="polite">
        <div class="tradeoff-heading"><span class="spark" aria-hidden="true">✳</span><div><h3>Tradeoffs to weigh</h3><p id="tradeoff-hint">Select an option to see its considerations.</p></div></div>
        <div class="tradeoff-grid" id="tradeoff-content">
          <div class="tradeoff-item"><span class="trade-icon exposure" aria-hidden="true">↘</span><div><strong>Initial exposure</strong><span>How many users encounter the update right away?</span></div></div>
          <div class="tradeoff-item"><span class="trade-icon timing" aria-hidden="true">◷</span><div><strong>Timing</strong><span>How quickly does the update reach users?</span></div></div>
          <div class="tradeoff-item"><span class="trade-icon confidence" aria-hidden="true">◎</span><div><strong>Review opportunity</strong><span>How much time remains to assess before release?</span></div></div>
        </div>
      </div>
    </section>

    <aside class="decision-panel" aria-labelledby="record-heading">
      <div class="section-heading">
        <div><p class="eyebrow">MAKE IT REVISITABLE</p><h2 id="record-heading">Record your decision</h2></div>
        <span class="step-label">2 of 2</span>
      </div>
      <p class="panel-note">Capture the reasoning and a point to check back. You can update this record later.</p>
      <label class="field-label" for="reasoning">Why this path?</label>
      <textarea id="reasoning" rows="4" placeholder="What matters most in this decision? What would change your mind?"></textarea>
      <label class="field-label checkpoint-label" for="checkpoint">Revisit this decision</label>
      <div class="date-wrap"><span aria-hidden="true">▦</span><input id="checkpoint" type="date" aria-label="Date to revisit this decision"></div>
      <button class="save-button" id="save-decision" type="button" disabled>Save decision <span aria-hidden="true">→</span></button>
      <p class="save-hint" id="save-hint">Choose a rollout path to continue.</p>
    </aside>
  </div>

  <section class="saved-record" id="saved-record" aria-live="polite" hidden>
    <div class="saved-icon" aria-hidden="true">✓</div>
    <div class="saved-copy"><p class="eyebrow">DECISION SAVED</p><h2 id="saved-choice"></h2><p id="saved-details"></p></div>
    <button class="edit-button" id="edit-decision" type="button">Edit decision</button>
  </section>
  <footer><span>Keep the decision visible. Revisit it as context changes.</span><span class="footer-mark">RELEASE NOTES <span aria-hidden="true">·</span> 01</span></footer>
</section>

/* CSS */
:root{font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:#182520;background:#f5f7f4;font-synthesis:none}*{box-sizing:border-box}.rollout{max-width:1080px;margin:0 auto;padding:24px 32px 28px}.topbar{display:flex;align-items:center;justify-content:space-between;padding:4px 0 30px;border-bottom:1px solid #e1e8e2}.brand{display:flex;align-items:center;gap:10px;font-weight:650;font-size:13px;letter-spacing:.01em}.brand-mark{display:grid;place-items:center;width:27px;height:27px;border-radius:8px;color:#fff;background:#21654b;font-size:17px}.status-pill{display:flex;align-items:center;gap:8px;border:1px solid #e1e8e2;background:#fff;border-radius:999px;padding:7px 11px;color:#64716a;font-size:11px}.status-dot{width:7px;height:7px;border-radius:50%;background:#74a88c}.intro{padding:38px 0 30px}.eyebrow{margin:0 0 9px;color:#708078;font-size:10px;font-weight:750;letter-spacing:.14em}.intro .eyebrow{color:#398063}.intro h1{margin:0;font-size:clamp(28px,4vw,42px);letter-spacing:-.045em;line-height:1.13;font-weight:680}.lede{margin:12px 0 0;color:#65736b;font-size:14px;line-height:1.6}.workspace{display:grid;grid-template-columns:minmax(0,1.3fr) minmax(280px,.8fr);gap:20px;align-items:start}.choices-panel,.decision-panel{background:#fff;border:1px solid #e5ebe6;border-radius:14px;padding:23px;box-shadow:0 4px 18px rgba(28,57,42,.035)}.section-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:18px}.section-heading h2{font-size:17px;letter-spacing:-.025em;margin:0}.section-heading .eyebrow{margin-bottom:6px}.step-label{font-size:10px;color:#7e8b83;background:#f3f6f3;border-radius:99px;padding:6px 9px}.choice-list{margin:0;padding:0;border:0;display:grid;gap:9px}.choice-card{display:flex;align-items:center;gap:12px;border:1px solid #e5ebe6;border-radius:10px;padding:14px 13px;cursor:pointer;transition:border-color .16s,background .16s,box-shadow .16s}.choice-card:hover{border-color:#a8c8b5}.choice-card:has(input:checked){border-color:#3b8664;background:#f5faf6;box-shadow:0 0 0 1px #3b8664}.choice-card input{position:absolute;opacity:0;width:1px;height:1px}.choice-card:focus-within{outline:3px solid #b8d8c4;outline-offset:2px}.radio-ui{width:17px;height:17px;flex:0 0 17px;border:1.5px solid #b8c3bb;border-radius:50%;position:relative}.choice-card:has(input:checked) .radio-ui{border-color:#32805c}.choice-card:has(input:checked) .radio-ui:after{content:"";position:absolute;inset:3px;border-radius:50%;background:#32805c}.choice-copy{display:grid;gap:4px;min-width:0}.choice-title{font-size:13px;font-weight:650}.choice-desc{font-size:11px;line-height:1.5;color:#748078}.choice-tag{margin-left:auto;white-space:nowrap;font-size:9px;font-weight:700;border-radius:99px;padding:6px 8px}.tag-cautious{background:#eaf4ed;color:#397457}.tag-fast{background:#edf2fa;color:#56709c}.tag-review{background:#f6f1e7;color:#8d7441}.tradeoffs{margin-top:20px;border-top:1px solid #edf0ed;padding-top:17px}.tradeoff-heading{display:flex;gap:10px;align-items:flex-start;margin-bottom:12px}.spark{display:grid;place-items:center;width:24px;height:24px;border-radius:7px;background:#eff6f1;color:#3f8663}.tradeoff-heading h3{font-size:12px;margin:0 0 3px}.tradeoff-heading p{font-size:10px;color:#7b8780;margin:0}.tradeoff-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}.tradeoff-item{display:flex;gap:8px;align-items:flex-start;padding:11px 9px;background:#f8faf8;border-radius:8px;min-height:72px}.trade-icon{font-size:15px;width:19px;text-align:center}.exposure{color:#418265}.timing{color:#7284a1}.confidence{color:#aa8951}.tradeoff-item div{display:grid;gap:4px}.tradeoff-item strong{font-size:10px}.tradeoff-item div span{font-size:9px;line-height:1.4;color:#7b8780}.decision-panel{padding:23px}.panel-note{margin:-6px 0 19px;color:#718078;font-size:11px;line-height:1.55}.field-label{display:block;margin:0 0 7px;font-size:11px;font-weight:650}.textarea,.decision-panel textarea{font:inherit}.decision-panel textarea{width:100%;resize:vertical;border:1px solid #dfe7e1;border-radius:8px;padding:11px;font-size:11px;line-height:1.5;color:#24332b;background:#fcfdfc;min-height:98px}.decision-panel textarea::placeholder{color:#a3ada6}.decision-panel textarea:focus,.date-wrap:focus-within{outline:3px solid #d3e8d9;border-color:#5a9875}.checkpoint-label{margin-top:16px}.date-wrap{display:flex;gap:9px;align-items:center;border:1px solid #dfe7e1;border-radius:8px;padding:0 10px;color:#7c8c81}.date-wrap input{width:100%;min-width:0;border:0;background:transparent;padding:10px 0;color:#33443a;font:inherit;font-size:11px;outline:0}.save-button{width:100%;margin-top:17px;display:flex;align-items:center;justify-content:center;gap:10px;border:0;border-radius:8px;background:#21654b;color:#fff;padding:12px 15px;font:inherit;font-size:12px;font-weight:650;cursor:pointer;transition:background .15s,opacity .15s}.save-button:hover:not(:disabled){background:#174e39}.save-button:disabled{opacity:.45;cursor:not-allowed}.save-hint{text-align:center;color:#86928a;font-size:10px;margin:9px 0 0}.saved-record{margin-top:18px;background:#edf6ef;border:1px solid #cce1d1;border-radius:12px;padding:17px 20px;display:flex;align-items:center;gap:14px}.saved-record[hidden]{display:none}.saved-icon{display:grid;place-items:center;width:32px;height:32px;flex:0 0 32px;border-radius:50%;background:#d8ecdd;color:#28704c;font-weight:750}.saved-copy{min-width:0;flex:1}.saved-copy .eyebrow{margin-bottom:4px;color:#438060}.saved-copy h2{font-size:14px;margin:0 0 4px}.saved-copy p:last-child{font-size:11px;color:#66776d;margin:0;line-height:1.45}.edit-button{border:1px solid #c4d9ca;border-radius:7px;padding:8px 11px;background:#fff;color:#286044;font:inherit;font-size:10px;font-weight:650;cursor:pointer}.edit-button:hover{background:#f7fbf8}footer{display:flex;justify-content:space-between;gap:16px;margin-top:30px;padding-top:15px;border-top:1px solid #e1e8e2;color:#89958d;font-size:10px}.footer-mark{letter-spacing:.1em;font-size:9px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media(max-width:760px){.rollout{padding:18px 18px 24px}.intro{padding:30px 0 24px}.workspace{grid-template-columns:1fr;gap:14px}.tradeoff-grid{grid-template-columns:1fr}.tradeoff-item{min-height:unset}.choice-card{align-items:flex-start}.choice-tag{font-size:8px;padding:5px 7px}}@media(max-width:420px){.rollout{padding:14px 13px 20px}.choices-panel,.decision-panel{padding:17px}.choice-card{gap:9px;padding:12px 10px}.choice-desc{font-size:10px}.choice-tag{display:none}.status-pill{font-size:10px}.saved-record{align-items:flex-start;flex-wrap:wrap}.edit-button{margin-left:46px}footer{flex-direction:column;gap:7px}}

/* JS */
(() => {
  const radios = Array.from(document.querySelectorAll('input[name="rollout"]'));
  const reasoning = document.getElementById('reasoning');
  const checkpoint = document.getElementById('checkpoint');
  const saveButton = document.getElementById('save-decision');
  const saveHint = document.getElementById('save-hint');
  const record = document.getElementById('saved-record');
  const savedChoice = document.getElementById('saved-choice');
  const savedDetails = document.getElementById('saved-details');
  const tradeoffHint = document.getElementById('tradeoff-hint');
  const editButton = document.getElementById('edit-decision');
  const tradeoffs = {
    '5% today': { hint: 'A smaller first release trades reach for a more limited initial exposure.', exposure: 'Begins with a smaller share of users.', timing: 'Starts today; broader availability can come later.', review: 'Creates a chance to observe before expanding.' },
    'Everyone today': { hint: 'A full release trades a faster, wider launch for broader initial exposure.', exposure: 'The update reaches all users at once.', timing: 'Fastest path to full availability.', review: 'Less opportunity to assess before broad release.' },
    'Postpone for review': { hint: 'More review trades speed for additional time before a release decision.', exposure: 'No new users encounter the update today.', timing: 'Availability is delayed.', review: 'Provides more time to assess before choosing a path.' }
  };
  function selectedValue() { const selected = radios.find(radio => radio.checked); return selected ? selected.value : ''; }
  function refresh() {
    const value = selectedValue();
    saveButton.disabled = !value;
    saveHint.textContent = value ? 'Add context if useful, then save your decision.' : 'Choose a rollout path to continue.';
    if (value) {
      const data = tradeoffs[value];
      tradeoffHint.textContent = data.hint;
      const descriptions = document.querySelectorAll('.tradeoff-item div span');
      descriptions[0].textContent = data.exposure;
      descriptions[1].textContent = data.timing;
      descriptions[2].textContent = data.review;
    } else {
      tradeoffHint.textContent = 'Select an option to see its considerations.';
      const defaults = ['How many users encounter the update right away?', 'How quickly does the update reach users?', 'How much time remains to assess before release?'];
      document.querySelectorAll('.tradeoff-item div span').forEach((item, index) => item.textContent = defaults[index]);
    }
  }
  radios.forEach(radio => radio.addEventListener('change', refresh));
  saveButton.addEventListener('click', () => {
    const value = selectedValue();
    if (!value) return;
    const reason = reasoning.value.trim();
    const date = checkpoint.value;
    savedChoice.textContent = value;
    const details = [];
    if (reason) details.push(reason);
    if (date) details.push(`Revisit on ${new Date(`${date}T12:00:00`).toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })}.`);
    if (!details.length) details.push('No additional reasoning or revisit date recorded.');
    savedDetails.textContent = details.join(' ');
    record.hidden = false;
    saveHint.textContent = 'Saved for this session. Edit any time to revisit.';
    saveButton.textContent = 'Update decision →';
  });
  editButton.addEventListener('click', () => {
    record.hidden = true;
    document.getElementById('record-heading').scrollIntoView({ behavior: 'smooth', block: 'center' });
    reasoning.focus({ preventScroll: true });
  });
  refresh();
})();

Prompt sent with the output schema

Return {"html":string,"css":string,"js":string}. HTML is a fragment inside host main; CSS and JavaScript are separate files. No document/main wrapper, script/style tags or inline handlers; attach listeners in js.
Return separate html, css, js string fields. html is a body fragment; put styling in css and behavior in js. No inline scripts, style elements or event-handler attributes: the host CSP refuses them. Use ordinary HTML/CSS/JavaScript without Leaf tags, imports or network dependencies. Design the presentation and interactions around the user's goal, preserving their facts. Make the result accessible and usable at narrow widths.

USER REQUEST:
Help me decide how to roll out a software update. We could release to 5% of users today, release to everyone today, or postpone for more review. A small release limits initial exposure. I want to weigh the tradeoffs and record a decision I can revisit.

What this experiment tells us

A component catalog can reduce the amount a model writes. Direct markup leaves more composition to the model. Generating all the code gives it control over appearance and behavior, with more code to get right.

These are individual first attempts from Luna, standard service, medium reasoning. “To source” measures elapsed time from submission to the complete response, including setup wait. Output tokens include the JSON response format. This is not time to a verified working widget or a general speed ranking.

Some native Leaf runs encountered local harness failures after generation. Their original source is shown unchanged and checked separately; those failed checks and automatic retries are excluded from the first-attempt source figures. No model-generated fix is presented as a first attempt.

Rendering checks detect empty output, overflow and script errors; they do not prove the result solves the request. Look for missing facts, invented assumptions and interactions that do not help. Leaf choices use this page’s history and Undo; generated HTML keeps its state only inside its preview.