Development Guide¶
Complete setup and workflow documentation for developing FiberPath GUI.
Prerequisites¶
Required¶
- Node.js 24.x and npm 11.x (nodejs.org)
- Rust 1.70+ (rustup.rs)
- Python CLI installed and available in PATH (for development mode)
- Via pip:
pip install fiberpath - Via uv:
uv pip install fiberpath - From source:
pip install -e .in repo root
Important: Production installers bundle the CLI—end users don't need Python. Developers need it for local testing.
Platform-Specific¶
Windows:
- Microsoft Visual Studio C++ Build Tools
- WebView2 (usually pre-installed on Windows 10+)
macOS:
- Xcode Command Line Tools:
xcode-select --install
Linux:
- Build essentials:
sudo apt install build-essential libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
CLI Discovery & Fallback¶
The GUI uses a two-stage CLI discovery process implemented in src-tauri/src/cli_path.rs:
1. Check for Bundled CLI (Production Mode):
- Windows installed:
resources\_up_\bundled-cli\fiberpath.exe - Windows dev:
resources\bundled-cli\fiberpath.exe - macOS:
Resources/bundled-cli/fiberpath(relative to.appbundle) - Linux:
resources/bundled-cli/fiberpath
2. Fallback to System PATH (Development Mode):
If bundled CLI not found, uses which fiberpath (Unix) or where fiberpath (Windows).
3. Error if Neither Found:
Returns user-friendly message suggesting pip install fiberpath.
Why This Design:
- Production users: Zero setup—CLI bundled in installer
- Contributors: No PyInstaller required for local dev
- CI testing: Works in both modes automatically
Verification:
# Ensure CLI is on PATH for development
fiberpath --version
# Test GUI with bundled CLI
npm run tauri build # Check src-tauri/target/release/bundle/
Initial Setup¶
# Clone repository
git clone https://github.com/your-org/fiberpath.git
cd fiberpath/fiberpath_gui
# Install dependencies
npm install
# Verify CLI is available
fiberpath --version
Development¶
Run Development Build¶
npm run tauri dev
This is the canonical dev loop — the only command that runs the GUI with a working backend. It starts:
- Vite dev server with HMR (Hot Module Replacement)
- Tauri window with development console enabled
- The API sidecar, spawned and supervised by the Rust shell (compute, file, and machine features work; the status bar reads CLI: Ready)
- File watcher for Rust changes (auto-rebuild)
Hot Reload:
- Frontend changes (Svelte/TypeScript) reload instantly
- Rust changes trigger rebuild (~5-15 seconds)
Don't QA the prebuilt
src-tauri/target/release/fiberpath_guibinary. It embeds the frontend that existed when it was last compiled, which is often stale. Always usenpm run tauri dev(or rebuild) to exercise current code.
Run Frontend Only (no backend)¶
npm run dev
Starts the Vite dev server at http://localhost:5173 for UI-only work —
styling, layout, component iteration with browser DevTools.
There is no backend in this mode. The sidecar URL and health are obtained
through the Tauri bridge (invoke("api_base_url") / check_cli_health), which
does not exist in a plain browser — so compute, file, and machine features are
unavailable. The app detects this and shows a calm "Browser preview" banner
(status bar: Browser preview) rather than an error. For anything that needs
the backend, use npm run tauri dev.
Testing¶
Run All Tests¶
npm test
Run Tests in Watch Mode¶
npm test -- --watch
Run Specific Test File¶
npm test -- schemas.test.ts
Test Coverage¶
npm test -- --coverage
Current Test Suite:
- Schema and validation tests (
src/lib) - Reactive state tests (
src/state/*.svelte.test.ts) - Service and converter tests
- Svelte component tests (
*.svelte.test.ts)
Building¶
Development Build¶
npm run tauri build -- --debug
Creates debug binary with:
- Development console enabled
- Faster build time
- Source maps included
Production Build¶
npm run tauri build
Creates optimized release bundle:
- Windows:
.exeinstaller insrc-tauri/target/release/bundle/msi/ - macOS:
.dmgdisk image insrc-tauri/target/release/bundle/dmg/ - Linux:
.AppImageor.debinsrc-tauri/target/release/bundle/
Build Output:
src-tauri/target/release/
├── fiberpath-gui[.exe] # Binary executable
└── bundle/
├── msi/ # Windows installer
├── dmg/ # macOS disk image
└── appimage/ # Linux portable app
Packaging¶
Create Distributable Package¶
npm run package
This runs:
npm run tauri build(production build)- Package verification
- Signing (if configured)
Release Checklist:
- [ ] Update version in
package.json,Cargo.toml,tauri.conf.json - [ ] Run
npm run check:allandnpm test - [ ] Run
npm run buildandnpm run perf:bundle - [ ] Test on target platforms
- [ ] Build production bundles
- [ ] Verify bundle functionality
- [ ] Tag release in git
Code Quality¶
Run All Checks¶
npm run check:all
Runs in sequence:
- TypeScript compiler (
tsc --noEmit) - Stylelint (
src/**/*.css) - CSS variable guard (
lint:css:vars) - Rust formatter check (
cargo fmt --check) - Clippy (Rust linting)
check:all covers the plain .ts type check; the .svelte/.svelte.ts
type check (npm run check:svelte, via svelte-check) runs as its own command.
CI Pipeline: These checks plus npm run check:svelte, npm run build, and
npm run perf:bundle run on every PR.
Individual Commands¶
# Type and CSS checks
npm run lint # TypeScript type check (tsc --noEmit) for .ts
npm run check:svelte # svelte-check for .svelte and .svelte.ts
npm run lint:css # Stylelint
npm run lint:css:vars # CSS variable guard
npm run lint:css:fix # Auto-fix CSS lint issues
# Rust checks
npm run format:check # cargo fmt --check
npm run format:fix # cargo fmt
npm run clippy # cargo clippy -- -D warnings
# Tests and build
npm test # Vitest
npm run test:coverage # Vitest with coverage
npm run build # Vite production build
npm run perf:bundle # Enforce bundle budget and emit metrics
Project Structure¶
fiberpath_gui/
├── src/ # Frontend code (Svelte 5 + Vite SPA)
│ ├── main.svelte.ts # App entry point (mounts App.svelte)
│ ├── App.svelte # Root component with workspace layout
│ ├── shell/ # App shell (MenuBar, tabs, workspaces, status bar)
│ ├── components/ # Feature components (forms, editors, layers, canvas, machine, dialogs)
│ ├── ui/ # Reusable primitives (NumberField, Dialog, …)
│ ├── state/ # Reactive runes singletons (*.svelte.ts)
│ ├── services/ # Plain service functions (file operations)
│ ├── lib/ # Tauri/API command bindings, validation helpers
│ ├── api/ # OpenAPI-generated sidecar client
│ ├── styles/ # Global CSS + design tokens
│ ├── tests/ # Test setup and mocks
│ └── types/ # Domain models, document, converters
├── src-tauri/ # Rust backend
│ ├── src/
│ │ ├── main.rs # Tauri command registration + app bootstrap
│ │ └── marlin.rs # Streaming state and command handling
│ ├── Cargo.toml # Rust dependencies
│ ├── tauri.conf.json # Tauri configuration
│ └── icons/ # App icons
├── schemas/ # JSON schemas
│ └── FiberPathProject.schema.json
├── docs/ # This documentation
├── package.json # NPM scripts and dependencies
├── tsconfig.json # TypeScript config (strict mode)
├── vite.config.ts # Vite build config
└── vitest.config.ts # Test configuration
Common Tasks¶
Add New Tauri Command¶
- Define in Rust (
src-tauri/src/main.rs):
#[tauri::command]
fn my_command(arg: String) -> Result<String, String> {
Ok(format!("Hello {}", arg))
}
- Register in
main():
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![my_command])
.run(tauri::generate_context!())
- Call from Frontend (
src/lib/commands.ts):
export async function myCommand(arg: string): Promise<string> {
return invoke("my_command", { arg });
}
Add New Layer Type¶
- Define Zod schema (
src/lib/schemas.ts) - Add discriminated union case to the wind-definition schema
- Update TypeScript types (
src/types/project.ts) - Add an editor component in
src/components/editors/and wire it intoPrepareWorkspace.svelte's layer-properties switch - Add tests in
schemas.test.ts(and an editor*.svelte.test.ts)
Add UI Component¶
- Create component file in
src/components/MyComponent.svelte(orsrc/ui/for a primitive) - Declare props with
let { ... }: Props = $props() - Reuse global primitives/tokens; add a scoped
<style>block for unique chrome - Read shared state from a
src/state/*.sveltesingleton via$derived - Write tests in
MyComponent.svelte.test.ts
Debugging¶
Frontend Debugging¶
Browser DevTools (dev mode only):
- Right-click → Inspect Element
- Or press F12 in Tauri window
Inspecting reactive state:
State lives in plain runes singletons (src/state/*.svelte.ts). Import one in the
DevTools console (or log it) to inspect it — for example
projectSession.document, projectSession.isDirty, or uiState.workspace. The
Svelte DevTools extension can also inspect component state and props live.
Rust Debugging¶
Console Logging:
println!("Debug: {:?}", value);
Run with backtrace:
RUST_BACKTRACE=1 npm run tauri dev
CLI Integration Debugging¶
Test CLI directly:
fiberpath plan examples/simple_cylinder/input.wind
Check CLI version:
fiberpath --version
Verify CLI in PATH:
# Windows PowerShell
Get-Command fiberpath
# macOS/Linux
which fiberpath
Troubleshooting¶
"Command 'fiberpath' not found"¶
Solution: Install Python CLI and ensure it's in PATH:
pip install fiberpath
fiberpath --version
"Tauri build failed on Linux"¶
Solution: Install WebKit dependencies:
sudo apt install libwebkit2gtk-4.1-dev libappindicator3-dev
Tests fail with "Cannot find module"¶
Solution: Rebuild dependencies:
rm -rf node_modules package-lock.json
npm install
HMR not working¶
Solution: Restart dev server:
# Ctrl+C to stop
npm run tauri dev
Streaming connection timeout¶
Solution: Check serial port permissions:
- Linux: Add user to dialout group:
sudo usermod -a -G dialout $USER(logout required) - macOS: Grant permissions in System Settings → Security
- Windows: Usually no action needed
Performance Profiling¶
See Performance Guide for detailed profiling instructions using the browser Performance panel.