diff --git a/docs/app/components/intelligent-ui/BikeDiagram.vue b/docs/app/components/intelligent-ui/BikeDiagram.vue new file mode 100644 index 00000000..1370214f --- /dev/null +++ b/docs/app/components/intelligent-ui/BikeDiagram.vue @@ -0,0 +1,290 @@ + + + + + diff --git a/docs/app/components/intelligent-ui/ImageCollage.vue b/docs/app/components/intelligent-ui/ImageCollage.vue new file mode 100644 index 00000000..8d3fa704 --- /dev/null +++ b/docs/app/components/intelligent-ui/ImageCollage.vue @@ -0,0 +1,27 @@ + + + diff --git a/docs/app/components/intelligent-ui/MediaList.vue b/docs/app/components/intelligent-ui/MediaList.vue new file mode 100644 index 00000000..5a652c90 --- /dev/null +++ b/docs/app/components/intelligent-ui/MediaList.vue @@ -0,0 +1,30 @@ + + + diff --git a/docs/app/components/intelligent-ui/QuantityCalculator.vue b/docs/app/components/intelligent-ui/QuantityCalculator.vue new file mode 100644 index 00000000..865e8ce9 --- /dev/null +++ b/docs/app/components/intelligent-ui/QuantityCalculator.vue @@ -0,0 +1,100 @@ + + + diff --git a/docs/app/components/intelligent-ui/SummaryCard.vue b/docs/app/components/intelligent-ui/SummaryCard.vue new file mode 100644 index 00000000..e9d3b520 --- /dev/null +++ b/docs/app/components/intelligent-ui/SummaryCard.vue @@ -0,0 +1,26 @@ + + + diff --git a/docs/app/components/intelligent-ui/Timeline.vue b/docs/app/components/intelligent-ui/Timeline.vue new file mode 100644 index 00000000..cb267a4c --- /dev/null +++ b/docs/app/components/intelligent-ui/Timeline.vue @@ -0,0 +1,61 @@ + + + diff --git a/docs/app/components/prose/IntelligentUiComparison.vue b/docs/app/components/prose/IntelligentUiComparison.vue new file mode 100644 index 00000000..64ef359c --- /dev/null +++ b/docs/app/components/prose/IntelligentUiComparison.vue @@ -0,0 +1,117 @@ + + + diff --git a/docs/app/components/prose/IntelligentUiHero.vue b/docs/app/components/prose/IntelligentUiHero.vue new file mode 100644 index 00000000..42f38123 --- /dev/null +++ b/docs/app/components/prose/IntelligentUiHero.vue @@ -0,0 +1,113 @@ + + + diff --git a/docs/app/constants/intelligent-ui.ts b/docs/app/constants/intelligent-ui.ts new file mode 100644 index 00000000..55dcb170 --- /dev/null +++ b/docs/app/constants/intelligent-ui.ts @@ -0,0 +1,199 @@ +// Answers rendered by the demos on /use-cases/intelligent-ui. + +const unsplash = (id: string, w = 400, h = 400) => `https://images.unsplash.com/photo-${id}?w=${w}&h=${h}&fit=crop&q=80` + +export const bikePrompt = 'Break down how a 7-speed bike is built' + +const bikeIntro = `### 7-speed bicycle + +A 7-speed bicycle is five systems working together. The frame carries the rider, the wheels roll, the drivetrain turns pedaling into motion across seven gears, the brakes slow you down, and the cockpit is where you steer and sit.` + +export const bikeStages: { label: string; markdown: string }[] = [ + { label: 'Chat', markdown: bikeIntro }, + { + label: 'Images', + markdown: `### 7-speed bicycle + +![Line drawing of a 7-speed bicycle](/intelligent-ui/bicycle.svg) + +Upright handlebars for steering, seven gears for effort, and hand brakes for speed.`, + }, + { + label: 'Intelligent UI', + markdown: `::bike-diagram{title="7-speed bicycle"} +--- +systems: + all: + title: Five systems, one machine + description: The frame carries you, the drivetrain moves you, and the rest steers and stops. Pick a system to see where it sits. + frame: + title: A diamond of tubes + description: The frame holds every other part, and carries the rider's weight down to both wheels. + wheels: + title: Two wheels + description: Spokes keep each rim true under load, and the tires grip the road and soak up bumps. + drivetrain: + title: Seven gears + description: The pedals turn the chainring, the chain turns the rear cogs, and the derailleur moves the chain across seven of them for climbs, flats and descents. + brakes: + title: Rim brakes + description: Each hand lever pulls a cable that squeezes two pads against the rim. + cockpit: + title: Where you meet the bike + description: The handlebar, the stem and the saddle set how you sit and steer. +--- +::`, + }, +] + +export const roastPrompt = 'Plan a Sunday lamb roast for friends, I still don’t know how many people are coming' + +export const roastMarkdown = `### A Sunday lamb roast for friends + +A slow Sunday dinner: rosemary and garlic lamb, potatoes with crisp edges, honey-glazed roots, and something green to cut through the richness. Your guest list is still moving, so the shopping list follows your headcount. + +::image-collage +--- +images: + - src: ${unsplash('1529692236671-f1f6cf9683ba', 800, 600)} + alt: Roast meat carved on a wooden board + - src: ${unsplash('1780304223294-d901e0378bb8', 400, 300)} + alt: A roast dinner with gravy and vegetables + - src: ${unsplash('1688437307687-fe226bddfab1', 400, 300)} + alt: A long table set for dinner with candles +--- +:: + +::summary-card{label="Your dinner plan" title="Sunday roast with friends"} +- **Style:** relaxed and generous, served family-style +- **Prep:** most of it done before anyone arrives +- **Oven time:** about 2 to 3 hours, depending on the lamb +- **Dessert:** baked the day before +:: + +#### 1. The menu + +::media-list +--- +items: + - image: ${unsplash('1529692236671-f1f6cf9683ba')} + title: Rosemary and garlic leg of lamb + description: Rubbed with lemon, garlic, rosemary and olive oil. Carve it at the table, with gravy and mint sauce. + - image: ${unsplash('1552661397-4233881ea8c8')} + title: Crisp roast potatoes + description: Parboiled, shaken until the edges go fluffy, then roasted until deep golden. + - image: ${unsplash('1548869206-93b036288d7e')} + title: Honey-glazed carrots and parsnips + description: Roasted with thyme and a spoonful of honey. + - image: ${unsplash('1631255444970-d06bbdd2c04f')} + title: Lemony greens + description: Tenderstem broccoli with toasted almonds and lemon zest. + - image: ${unsplash('1506127946181-abb01a32593c')} + title: Apple crumble + description: Baked the day before, warmed while you eat the main course. Serve with vanilla ice cream. +--- +:: + +#### 2. What to buy + +Change the number of people, and the quantities follow. + +::quantity-calculator{:guests="5"} +--- +items: + - name: Bone-in leg of lamb + perGuest: 400 + unit: g + - name: Potatoes + perGuest: 300 + unit: g + - name: Carrots + perGuest: 1.5 + - name: Parsnips + perGuest: 1 + - name: Tenderstem broccoli + perGuest: 125 + unit: g + - name: Apples for the crumble + perGuest: 0.8 +--- +Generous portions. The lamb weight includes the bone. +:: + +Also pick up garlic, rosemary, thyme, lemons, honey, almonds, gravy ingredients, mint sauce and vanilla ice cream. + +#### 3. Cooking timeline + +Timed for dinner at 7 pm with a 2.4 kg leg of lamb. Adjust the roasting time to your joint. + +::timeline{title="Cooking checklist"} +--- +items: + - time: Saturday + title: Get ahead + detail: Bake the crumble, mix the marinade and set the table. + - time: 3:30 pm + title: Season the lamb + detail: Rub in the marinade and let the lamb come to room temperature. + - time: 4:30 pm + title: Lamb in the oven + detail: Roast it, and trust a meat thermometer more than the clock. + - time: 5:15 pm + title: Prepare the sides + detail: Peel the roots, parboil the potatoes and rough up their edges. + - time: 6:15 pm + title: Rest the lamb + detail: Cover it loosely. Turn the oven up and roast the potatoes and roots. + - time: 6:45 pm + title: Finish + detail: Make the gravy, cook the greens and warm the plates. + - time: 7:00 pm + title: Dinner + detail: Carve at the table. Warm the crumble while everyone eats. +--- +:: + +Cook the lamb to at least 63 °C (145 °F) inside, then let it rest for 3 minutes or more. + +#### 4. Three hosting tips + +- **Buy the lamb last**, once your numbers are final. +- **Free up oven space**: the lamb and the potatoes both need room. +- **Put out something to nibble**, such as olives, bread and whipped feta, while you finish cooking. +` + +export const roastPlainMarkdown = `Sure! Since you don't know the headcount yet, only the lamb really needs to scale. Most sides stretch for a couple of extra guests. + +### Sunday roast menu + +- **Main:** rosemary and garlic leg of lamb +- **Sides:** roast potatoes, honey-glazed carrots and parsnips, lemony broccoli +- **Sauce:** gravy and mint sauce +- **Dessert:** apple crumble with vanilla ice cream + +### How much to buy + +| Guests | Lamb (bone-in) | Potatoes | +| --- | --- | --- | +| 4 | 1.6 kg | 1.2 kg | +| 6 | 2.4 kg | 1.8 kg | +| 8 | 3.2 kg | 2.4 kg | + +### Timeline for dinner at 7 pm + +1. **Saturday:** bake the crumble and mix the marinade. +2. **3:30 pm:** season the lamb. +3. **4:30 pm:** lamb in the oven. +4. **5:15 pm:** parboil the potatoes and prepare the roots. +5. **6:15 pm:** rest the lamb, roast the potatoes and roots. +6. **6:45 pm:** gravy and greens. +7. **7:00 pm:** carve and serve. + +Cook the lamb to at least 63 °C (145 °F) inside, then let it rest for 3 minutes or more. + +### Tips + +- Buy the lamb once your numbers are final. +- The lamb and the potatoes both need oven space. +- Put out olives and bread while you finish cooking. +` diff --git a/docs/content/10.use-cases/1.intelligent-ui.md b/docs/content/10.use-cases/1.intelligent-ui.md index 71fa0572..db713be9 100644 --- a/docs/content/10.use-cases/1.intelligent-ui.md +++ b/docs/content/10.use-cases/1.intelligent-ui.md @@ -21,6 +21,11 @@ links: An intelligent UI answers with interactive components, such as a calculator, a timeline, or a chart, instead of text only. With Comark, the model writes component syntax in its Markdown answer, and your app renders your own components while the answer streams. +::intelligent-ui-hero +:: + +Each step above is one Markdown answer rendered by Comark. Select **Source** to see what the model writes: the last step adds a `::bike-diagram` component, and the app renders it as an interactive diagram. + ## The pattern On October 7, 2026, OpenAI introduced [Intelligent UI in ChatGPT](https://openai.com/index/gpt-6-for-everyone/). ChatGPT can now answer with graphics, buttons, forms, charts, and small tools. OpenAI describes how it works: @@ -40,32 +45,41 @@ Comark isn't affiliated with OpenAI, and ChatGPT doesn't use Comark. This page s ## What the model writes -The model answers in Markdown, and places a component where it helps. Here, a dinner plan includes a calculator for quantities and a timeline: +The model answers in Markdown, and places a component where it helps. Here is the same dinner plan twice: as plain Markdown, and with components for the photos, the menu, the quantities, and the timeline. Change the number of people, tick the steps, select **Replay** to stream the answer again, or **Source** to read it: -```mdc -## Pizza night for friends +::intelligent-ui-comparison +:: -Here is a plan that scales with your guest count. +The calculator and the timeline come from this part of the answer: -::quantity-calculator{:guests="6"} +```mdc +::quantity-calculator{:guests="5"} --- items: - - name: Pizza dough balls - perGuest: 1.5 - unit: balls - - name: Mozzarella - perGuest: 80 + - name: Bone-in leg of lamb + perGuest: 400 + unit: g + - name: Potatoes + perGuest: 300 unit: g --- +Generous portions. The lamb weight includes the bone. :: -::timeline -- **4:00 pm** Take the dough out of the fridge. -- **6:30 pm** Heat the oven to its highest setting. +::timeline{title="Cooking checklist"} +--- +items: + - time: 3:30 pm + title: Season the lamb + detail: Rub in the marinade and let the lamb come to room temperature. + - time: 4:30 pm + title: Lamb in the oven + detail: Roast it, and trust a meat thermometer more than the clock. +--- :: ``` -The `:` prefix gives a typed value: `guests` is the number `6`. The YAML block passes `items` as an array of objects. The list inside `::timeline` is the default slot. See [component syntax](/syntax/components) for props, slots, and nesting. +The `:` prefix gives a typed value: `guests` is the number `5`. The YAML block passes `items` as an array of objects. The text after the YAML block is the default slot. See [component syntax](/syntax/components) for props, slots, and nesting. ## Write streamable components @@ -73,7 +87,7 @@ A component renders on the first frame that contains its opening line, and gets 1. While the model writes `{:guests="`, the `guests` prop is `undefined`. 2. While it writes the YAML block, `items` is missing. -3. Then `items` grows one entry at a time, and the last entry can miss fields, for example `{ name: 'Mozzarel' }`. +3. Then `items` grows one entry at a time, and the last entry can miss fields, for example `{ name: 'Potat' }`. Make every prop optional, and render what you have. Check model values before you use them, and keep the user's edits separate from the props, so a later frame doesn't overwrite them: @@ -216,9 +230,9 @@ export const catalog: CatalogEntry[] = [ }, { tag: 'timeline', - description: 'Shows ordered steps with times. The default slot is a Markdown list.', + description: 'Shows timed steps that the user can tick off.', useWhen: 'The answer is a schedule or a sequence of timed steps.', - example: '::timeline\n- **9:00** Arrive.\n- **9:30** Start.\n::', + example: '::timeline{title="Checklist"}\n---\nitems:\n - time: "9:00"\n title: Arrive\n detail: Check in at the front desk.\n---\n::', }, ] diff --git a/docs/public/intelligent-ui/bicycle.svg b/docs/public/intelligent-ui/bicycle.svg new file mode 100644 index 00000000..6fa07959 --- /dev/null +++ b/docs/public/intelligent-ui/bicycle.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + +