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.

A two-pane workbench (sidebar + main):

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)),
])

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) {
        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::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::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.