Skip to main content

Crate damascene_core

Crate damascene_core 

Source
Expand description
Damascene badge icon

§damascene-core

Damascene hero demo — release console rendered headlessly through the wgpu backend

Backend-agnostic UI primitives for Damascene apps.

Damascene is shaped around how an LLM authors UI: vocabulary parity with the training distribution matters more than configurability, and the minimum output should be the correct output. The catalog below — card, sidebar, tabs_list, dialog, toolbar, item, etc. — mirrors the shadcn / WAI-ARIA shapes models already know. Reach for those before composing primitives. column / row / stack / button / text are layout fallbacks for when no named widget fits, not the canonical app vocabulary.

§Reach for these first

When scaffolding a UI, prefer the named affordance over the underlying primitives. The list is short:

IntentIdiomatic callAvoid
Grouped content (settings card, panel of fields, any “boxed” surface)card([card_header([card_title("Title")]), card_content([...])]) or titled_card("Title", [...])column([...]).fill(CARD).stroke(BORDER).radius(...) or column(...).surface_role(SurfaceRole::Panel) (Panel only sets stroke + shadow — not fill)
Flat sidebar / nav railsidebar([sidebar_header(...), sidebar_group([...])]) plus sidebar_menu_button_with_icon(...) for leaf itemscolumn(...).fill(CARD).stroke(BORDER).width(SIDEBAR_WIDTH) or column(...).surface_role(SurfaceRole::Panel) for the sidebar surface
Sidebar tree / dense resource listkeep sidebar([...]), then make one local tree_row(depth, leading, label, trailing, current) helper from row([...]).focusable().height(Size::Fixed(28.0..40.0)).current() and indent via paddingforcing every branch/file/stash into flat sidebar_menu_button(...), or using card/table rows inside the sidebar
Toolbar / page header rowtoolbar([toolbar_title("Documents"), spacer(), toolbar_group([...])]).padding(Sides::xy(tokens::SPACE_4, tokens::SPACE_2)) as app chrome; use card_header only inside a cardwrapping the top toolbar in card([card_content([toolbar(...)])]), or ad hoc action rows with inconsistent vertical alignment
Top-level app menusmenubar([menubar_trigger("app-menu", "file", "File", open == Some("file"))]) plus root-layer menubar_menu("app-menu", "file", [...]), folded with menubar::apply_event(&mut open, &event, "app-menu")a toolbar row of unrelated dropdown buttons, or a hand-rolled File/Edit/View strip
Conversation / event-log rowa local log_row(role_color, faint_fill, content) helper built from row([gutter, content]); use accordion_item for collapsible reasoning/tool detailscard([card_header([badge(role)]), card_content([message])]) repeated for every chat message
Tabs / segmented controltabs_list(key, &current, options) + tabs::apply_event; for icon/badge/count tabs, use tabs_list_from_triggers([tab_trigger_content(key, value, [...], selected)])manual row([button, button]).fill(MUTED) segment, or hand-rolled selected-tab state
Object/action list row (recent repo, file, project, person)item([item_media_icon(...), item_content([item_title(...), item_description(...)]), item_actions(...)]) inside item_group([...])row([column([text, text]), button, button]).key(...) — every clickable repo/file/project/person row is item, not a hand-rolled focusable row
Dialogdialog(key, [dialog_header([...]), body, dialog_footer([...])])a custom centered overlay card
Edge sheetsheet(key, SheetSide::Right, [sheet_header([...]), body])a modal manually pinned to the viewport edge
Dropdown / context menu (action menu — items perform side-effects; for a value-bound picker see the next row)dropdown_menu(key, trigger, [dropdown_menu_label(...), dropdown_menu_item_with_shortcut(...)])a popover full of hand-rolled rows; per-row [Edit][Delete] button pairs that should collapse into one trigger
Value picker (model, timezone, status, any enum field)select_trigger(key, &current_label) + select_menu(key, [(value, label), …]) paired via select::apply_event(&mut value, &mut open, &event, key, parse)dropdown_menu with hand-rolled state, an accordion-based picker, or a hand-rolled popover full of menu_items
Standard tooltip.tooltip("...") on any elementa manually-positioned popover
Callout / validation summaryalert([alert_title("Heads up"), alert_description("Details")]).warning()a manually styled card with status-colored text
Status indicator (Online, Pending, Failed)badge("Online").success() (also .warning() / .destructive() / .info() / .muted())text("● Online").text_color(SUCCESS)
User identity chipavatar_fallback("Alicia Koch") or avatar_image(img)a bare image/text node with custom circle styling
Loading placeholderskeleton().width(Size::Fixed(220.0)) or skeleton_circle(32.0)hard-coded muted rectangles
Section dividerseparator() / vertical_separator()hand-rolled 1px boxes
Command/menu rowcommand_row("git-branch", "New branch", "Ctrl+B") or command_item([...])repeating icon-slot/label/shortcut rows by hand
Collapsible sectionaccordion_item("settings", "security", "Security", open, [...]) + accordion::apply_event(...)a button plus hand-managed chevron row
Breadcrumb pathbreadcrumb_list([breadcrumb_link("Projects"), breadcrumb_separator(), breadcrumb_page("Damascene")])a raw slash-delimited text string
Paginationpagination_content([pagination_previous(), pagination_link("1", true), pagination_next()])unaligned text buttons with custom square sizing
Section heading / page title.heading() / h2(...) (or .title() / h3(...)).font_size(16.0).font_weight(Bold).text_color(...)
Field label.label().font_weight(Semibold).text_color(...)
Helper / hint text.caption() or .muted().font_size(12.0).text_color(tokens::MUTED_FOREGROUND)
Inline code / mono.code() or mono(...).font_family("monospace") (no such API)
Selected row in a collection.selected() chainablesurface_role(SurfaceRole::Selected) (works, but .selected() reads better and sets content color)
Current nav / page item.current() chainablesurface_role(SurfaceRole::Current)
Resizable divider between two panesresize_handle(Axis::Row).key(...) + resize_handle::apply_event_fixed(...)divider() (which is non-interactive) plus drag plumbing
Indent inside a list (e.g. tree depth).padding(Sides { left: indent, ..Sides::zero() })row([spacer().width(Fixed(indent)), ...])
Toggle (preferences)switch(self.value).key(k) + switch::apply_event(...)a button with two text labels
Labelled control row (settings, prefs)field_row("Label", control)hand-rolled row([text("Label").label(), spacer(), control]) repeated everywhere
Stacked long field (URL, path, token, search)form_item([form_label("Repository URL"), form_control(text_input(...).width(Size::Fill(1.0))), form_description(...)]) inside form([...])using field_row for long strings, or repeating column([text(label).label(), text_input(...)])
Date picker / month gridcalendar_month("billing-date", "May 2026", days) with CalendarDay::new(value, label).selected() / .outside() / .disabled() and calendar::apply_event(&mut selected, &event, "billing-date")a hand-rolled grid of tiny buttons with ad hoc selected/outside-month styling
Raster image (logo, screenshot, thumbnail)image(Image::from_rgba8(...)).image_fit(ImageFit::Contain)reaching for a custom shader
Throwaway notificationaccumulate ToastSpec::success("Saved") and return them from App::drain_toastsspinning a manual modal with a timer

§Smells that mean an affordance is being missed

One per line — if any of these appear in your tree, a named widget is the right reach instead.

  • column(...).surface_role(SurfaceRole::Panel) — use card() or sidebar(). Panel decorates, it doesn’t fill.
  • column([row, body]).fill(CARD).stroke(BORDER) reinventing the card silhouette — call card([...]) (or titled_card(...)).
  • column(...).fill(CARD).stroke(BORDER).width(SIDEBAR_WIDTH) reinventing the sidebar surface — call sidebar([...]).
  • A keyed/focusable row([column([t1,t2]), button, button]) used as a clickable file/repo/project/person/asset entry — use item([item_media, item_content([item_title, item_description]), item_actions([...])]) so hover, press, focus, the rail, and the slots are named.
  • Per-row [Edit][Delete] button pairs in a narrow list — collapse to one dropdown_menu trigger or a single icon-button kebab; let selection drive editing in the right pane.
  • card([card_content([toolbar(...)])]) for the top app header — a toolbar is chrome, not a boxed content object.
  • A File / Edit / View strip built from separate button(...) or dropdown_menu(...) calls — use menubar, menubar_trigger, and menubar_menu so the root, triggers, dismiss keys, and menu-row anatomy stay named.
  • row([title, spacer(), action]).fill(MUTED).stroke(BORDER) header bar sitting above a body inside a card — that’s a hand-rolled card_header. Lift the row into card_header([...]).fill(MUTED), or split the “header bar over body” block into its own card([card_header(...), card_content(...)]).
  • A sidebar full of unrelated card() sections — use sidebar_group, accordion_item, or a local dense tree_row helper inside sidebar.
  • A transcript rendered as one card() per message — use an event-log row with a narrow role gutter so long assistant output reads as a stream.
  • field_row squeezing a repository URL, filesystem path, token, or search query into the right edge of a dialog — use stacked form_item.
  • A date picker rendered as a manual 7-column row/column grid — use calendar_month so day sizing, outside-month dimming, selected state, and nav keys are canonical.
  • .gap(0.0) — already the default; delete it.
  • .font_size(...).font_weight(...).text_color(...) on the same node — use a role modifier (.heading() / .label() / .caption() / .muted()).
  • Wrapping a single child in row([single]) to apply .padding(...) — every El has .padding() directly.
  • An explicit .fill(tokens::BACKGROUND) on the root — the host already paints it.
  • IconName::AlertCircle as a placeholder when the project has its own SVG — use SvgIcon::parse_current_color(include_str!("...")) and pass it to icon(...).

§Common app shells

When the catalog widget doesn’t fit your data shape exactly, wrap it rather than replace it. card([...]) and sidebar([...]) are column-flavored containers that bundle the canonical fill + stroke + radius + shadow + role recipe — you can put any composition inside.

At the window root, start from page([...]) — it bakes the window padding (so toolbars and text don’t sit flush against window edges or clip under rounded window corners) and an overlay root (so .tooltip() layers have somewhere to mount). A bare column/row returned from App::build has neither.

A two-pane workbench (sidebar + main):

page([row([
    sidebar([
        sidebar_header([h3("Repository")]),
        sidebar_group([
            sidebar_group_label("Branches"),
            sidebar_menu([/* sidebar_menu_button_with_icon(...) per branch */]),
        ]),
    ]),
    column([
        toolbar([toolbar_title("main"), spacer(), button("Push").primary().key("push")]),
        card([card_content([/* your view */])]).height(Size::Fill(1.0)),
    ])
    .width(Size::Fill(1.0))
    .height(Size::Fill(1.0)),
])
.gap(tokens::SPACE_4)
.height(Size::Fill(1.0))])

A three-column workbench (sidebar + center + inspector). Use card() for the inspector pane the same way — it gives you the same recipe the sidebar uses, just at Size::Fixed(WIDTH) instead of SIDEBAR_WIDTH. Reach into card_header for selected-item identity (title, metadata, copy / open actions) and card_content for the scrollable body. The slots bake shadcn’s stock recipe directly into their constructors — card_header is p-6 with a small space-y-1.5 between title and description; card_content and card_footer are p-6 pt-0. Naive use produces the right visual without an explicit .padding(...). Override per-call, Tailwind-shaped: .padding(SPACE_4) to swap the whole recipe (= p-4), or the additive shorthands .pt(...), .pb(...), .pl(...), .pr(...), .px(...), .py(...) to override a single side or axis while preserving the constructor’s defaults elsewhere (= p-6 pt-0). The two compose, so a tighter card body that keeps the no-double-pad seam is card_content([...]).padding(tokens::SPACE_3).pt(0.0) (= p-3 pt-0) — .padding(SPACE_3) alone would reset the bundled pt-0 and leave a visible doubled gap below the header. The override case below uses .padding(0.0) on card_content because its only child is a scroll(...) that should reach the card edges.

row([
    sidebar([/* nav */]),
    column([/* center pane */]).width(Size::Fill(1.0)),
    card([
        card_header([
            row([h3(item.title.clone()), spacer(), button("Copy ID").ghost().key("copy")])
                .align(Align::Center)
                .gap(tokens::SPACE_2),
            text(item.subtitle.clone()).muted().caption(),
        ]),
        card_content([scroll([/* sub-cards, fields */])])
            .padding(0.0)
            .height(Size::Fill(1.0)),
    ])
    .width(Size::Fixed(320.0))
    .height(Size::Fill(1.0)),
])

A list of selectable objects inside a card (recent repos, project imports, search results) — this is item + item_group, not a column of hand-rolled rows:

titled_card(
    "Recent repositories",
    [item_group([
        item([
            item_media_icon(IconName::Folder),
            item_content([
                item_title("damascene"),
                item_description("/home/christian/workspace/damascene"),
            ]),
            item_actions([badge("current").info()]),
        ])
        .key("recent:damascene")
        .current(),
        item([
            item_media_icon(IconName::Folder),
            item_content([
                item_title("whisper-git"),
                item_description("/home/christian/workspace/whisper-git"),
            ]),
            item_actions([icon(IconName::ChevronRight).muted()]),
        ])
        .key("recent:whisper"),
    ])],
)

A tabbed page:

column([
    tabs_list("view", &self.tab, [("working", "Working"), ("history", "History")]),
    match self.tab.as_str() {
        "history" => history_view(self),
        _ => working_view(self),
    },
])

A chat / event-log workbench:

Keep the app shell boring: sidebar on the left, toolbar for selected thread identity and actions, scroll(log_rows) for the transcript, and a bottom composer row with text_area plus actions. The transcript itself is not a card collection. Cards isolate objects; event logs should scan as one continuous record with small role markers.

fn log_row(role_color: Color, faint_fill: Option<Color>, content: El) -> El {
    let row = row([
        El::new(Kind::Custom("log_gutter"))
            .fill(role_color)
            .width(Size::Fixed(3.0))
            .height(Size::Fill(1.0)),
        content
            .padding(Sides {
                left: tokens::SPACE_3,
                right: tokens::SPACE_2,
                top: tokens::SPACE_2,
                bottom: tokens::SPACE_2,
            })
            .width(Size::Fill(1.0)),
    ])
    .width(Size::Fill(1.0));
    if let Some(fill) = faint_fill { row.fill(fill) } else { row }
}

column([
    toolbar([toolbar_title(thread.title.clone()), spacer(), badge(thread.state_label)]),
    scroll(thread.items.iter().map(|item| match item {
        // `paragraph` for plain user input; `md(...)` when the source
        // is markdown (assistant streams, tool output prose).
        ChatItem::User(text) => log_row(tokens::INFO, Some(tokens::INFO.with_alpha(38)), paragraph(text)),
        ChatItem::Assistant(text) => log_row(tokens::SUCCESS, None, md(text)),
        ChatItem::Reasoning { id, open, preview, body } => log_row(
            tokens::MUTED_FOREGROUND,
            None,
            accordion_item("reasoning", id, preview, *open, [md(body)]),
        ),
        ChatItem::Tool(call) => log_row(
            tokens::WARNING,
            None,
            accordion_item("tool", call.id, call.summary, call.open, [code_block(call.details)]),
        ),
    }))
    .key(format!("thread-scroll:{}", thread.id))
    .padding(tokens::SPACE_4)
    .gap(tokens::SPACE_2)
    .height(Size::Fill(1.0)),
    row([
        text_area(&self.compose, &self.selection, "compose").height(Size::Fixed(120.0)),
        button("Send").primary().key("send"),
    ])
    .gap(tokens::SPACE_3)
    .padding(tokens::SPACE_3)
    .align(Align::End),
])

When a text_area is fixed-height like the composer above, the app should queue text_area::caret_scroll_request_for(...) from App::drain_scroll_requests after text_area::apply_event(...) returns true. That lets PageUp/PageDown, arrows, paste, and typing keep the caret visible without emitting a scroll request every frame.

If sidebar_menu_button_with_icon doesn’t fit your row anatomy (count badges, nested sub-groups, custom leading icons), keep the outer sidebar([...]) for the panel surface and compose the rows freely inside. Same for card_content — anything column-shaped goes there.

§App trait scaffolding

Once the shell is in place, the App trait wires it to the runtime. build returns the El tree; on_event handles routed events keyed by the same string passed to .key("...") — same identifier, no separate .on_click(...) registration. Hover, press, and focus visuals are applied automatically; the author never tags a node “this one is hovered.”

use damascene_core::prelude::*;

struct Counter {
    value: i32,
}

impl App for Counter {
    fn build(&self, _cx: &BuildCx) -> El {
        column([
            h1(format!("{}", self.value)),
            row([
                button("-").key("dec"),
                button("+").key("inc").primary(),
            ])
            .gap(tokens::SPACE_2),
        ])
        .gap(tokens::SPACE_3)
        .padding(tokens::SPACE_4)
    }

    fn on_event(&mut self, event: UiEvent, _cx: &EventCx) {
        if event.is_click_or_activate("inc") {
            self.value += 1;
        } else if event.is_click_or_activate("dec") {
            self.value -= 1;
        }
    }
}

This is a deliberately tiny example — column/row/button is fine for a counter, but for a real app start from the workbench skeletons above. Use damascene-winit-wgpu to open a native desktop window. Use damascene-wgpu directly only when writing a custom host or embedding Damascene in an existing render loop. If the UI mirrors external state, refresh it in App::before_build — hosts call that hook immediately before each build.

§Surface roles, briefly

SurfaceRole is a decoration layer, not a fill recipe. Panel and Raised set stroke and shadow only — they assume you (or the widget wrapping you) supplied a fill. Sunken / Selected / Current / Input / Danger do default a fill from the palette. Per-variant contracts live on the SurfaceRole enum’s rustdoc; reach for the .selected() / .current() chainables for state, and for card() / sidebar() / dialog() / popover() for surface containers.

§El modifier reference

Every modifier below is a chainable method on El. They compose freely and order rarely matters. Grouped by what you’re saying. For the full widget surface (constructors like card, tabs_list, dropdown_menu, …), see the “Reach for these first” catalog above and the damascene_core::prelude re-exports.

§Sizing

ModifierMeaning
.width(Size) / .height(Size)Set axis size. Size::Fixed(n), Size::Hug, Size::Fill(weight).
.fill_width() / .fill_height()Shorthand for Size::Fill(1.0) on that axis. CSS width: 100% / height: 100%.
.fill_size()Both axes fill.
.hug()Both axes hug content.
.min_width(n) / .max_width(n) / .min_height(n) / .max_height(n)Bound a resolved axis. Compose with any Size.
.size(ComponentSize) / .medium() / .large()T-shirt size for stock controls.

§Padding

ModifierMeaning
.padding(Sides or f32)Set all sides (wholesale, like CSS padding).
.pt(n) / .pb(n) / .pl(n) / .pr(n)Override one side. Mirrors Tailwind pt-N etc., and preserves the constructor’s other sides.
.px(n) / .py(n)Override one axis. Mirrors Tailwind px-N / py-N.

§Layout (container nodes)

ModifierMeaning
.gap(n)Inter-child spacing.
.axis(Axis)Override flow direction.
.align(Align)Cross-axis alignment.
.justify(Justify)Main-axis distribution.
.clip()Clip overflow to this node’s rect.
.scrollable()Make this node a scroll viewport.
.scrollbar() / .no_scrollbar()Show or suppress the draggable thumb.
.pin_end()Stick offset to the tail (chat/log behaviour).
.arrow_nav_siblings()Treat focusable children as one arrow-navigable group.
.virtual_anchor_policy(p)Override virtual-list anchor point.
.layout(|cx| -> Vec<Rect>)Replace child distribution with a custom function.
.child(c) / .children(iter)Append children.

§Text content

ModifierMeaning
.text(s)Set the text content.
.text_color(c) / .color(c)Color the run.
.text_align(a) / .center_text() / .end_text()Block alignment.
.text_wrap(w) / .wrap_text() / .nowrap_text()Wrap mode.
.text_overflow(o) / .ellipsis() / .max_lines(n)Truncation.
.font_size(n) / .line_height(n)Type metrics.
.font_weight(w) / .bold() / .semibold()Weight.
.font_family(f) / .inter() / .roboto()Sans face.
.mono_font_family(f) / .jetbrains_mono() / .mono()Mono face.
.italic() / .underline() / .strikethrough()Inline style.
.background(c)Inline-run highlight (HTML <mark>).
.code()Markdown-flavoured inline code.
.link(url)Link run.

§Text role presets

ModifierRole
.display() / .heading() / .title()h1 / h2 / h3 sizes. The h1 / h2 / h3 constructors are shorthands for these on a fresh text node.
.body()Default running text.
.label()Field labels.
.caption()Hint / helper text.
.text_role(TextRole)Set the role directly when none of the above presets fit.
.small() / .xsmall()Step the text role size down.
.muted()Subdued foreground over any role (color only).

§Variants & states (theme-aware)

ModifierMeaning
.primary() / .secondary() / .ghost() / .outline()Button/badge variant.
.success() / .warning() / .destructive() / .info()Status color.
.selected() / .current()Active row in a collection / current nav item.
.disabled() / .invalid() / .loading()Interactive state.

§Visual decoration

ModifierMeaning
.fill(Color)Solid background fill.
.dim_fill(Color)Fill that envelopes from 0 → 1 with hover/press.
.stroke(Color) / .stroke_width(n)Border.
.radius(Corners or f32)Rounded corners.
.shadow(n)Drop shadow.
.surface_role(SurfaceRole)Token-driven decoration (Panel, Raised, Sunken, …).
.paint_overflow(Sides)Allow paint to extend beyond the layout rect.
.focus_ring_inside() / .focus_ring_outside()Pin focus ring position.
.tooltip(s)Standard tooltip text.
.cursor(Cursor) / .cursor_pressed(Cursor)Hover cursor / press-time override.

§Icon / image / vector / surface

ModifierMeaning
.icon_source(src) / .icon_name(src)Built-in IconName or an SvgIcon.
.icon_size(n) / .icon_stroke_width(n)Icon sizing.
.image(img) / .image_fit(f) / .image_tint(c)Raster source.
.vector_source(a) / .vector_painted() / .vector_mask(c) / .vector_render_mode(m)Vector source and paint mode.
.surface_source(s) / .surface_alpha(a) / .surface_fit(f) / .surface_transform(t)App-owned GPU texture.

§Animation, transform, custom paint

ModifierMeaning
.opacity(v) / .translate(x, y) / .scale(v)Per-frame transform.
.animate(Timing)Per-(node, prop) tween/spring.
.redraw_within(Duration)Ask the host to drive a frame within deadline.
.shader(ShaderBinding)Custom shader.

§Identity & interaction

ModifierMeaning
.key(s)Stable id for event routing, hit-test, and state survival across rebuilds.
.focusable() / .always_show_focus_ring()Tab participation.
.selectable()Static-text selection opt-in.
.capture_keys()Route raw key events here while focused.
.block_pointer()Stop pointer hits at this node.
.hit_overflow(Sides)Enlarge the hit area beyond the rect.
.consumes_touch_drag()Claim drag from a touch panner.
.alpha_follows_focused_ancestor() / .blink_when_focused() / .state_follows_interactive_ancestor()Inherit interaction visuals from a focused/interactive ancestor.
.hover_alpha(rest, peak)Custom hover envelope.
.metrics_role(MetricsRole)Theme-facing metrics role.
.selection_source(src)Override selection identity.
.at(file, line) / .at_loc(loc)Override source-location identity for #[track_caller]-aware widgets.

§Math

ModifierMeaning
.math_expr(expr) / .math_display(d)Lay out a MathExpr (MathML or TeX-parsed).

§API layers

  • prelude — the app and widget author surface; what an LLM should usually import.
  • widgets — controlled widget builders and their apply_event / apply_input helpers (e.g. text_input::apply_event, slider::normalized_from_event).
  • bundle — headless artifacts (tree.txt / draw_ops.txt / lint.txt / .svg) for tests and design review. The lint pass catches raw colors, text overflow, alignment misses, missing surface fills, and duplicate ids.
  • ir, paint, runtime, text atlas, vector mesh, and MSDF modules are advanced backend / diagnostic surfaces. Public because sibling backend crates use them; ordinary app code should not start there.

The crate ships runnable examples under examples/: settings, scroll_list, virtual_list, inline_runs, modal, custom_shader, circular_layout, plus the dashboard_01_calibration reference fixture that mirrors the shadcn dashboard-01 demo through stock widgets.

§Rendering smoke test

Any App builds and renders headlessly through the bundle pipeline:

use damascene_core::prelude::*;

struct Demo;

impl App for Demo {
    fn build(&self, _cx: &BuildCx) -> El {
        card([
            card_header([card_title("Hello")]),
            card_content([text("rendered headlessly")]),
        ])
        .width(Size::Fixed(320.0))
    }
}

let app = Demo;
let theme = app.theme();
let mut ui = app.build(&BuildCx::new(&theme));
let bundle = render_bundle(&mut ui, Rect::new(0.0, 0.0, 720.0, 400.0));
assert!(!bundle.svg.is_empty());

§Rendering pipeline

Builders produce an El tree. Layout writes rects into UiState. The draw-op pass resolves visual facts into backend-neutral DrawOp values. Backend runners turn those draw ops into GPU resources and route pointer/keyboard input back into UiEvent values.

The stock surface shader is rounded_rect; text, icons, custom shaders, and backdrop-sampling materials all flow through the same tree and event model.

Re-exports§

pub use theme::palette;
pub use theme::style;
pub use theme::tokens;
pub use anim::AnimProp;
pub use anim::AnimValue;
pub use anim::Animation;
pub use anim::SpringConfig;
pub use anim::Timing;
pub use anim::TweenConfig;
pub use bundle::artifact::Bundle;
pub use bundle::artifact::render_bundle;
pub use bundle::artifact::render_bundle_themed;
pub use bundle::artifact::render_bundle_with;
pub use bundle::artifact::render_bundle_with_theme;
pub use bundle::artifact::write_bundle;
pub use bundle::inspect::dump_tree;
pub use bundle::lint::Finding;
pub use bundle::lint::FindingKind;
pub use bundle::lint::LintReport;
pub use bundle::lint::lint;
pub use bundle::manifest::draw_ops_text;
pub use bundle::manifest::shader_manifest;
pub use bundle::svg::svg_from_ops;
pub use clipboard::delete_selection_event;
pub use clipboard::paste_text_event;
pub use cursor::Cursor;
pub use event::App;
pub use event::AppShader;
pub use event::BuildCx;
pub use event::EventCx;
pub use event::FrameTrigger;
pub use event::HostDiagnostics;
pub use event::KeyChord;
pub use event::KeyModifiers;
pub use event::KeyPress;
pub use event::Pointer;
pub use event::PointerButton;
pub use event::PointerId;
pub use event::PointerKind;
pub use event::SurfaceColorInfo;
pub use event::SurfaceFormatInfo;
pub use event::UiEvent;
pub use event::UiEventKind;
pub use event::UiKey;
pub use event::UiTarget;
pub use focus::focus_order;
pub use hit_test::hit_test;
pub use hit_test::hit_test_target;
pub use icons::svg::IconSource;
pub use icons::svg::IntoIconSource;
pub use icons::svg::SvgIcon;
pub use icons::svg::SvgIconPaintMode;
pub use icons::IconStroke;
pub use icons::all_icon_names;
pub use icons::icon;
pub use icons::icon_path;
pub use icons::icon_strokes;
pub use icons::icon_vector_asset;
pub use layout::LayoutCtx;
pub use layout::LayoutFn;
pub use layout::VirtualAnchorPolicy;
pub use layout::VirtualItems;
pub use layout::VirtualMode;
pub use layout::layout;
pub use math::MathAtom;
pub use math::MathDisplay;
pub use math::MathExpr;
pub use math::MathLayout;
pub use math::MathParseError;
pub use math::layout_math;
pub use math::parse_mathml;
pub use math::parse_mathml_with_display;
pub use math::parse_tex;
pub use metrics::ComponentSize;
pub use metrics::MetricsRole;
pub use metrics::ThemeMetrics;
pub use scene::GeometryHandle;
pub use scene::GeometryId;
pub use scene::LineData;
pub use scene::LineSegment;
pub use scene::LinesHandle;
pub use scene::MeshData;
pub use scene::MeshHandle;
pub use scene::MeshVertex;
pub use scene::PointData;
pub use scene::PointsHandle;
pub use scene::ScenePoint;
pub use state::AnimationMode;
pub use state::UiState;
pub use state::WidgetState;
pub use style::StyleProfile;
pub use palette::Palette;
pub use selection::Selection;
pub use selection::SelectionPoint;
pub use selection::SelectionRange;
pub use selection::selected_text;
pub use text::metrics::MeasuredText;
pub use text::metrics::TextGeometry;
pub use text::metrics::TextHit;
pub use text::metrics::TextLayout;
pub use text::metrics::TextLine;
pub use text::metrics::caret_xy;
pub use text::metrics::caret_xy_with_family;
pub use text::metrics::hit_text;
pub use text::metrics::hit_text_with_family;
pub use text::metrics::layout_text;
pub use text::metrics::layout_text_with_family;
pub use text::metrics::layout_text_with_line_height_and_family;
pub use text::metrics::line_height;
pub use text::metrics::line_width;
pub use text::metrics::line_width_with_family;
pub use text::metrics::measure_text;
pub use text::metrics::selection_rects;
pub use text::metrics::selection_rects_with_family;
pub use text::metrics::wrap_lines;
pub use text::metrics::wrap_lines_with_family;
pub use theme::Theme;
pub use tree::Align;
pub use tree::Axis;
pub use tree::Color;
pub use tree::Corners;
pub use tree::El;
pub use tree::FontFamily;
pub use tree::FontWeight;
pub use tree::IconName;
pub use tree::InteractionState;
pub use tree::Justify;
pub use tree::Kind;
pub use tree::Rect;
pub use tree::Sides;
pub use tree::Size;
pub use tree::Source;
pub use tree::SurfaceRole;
pub use tree::TextAlign;
pub use tree::TextOverflow;
pub use tree::TextRole;
pub use tree::TextWrap;
pub use tree::chart3d;
pub use tree::column;
pub use tree::divider;
pub use tree::hard_break;
pub use tree::math;
pub use tree::math_block;
pub use tree::math_inline;
pub use tree::row;
pub use tree::scroll;
pub use tree::spacer;
pub use tree::stack;
pub use tree::surface;
pub use tree::text_runs;
pub use tree::vector;
pub use tree::virtual_list;
pub use tree::virtual_list_dyn;
pub use vector::IconMaterial;
pub use vector::VectorRenderMode;
pub use widgets::accordion::AccordionAction;
pub use widgets::accordion::accordion;
pub use widgets::accordion::accordion_content;
pub use widgets::accordion::accordion_item;
pub use widgets::accordion::accordion_item_key;
pub use widgets::accordion::accordion_separator;
pub use widgets::accordion::accordion_trigger;
pub use widgets::accordion::accordion_trigger_with_icon;
pub use widgets::alert::alert;
pub use widgets::alert::alert_description;
pub use widgets::alert::alert_title;
pub use widgets::avatar::DEFAULT_AVATAR_SIZE;
pub use widgets::avatar::avatar_fallback;
pub use widgets::avatar::avatar_image;
pub use widgets::avatar::avatar_initials;
pub use widgets::badge::badge;
pub use widgets::blockquote::blockquote;
pub use widgets::breadcrumb::breadcrumb;
pub use widgets::breadcrumb::breadcrumb_item;
pub use widgets::breadcrumb::breadcrumb_list;
pub use widgets::breadcrumb::breadcrumb_page;
pub use widgets::breadcrumb::breadcrumb_separator;
pub use widgets::button::button;
pub use widgets::button::button_with_icon;
pub use widgets::button::icon_button;
pub use widgets::calendar::CalendarAction;
pub use widgets::calendar::CalendarDay;
pub use widgets::calendar::calendar_day_key;
pub use widgets::calendar::calendar_month;
pub use widgets::card::card;
pub use widgets::card::card_content;
pub use widgets::card::card_description;
pub use widgets::card::card_header;
pub use widgets::card::card_title;
pub use widgets::card::titled_card;
pub use widgets::checkbox::checkbox;
pub use widgets::code_block::code_block;
pub use widgets::code_block::code_block_chrome;
pub use widgets::command::command_group;
pub use widgets::command::command_icon;
pub use widgets::command::command_item;
pub use widgets::command::command_label;
pub use widgets::command::command_row;
pub use widgets::command::command_shortcut;
pub use widgets::dialog::dialog;
pub use widgets::dialog::dialog_content;
pub use widgets::dialog::dialog_description;
pub use widgets::dialog::dialog_header;
pub use widgets::dialog::dialog_title;
pub use widgets::dropdown_menu::dropdown_menu;
pub use widgets::dropdown_menu::dropdown_menu_content;
pub use widgets::dropdown_menu::dropdown_menu_content_with_density;
pub use widgets::dropdown_menu::dropdown_menu_group;
pub use widgets::dropdown_menu::dropdown_menu_icon;
pub use widgets::dropdown_menu::dropdown_menu_item;
pub use widgets::dropdown_menu::dropdown_menu_item_label;
pub use widgets::dropdown_menu::dropdown_menu_item_with_density;
pub use widgets::dropdown_menu::dropdown_menu_item_with_icon;
pub use widgets::dropdown_menu::dropdown_menu_item_with_icon_and_shortcut;
pub use widgets::dropdown_menu::dropdown_menu_item_with_shortcut;
pub use widgets::dropdown_menu::dropdown_menu_label;
pub use widgets::dropdown_menu::dropdown_menu_separator;
pub use widgets::dropdown_menu::dropdown_menu_shortcut;
pub use widgets::dropdown_menu::dropdown_menu_with_density;
pub use widgets::editor_tabs::ActiveTabStyle;
pub use widgets::editor_tabs::CloseVisibility;
pub use widgets::editor_tabs::EditorTabsAction;
pub use widgets::editor_tabs::EditorTabsConfig;
pub use widgets::editor_tabs::editor_tab;
pub use widgets::editor_tabs::editor_tab_add_key;
pub use widgets::editor_tabs::editor_tab_close_key;
pub use widgets::editor_tabs::editor_tab_select_key;
pub use widgets::editor_tabs::editor_tabs;
pub use widgets::editor_tabs::editor_tabs_with;
pub use widgets::form::field_row;
pub use widgets::form::form;
pub use widgets::form::form_control;
pub use widgets::form::form_description;
pub use widgets::form::form_item;
pub use widgets::form::form_label;
pub use widgets::form::form_message;
pub use widgets::form::form_section;
pub use widgets::input_otp::input_otp;
pub use widgets::item::item;
pub use widgets::item::item_actions;
pub use widgets::item::item_content;
pub use widgets::item::item_description;
pub use widgets::item::item_group;
pub use widgets::item::item_header;
pub use widgets::item::item_media;
pub use widgets::item::item_media_icon;
pub use widgets::item::item_separator;
pub use widgets::item::item_title;
pub use widgets::list::bullet_list;
pub use widgets::list::numbered_list;
pub use widgets::list::numbered_list_from;
pub use widgets::list::task_list;
pub use widgets::menubar::MenubarAction;
pub use widgets::menubar::menubar;
pub use widgets::menubar::menubar_content;
pub use widgets::menubar::menubar_group;
pub use widgets::menubar::menubar_icon;
pub use widgets::menubar::menubar_item;
pub use widgets::menubar::menubar_item_label;
pub use widgets::menubar::menubar_item_with_icon;
pub use widgets::menubar::menubar_item_with_icon_and_shortcut;
pub use widgets::menubar::menubar_item_with_shortcut;
pub use widgets::menubar::menubar_label;
pub use widgets::menubar::menubar_menu;
pub use widgets::menubar::menubar_separator;
pub use widgets::menubar::menubar_shortcut;
pub use widgets::menubar::menubar_trigger;
pub use widgets::menubar::menubar_trigger_key;
pub use widgets::number_scrubber::ScrubDrag;
pub use widgets::number_scrubber::ScrubberOpts;
pub use widgets::number_scrubber::number_scrubber;
pub use widgets::numeric_input::NumericInputOpts;
pub use widgets::numeric_input::numeric_input;
pub use widgets::overlay::modal;
pub use widgets::overlay::modal_panel;
pub use widgets::overlay::overlay;
pub use widgets::overlay::overlays;
pub use widgets::overlay::scrim;
pub use widgets::page::page;
pub use widgets::pagination::pagination;
pub use widgets::pagination::pagination_content;
pub use widgets::pagination::pagination_ellipsis;
pub use widgets::pagination::pagination_item;
pub use widgets::pagination::pagination_next;
pub use widgets::pagination::pagination_previous;
pub use widgets::popover::Anchor;
pub use widgets::popover::MenuDensity;
pub use widgets::popover::Side;
pub use widgets::popover::TOUCH_MENU_ITEM_HEIGHT;
pub use widgets::popover::anchor_rect;
pub use widgets::popover::apply_menu_density;
pub use widgets::popover::context_menu;
pub use widgets::popover::context_menu_with_density;
pub use widgets::popover::dropdown;
pub use widgets::popover::menu_item;
pub use widgets::popover::menu_item_with_density;
pub use widgets::popover::popover;
pub use widgets::popover::popover_panel;
pub use widgets::progress::progress;
pub use widgets::radio::RadioAction;
pub use widgets::radio::radio_group;
pub use widgets::radio::radio_item;
pub use widgets::radio::radio_option_key;
pub use widgets::select::SelectAction;
pub use widgets::select::select_menu;
pub use widgets::select::select_menu_with_density;
pub use widgets::select::select_option_key;
pub use widgets::select::select_trigger;
pub use widgets::separator::separator;
pub use widgets::separator::vertical_separator;
pub use widgets::sheet::SheetSide;
pub use widgets::sheet::sheet;
pub use widgets::sheet::sheet_content;
pub use widgets::sheet::sheet_description;
pub use widgets::sheet::sheet_header;
pub use widgets::sheet::sheet_title;
pub use widgets::sidebar::sidebar;
pub use widgets::sidebar::sidebar_group;
pub use widgets::sidebar::sidebar_group_label;
pub use widgets::sidebar::sidebar_header;
pub use widgets::sidebar::sidebar_menu;
pub use widgets::sidebar::sidebar_menu_button;
pub use widgets::sidebar::sidebar_menu_button_with_icon;
pub use widgets::sidebar::sidebar_menu_item;
pub use widgets::sidebar::sidebar_menu_label;
pub use widgets::skeleton::skeleton;
pub use widgets::skeleton::skeleton_circle;
pub use widgets::slider::SliderAction;
pub use widgets::slider::slider;
pub use widgets::switch::switch;
pub use widgets::table::table;
pub use widgets::table::table_body;
pub use widgets::table::table_cell;
pub use widgets::table::table_head;
pub use widgets::table::table_head_el;
pub use widgets::table::table_header;
pub use widgets::table::table_row;
pub use widgets::tabs::TabsAction;
pub use widgets::tabs::tab_option_key;
pub use widgets::tabs::tab_trigger;
pub use widgets::tabs::tab_trigger_content;
pub use widgets::tabs::tabs_list;
pub use widgets::tabs::tabs_list_from_triggers;
pub use widgets::text::h1;
pub use widgets::text::h2;
pub use widgets::text::h3;
pub use widgets::text::mono;
pub use widgets::text::paragraph;
pub use widgets::text::text;
pub use widgets::text_area::text_area;
pub use widgets::text_input::ClipboardKind;
pub use widgets::text_input::MaskMode;
pub use widgets::text_input::TextInputOpts;
pub use widgets::text_input::TextSelection;
pub use widgets::text_input::text_input;
pub use widgets::text_input::text_input_with;
pub use widgets::toggle::ToggleAction;
pub use widgets::toggle::toggle;
pub use widgets::toggle::toggle_group;
pub use widgets::toggle::toggle_group_multi;
pub use widgets::toggle::toggle_item;
pub use widgets::toggle::toggle_option_key;
pub use widgets::toolbar::toolbar;
pub use widgets::toolbar::toolbar_description;
pub use widgets::toolbar::toolbar_group;
pub use widgets::toolbar::toolbar_title;

Modules§

affine
2D affine transforms.
anim
Animation primitives.
bundle
Artifact pipeline — the agent loop’s feedback channel.
clipboard
Backend-neutral clipboard helpers for host integrations.
color
Color values + colorspace conversion + perceptual interpolation.
cursor
Pointer-cursor model.
draw_ops
Tree → DrawOp resolution.
event
Event types and the App trait.
focus
Linear focus traversal — collects the focusable keyed nodes into the order Tab/Shift-Tab walks. Ancestors with clip shrink the visible rect so a focusable that’s been scrolled out of view is dropped.
hit_test
Pointer hit-testing and scroll routing on a laid-out tree.
icons
Built-in vector icons.
image
App-supplied raster images.
ir
Backend-neutral draw-op IR.
layout
Flex-style layout pass over the El tree.
math
Native math expression IR and box layout.
metrics
Component sizing vocabulary.
prelude
App and widget author prelude.
profile
Span-tracing primitives gated behind the profiling Cargo feature.
scene
Backend-neutral data for the Scene3D draw-op: small, polished, hardware-accelerated 3D graphs and models.
scroll
App-side scroll request types.
selection
Library-level text selection model.
shader
Shader handles, uniform values, and bindings.
state
UiState — the renderer’s interaction-state side store.
surface
App-owned GPU textures composited into the paint stream.
text
Text shaping + atlas infrastructure. The unified RGBA glyph atlas (color emoji + outline glyphs) lives in atlas; line measurement, wrapping, and the TextLayout value backends consume live in metrics.
theme
Theme-level shader routing.
toast
Runtime-synthesized toast notifications.
tooltip
Hover-driven tooltips.
tree
The El tree — the central data structure.
vector
Backend-agnostic SVG/vector asset IR.
widgets
Stock widget vocabulary — reach for these before composing column / row / button / text by hand.

Macros§

profile_span
Enter a span for the rest of the current scope. No-op unless the profiling feature is enabled. Pass a &'static str literal — the macro forwards it to tracing::trace_span! (or to a () binding when off).

Structs§

AppTexture
An app-owned GPU texture handed to Damascene for compositing. Cheap Arc-backed clone; pass into crate::tree::surface to display.
AppTextureId
Stable identity for an AppTexture. Allocated by the constructor that wraps the underlying GPU texture; backends cache their bind groups / descriptor sets keyed on this id, so it must not be reused for a different texture during the lifetime of the wrapping AppTexture.
ShaderBinding
A shader handle plus the uniforms to bind for one draw.

Enums§

DrawOp
One paint operation in the laid-out frame.
ShaderHandle
Where a draw op’s pixels come from.
StockShader
Shipped shader inventory. See docs/SHADER_VISION.md for the shader model.
SurfaceAlpha
How an AppTexture composes with widgets painted underneath it.
SurfaceFormat
Pixel format of an AppTexture. The widget composites by sampling the texture; the backend picks a sampler / shader path that matches.
SurfaceSource
Source of pixels for a crate::tree::Kind::Surface widget.
TextAnchor
UniformValue
A single uniform’s value. Keep small and concrete; this is the wire format between the grammar layer and the renderer.

Traits§

AppTextureBackend
Backend implementation of an AppTexture. Implemented by damascene-wgpu and damascene-vulkano against their native texture types; the runtime downcasts via Self::as_any in the backend’s record path.

Functions§

draw_ops
Walk the laid-out tree and emit draw ops in paint order.
draw_ops_with_theme
Walk the laid-out tree and emit draw ops using a caller-supplied theme.
next_app_texture_id
Allocate a fresh AppTextureId. Used by backend constructors. App code should not call this directly — go through the backend’s app_texture(...) constructor instead.

Type Aliases§

UniformBlock
Named uniform values for a single draw. BTreeMap for deterministic iteration in artifacts.