Scene
Composes a clinia.com-style patient graph in code: a card, entity pills, relation tags and lines that build in on scroll.
When to use
- Illustrate what Clinia does on a marketing page: a patient's data connected into one story.
- A section that needs a scene and has no Rive file for it.
When not to use
- A product (
base-luma) surface: the scene roles are marketing only, and product apps don't load them. - Real patient data, or a chart someone needs to read: use Chart or Table.
- A hero that needs full motion (morphs, loops, steps): use a Rive scene.
Install
npx shadcn@latest add @clinia/scenePreview
Usage
import { Scene, SceneCard, SceneLines, ScenePill, SceneTag } from "@/components/ui/scene";
<Scene label="Darius Lee's patient graph: type 2 diabetes, measured by HbA1c." aspect="4 / 3">
<SceneCard x={48} y={53} name="Darius Lee" detail="Jul 28, 1956" />
<ScenePill x={48} y={33} kind="condition" emphasis at={0.3}>T2 diabetes</ScenePill>
<ScenePill x={15} y={14} kind="lab" at={0.6}>HbA1c 6.9%</ScenePill>
{/* Each line once both its ends are on screen, drawn from the inner end. */}
<SceneLines lines={[{ from: [48, 33], to: [48, 53], at: 0.6 }, { from: [48, 33], to: [15, 14], at: 0.9 }]} />
{/* Each tag on its line's midpoint, once the line is drawn. */}
<SceneTag x={31.5} y={23.5} kind="lab" at={1.2}>Measures</SceneTag>
</Scene>Clinia rules
- Import
@clinia/tailwindcss/marketingafter the theme. Thetheme-marketingitem already does. - One patient card as the anchor and one
emphasispill per scene. - Build in order with
at: the card at 0, the emphasized pill, the outer pills, then each line once both its ends are on screen (give it its ownat), then each tag once its line is drawn. Never leave a line floating. - Colour tags by the entity they point to:
MEASURESa lab,TREATSwith a medication,COMPLICATIONof a condition. - Two shapes work: a patient graph (the card in the middle, entities around it) and sources into one record (chips on one side, dashed links converging on the card, entities on the other).
- Keep 5 to 10 parts on screen, and leave about a quarter of the width empty on each side.
- Vital (
scene-condition) is a curated display spot here, never an accent elsewhere on the page.
Do and don't
Accessibility
Built in
- A scene is one
role="img"named bylabel; its parts are hidden from assistive tech, so a screen reader hears one sentence, not a list of tags. - Tag text is
foregroundon a tint of its entity colour, so it reads in both themes even at 10px. - Reduced motion collapses the build: the scene appears complete.
Your responsibility
- Write
labelas the sentence the scene shows, and say the same in the text beside it. Never put the only copy of a message inside a scene.
How to test
- With a screen reader, move to the scene: it reads the label once, as an image.
- Turn on reduced motion and reload: the scene is complete on arrival.
API
Scene
| Prop | Values | Default | Description |
|---|---|---|---|
| label | string | – | What the scene shows, in one sentence. The scene is one image to assistive tech; say the same in nearby text. |
| aspect | string | 4 / 3 | CSS aspect ratio of the scene, such as "413 / 310". |
| width | number | DESIGN_WIDTH | Width in px the parts lay out at before the scene scales to fit. Wider gives boxes and lines more room around the same type. |
SceneCard
| Prop | Values | Default | Description |
|---|---|---|---|
| x | number | – | Horizontal centre of the part, in percent of the scene's width. |
| y | number | – | Vertical centre of the part, in percent of the scene's height. |
| at | number | – | Delay in seconds after the scene comes into view. |
| w | number | – | Width of a box part (a panel, or a card with fields), in percent of the scene's width. Without it the box fits its content. |
| data-node | string | – | The plan node this part draws, so lines can find its edges. SceneFromPlan sets it. |
| name | string | – | The anchor of a patient graph, usually the patient. |
| detail | string | – | One line under the name, such as a date of birth or a path. |
| avatar | string | – | Photo URL. Without one, the card shows initials. |
| fields | { label: string; value: string; }[] | – | Label and value pairs listed under the name, such as a provider's address. With fields, the card is a box that lines meet at its edge. |
| more | string | – | A last mono line under the fields, such as "13 other fields". |
| display | boolean | false | A larger card with the name in the display serif, for the patient at the centre of a scattered record. |
SceneChip
| Prop | Values | Default | Description |
|---|---|---|---|
| x | number | – | Horizontal centre of the part, in percent of the scene's width. |
| y | number | – | Vertical centre of the part, in percent of the scene's height. |
| at | number | – | Delay in seconds after the scene comes into view. |
| w | number | – | Width of a box part (a panel, or a card with fields), in percent of the scene's width. Without it the box fits its content. |
| data-node | string | – | The plan node this part draws, so lines can find its edges. SceneFromPlan sets it. |
SceneField
| Prop | Values | Default | Description |
|---|---|---|---|
| seed | string | – | |
| count | number | – |
SceneFromPlan
| Prop | Values | Default | Description |
|---|---|---|---|
| plan | ScenePlan | – | The scene to render, as data. |
SceneLines
| Prop | Values | Default | Description |
|---|---|---|---|
| lines | { from: [number, number]; to: [number, number]; dashed?: boolean; at?: number; }[] | – | Lines between two points in percent of the scene, drawn from |
| at | number | 0 | Delay in seconds for lines without their own |
ScenePanel
| Prop | Values | Default | Description |
|---|---|---|---|
| x | number | – | Horizontal centre of the part, in percent of the scene's width. |
| y | number | – | Vertical centre of the part, in percent of the scene's height. |
| at | number | – | Delay in seconds after the scene comes into view. |
| w | number | – | Width of a box part (a panel, or a card with fields), in percent of the scene's width. Without it the box fits its content. |
| data-node | string | – | The plan node this part draws, so lines can find its edges. SceneFromPlan sets it. |
| title | string | – | Mono uppercase title at the top of the box, such as "Provider records". |
| rows | { label: string; detail?: string; chip?: string; }[] | – | One line each: a name, an optional grey detail, and an optional chip on the right. A line can start or end on a row. |
| more | string | – | A last mono line under the rows, such as "12 more records". |
ScenePill
| Prop | Values | Default | Description |
|---|---|---|---|
| x | number | – | Horizontal centre of the part, in percent of the scene's width. |
| y | number | – | Vertical centre of the part, in percent of the scene's height. |
| at | number | – | Delay in seconds after the scene comes into view. |
| w | number | – | Width of a box part (a panel, or a card with fields), in percent of the scene's width. Without it the box fits its content. |
| data-node | string | – | The plan node this part draws, so lines can find its edges. SceneFromPlan sets it. |
| kind | conditionlabmedication | – | Entity type: sets the dot colour. |
| emphasis | boolean | false | The one entity the scene is about. Gets the condition-coloured outline; one per scene. |
SceneSource
| Prop | Values | Default | Description |
|---|---|---|---|
| x | number | – | Horizontal centre of the part, in percent of the scene's width. |
| y | number | – | Vertical centre of the part, in percent of the scene's height. |
| at | number | – | Delay in seconds after the scene comes into view. |
| w | number | – | Width of a box part (a panel, or a card with fields), in percent of the scene's width. Without it the box fits its content. |
| data-node | string | – | The plan node this part draws, so lines can find its edges. SceneFromPlan sets it. |
| source | string | – | Where the record came from, such as "EHR · Regional hospital". |
| value | string | – | The fact as that source wrote it, such as "Metformin HCl 500 mg tab". |
| meta | string | – | How it arrived, in one grey line, such as "fhir r4 · rxnorm coded". |
| kind | conditionlabmedicationbeige | – | Tints the card and colours its source line with an entity colour, or a warm beige for a source with no entity. Without it the card is plain. |
| rotate | number | 0 | A small tilt in degrees, -4 to 4, so the records read as scattered. |
SceneTag
| Prop | Values | Default | Description |
|---|---|---|---|
| x | number | – | Horizontal centre of the part, in percent of the scene's width. |
| y | number | – | Vertical centre of the part, in percent of the scene's height. |
| at | number | – | Delay in seconds after the scene comes into view. |
| w | number | – | Width of a box part (a panel, or a card with fields), in percent of the scene's width. Without it the box fits its content. |
| data-node | string | – | The plan node this part draws, so lines can find its edges. SceneFromPlan sets it. |
| kind | conditionlabmedication | – | The entity the relation points to: MEASURES a lab, TREATS with a medication, COMPLICATION of a condition. |