solverforge-ui
Frontend component library for SolverForge constraint-optimization applications. Emerald-themed, zero-framework, vendor-ready. One line to mount, zero npm, zero webpack.
// Cargo.toml
solverforge-ui =
// main.rs
let app = router
.merge // serves /sf/*
.fallback_service;
That's it. Every asset is compiled into the binary via include_dir!.
Screenshots
Planner123 — Gantt chart with dependency arrows, project-colored bars, and constraint scoring:

Furnace Scheduler — Timeline rail with resource cards, temperature/load gauges, and positioned job blocks:

Philosophy
Every backend element has a corresponding UI element. The library grows
alongside the solver. When you scaffold a new SolverForge project with
solverforge new, it's already wired in.
Quick Start
API Reference
Components
| Factory | Returns | Description |
|---|---|---|
SF.createHeader(config) |
HTMLElement |
Sticky header with logo, title, nav tabs, solve/stop/analyze buttons |
SF.createStatusBar(config) |
{el, updateScore, setSolving, updateMoves, colorDotsFromAnalysis} |
Score display + constraint dot indicators |
SF.createButton(config) |
HTMLButtonElement |
Button with variant/size/icon/shape modifiers |
SF.createModal(config) |
{el, body, open, close, setBody} |
Dialog with emerald gradient header, backdrop, Escape key |
SF.createTable(config) |
HTMLElement |
Data table with headers and row click |
SF.createTabs(config) |
{el, show} |
Tab panel container |
SF.createFooter(config) |
HTMLElement |
Footer with links and version |
SF.createApiGuide(config) |
HTMLElement |
REST API documentation panel |
SF.showToast(config) |
void |
Toast notification (auto-dismiss) |
SF.showError(title, detail) |
void |
Danger toast shorthand |
SF.showTab(tabId) |
void |
Activate a tab panel by ID |
Timeline Rail
| Factory | Returns | Description |
|---|---|---|
SF.rail.createHeader(config) |
HTMLElement |
Day/period column header above resource cards |
SF.rail.createCard(config) |
{el, rail, addBlock, clearBlocks, setSolving} |
Resource lane with identity, gauges, stats, and block rail |
SF.rail.addBlock(rail, config) |
HTMLElement |
Positioned block (task/job) inside a rail |
SF.rail.addChangeover(rail, config) |
HTMLElement |
Diagonal-striped gap between blocks |
Gantt (Frappe Gantt)
| Factory | Returns | Description |
|---|---|---|
SF.gantt.create(config) |
{el, mount, setTasks, refresh, changeViewMode, highlightTask, destroy} |
Split-pane Gantt with grid table + Frappe Gantt chart |
Solver Lifecycle
| Factory | Returns | Description |
|---|---|---|
SF.createBackend(config) |
Backend adapter | HTTP or Tauri IPC transport |
SF.createSolver(config) |
{start, stop, isRunning, getJobId} |
SSE state machine with auto status bar updates |
Utilities
| Function | Description |
|---|---|
SF.score.parseHard(str) |
Extract hard score from "0hard/-42soft" |
SF.score.parseSoft(str) |
Extract soft score |
SF.score.parseMedium(str) |
Extract medium score |
SF.score.getComponents(str) |
{hard, medium, soft} |
SF.score.colorClass(str) |
"score-green" / "score-yellow" / "score-red" |
SF.colors.pick(key) |
Tango palette color for any key (cached) |
SF.colors.project(index) |
{main, dark, light} from 8-color project palette |
SF.colors.reset() |
Clear the color cache |
SF.escHtml(str) |
HTML-escape a string |
SF.el(tag, attrs, ...children) |
DOM element factory |
Button Variants
// white bg, emerald text
// red bg, white text
// emerald-700 bg
// gray border
Timeline Rail
The scheduling hero view. Resource lanes with positioned task blocks, gauges, stats, heatmaps, and changeover indicators.
// Day header
var header = SF..;
container.;
// One card per resource (furnace, vehicle, employee, machine...)
var card = SF..;
container.;
// Add task blocks (positioned by start/end within horizon)
card.;
// Changeover gap between blocks
SF..;
// Solving state (breathing emerald glow)
card.;
Gauge styles: heat (blue→amber→red), load (emerald→amber→red), emerald (solid green).
Gantt Chart
Interactive task scheduling with Frappe Gantt. Split-pane layout: task grid on top, SVG timeline chart on bottom. Drag to reschedule, resize to change duration, project-colored bars, dependency arrows.
var gantt = SF..;
gantt.;
gantt.;
gantt.;
gantt.;
View modes: Quarter Day, Half Day, Day, Week, Month.
Backend Adapters
Axum (default)
var backend = ;
Expects standard SolverForge REST endpoints:
POST /schedules— start solvingGET /schedules/{id}— get solutionGET /schedules/{id}/events— SSE streamGET /schedules/{id}/analyze— constraint analysisDELETE /schedules/{id}— stop solvingGET /demo-data/{name}— load demo dataset
Tauri
var backend = ;
Generic fetch (Rails, etc.)
var backend = ;
Optional Modules
Map (Leaflet)
var map = SF..;
map.;
map.;
map.;
map.;
map.;
map.; // dim all routes except this color
map.;
SF..; // Google polyline algorithm
Design System
Colors
| Token | Hex | Usage |
|---|---|---|
--sf-emerald-500 |
#10b981 |
Primary brand, success states |
--sf-emerald-600 |
#059669 |
Primary dark |
--sf-emerald-700 |
#047857 |
Primary buttons, links |
--sf-red-600 |
#dc2626 |
Danger buttons, hard violations |
--sf-amber-500 |
#f59e0b |
Warnings, soft violations |
--sf-gray-50 |
#f9fafb |
Backgrounds |
--sf-gray-900 |
#111827 |
Primary text |
8 project colors for assignment: emerald, blue, purple, amber, pink, cyan, rose, lime.
Fonts
- Space Grotesk (body, headings) — variable weight 300-700, self-hosted WOFF2
- JetBrains Mono (code, scores, data) — variable weight 100-800, self-hosted WOFF2
Spacing
--sf-space-{0,1,2,3,4,5,6,8,10,12,16} — 0 to 4rem in quarter-rem increments.
Shadows
--sf-shadow-{sm,base,md,lg,xl,2xl} — elevation scale.
--sf-shadow-emerald — colored shadow for branded elements.
Animations
sf-spin / sf-dot-pulse / sf-score-flash / sf-dialog-slide-in / sf-breathe / sf-slide-in / sf-fade-in / sf-late-glow
Project Structure
solverforge-ui/
├── Cargo.toml # 2 deps: axum + include_dir
├── src/lib.rs # routes() + asset serving
├── Makefile # make → cats css-src/ + js-src/ into sf.css + sf.js
├── css-src/ # 16 CSS source files (numbered for concat order)
│ ├── 00-tokens.css # design system variables
│ ├── 01-reset.css # box-sizing reset
│ ├── 02-typography.css # @font-face declarations
│ ├── 03-layout.css # .sf-app, .sf-main, tab panels
│ ├── 04-header.css # .sf-header
│ ├── 05-statusbar.css # .sf-statusbar + constraint dots
│ ├── 06-buttons.css # .sf-btn variants
│ ├── 07-modal.css # .sf-modal
│ ├── 08-table.css # .sf-table + constraint analysis table
│ ├── 09-badges.css # .sf-badge variants
│ ├── 10-cards.css # .sf-card, .sf-kpi-card
│ ├── 11-tooltip.css # .sf-tooltip
│ ├── 12-footer.css # .sf-footer
│ ├── 13-scrollbars.css # custom webkit scrollbars
│ ├── 14-animations.css # @keyframes + toast + api guide
│ ├── 15-rail.css # timeline rail, resource cards, blocks
│ └── 16-gantt.css # Frappe Gantt + Split.js layout + bar styling
├── js-src/ # 15 JS source files
│ ├── 00-core.js # SF namespace, escHtml, el()
│ ├── 01-score.js # score parsing
│ ├── 02-colors.js # Tango palette + project colors
│ ├── 03-buttons.js # createButton()
│ ├── 04-header.js # createHeader()
│ ├── 05-statusbar.js # createStatusBar()
│ ├── 06-modal.js # createModal()
│ ├── 07-tabs.js # createTabs(), showTab()
│ ├── 08-table.js # createTable()
│ ├── 09-toast.js # showToast(), showError()
│ ├── 10-backend.js # createBackend() — axum/tauri/fetch
│ ├── 11-solver.js # createSolver() — SSE state machine
│ ├── 12-api-guide.js # createApiGuide(), createFooter()
│ ├── 13-rail.js # timeline rail, resource cards, blocks
│ └── 14-gantt.js # Frappe Gantt wrapper (split pane, grid, chart)
└── static/sf/ # Embedded assets (include_dir!)
├── sf.css # concatenated from css-src/
├── sf.js # concatenated from js-src/
├── img/ # SVG logos (ouroboros, favicon, brand)
├── fonts/ # Space Grotesk + JetBrains Mono WOFF2
├── modules/ # optional: sf-map.js/css
└── vendor/ # FontAwesome 6.5, Leaflet 1.9, Frappe Gantt, Split.js
Integration Paths
| Project Type | How It Works |
|---|---|
| Axum | Add crate dep, call .merge(solverforge_ui::routes()) |
| Tauri | Add crate dep, serve via Tauri's asset protocol or custom command |
| Rails | Copy static/sf/ into public/sf/, reference in layouts |
| Any HTTP server | Copy static/sf/, serve as static files |
solverforge new |
Automatic — wired into generated project |
Non-Rust Projects
The static/sf/ directory is self-contained. Copy it, git-submodule it,
or symlink it into any project that serves static files:
# git submodule
Development
# Edit source files
# Rebuild concatenated files
# Compile the crate (embeds updated assets)
Acknowledgments
solverforge-ui builds on these excellent open-source projects:
| Project | Use | License | Link |
|---|---|---|---|
| Font Awesome Free | Icons (Solid subset) | CC BY 4.0 (icons), SIL OFL (fonts), MIT (code) | github |
| Frappe Gantt | Interactive Gantt chart | MIT | github |
| Split.js | Resizable split panes | MIT | github |
| Leaflet | Interactive maps (optional module) | BSD-2-Clause | github |
| Space Grotesk | Body typeface | SIL Open Font License 1.1 | github |
| JetBrains Mono | Monospace typeface | SIL Open Font License 1.1 | github |
| Axum | Rust web framework | MIT | github |
| include_dir | Compile-time file embedding | MIT | github |
License
Apache-2.0