Contributing
Code Style
Rust
- Formatter:
rustfmt(default settings). Run withcargo fmtbefore committing. - Linter:
clippy. Run withcargo clippy -- -D warningsto catch common mistakes. - Naming:
snake_casefor functions, variables, and modules.PascalCasefor types and traits.
TypeScript
- Formatter: Prettier (configured in the project).
- Linter: ESLint (configured in the project). Run with
pnpm lint. - Naming:
camelCasefor variables, functions, and properties.PascalCasefor components, types, and interfaces.
Frontend Patterns
Components
All components are functional components using React hooks. No class components.
// Good
export function ViewerToolbar({ sceneId }: ViewerToolbarProps) {
const [active, setActive] = useState(false)
// ...
}
// Avoid
export class ViewerToolbar extends React.Component { ... }
State Management
Global state uses Zustand stores. Each domain has its own store:
import { create } from 'zustand'
interface ProjectStore {
projects: Project[]
loadProjects: () => Promise<void>
}
export const useProjectStore = create<ProjectStore>((set) => ({
projects: [],
loadProjects: async () => {
const data = await invoke('list_projects')
set({ projects: data })
},
}))
Tauri IPC Calls
Use the @tauri-apps/api invoke function to call Rust commands:
import { invoke } from '@tauri-apps/api/core'
const project = await invoke<ProjectResponse>('get_project', {
projectId: 'abc123',
})
Git Workflow
Branches
master-- Main branch. Always deployable.- Feature branches --
feat/<short-description> - Bug fix branches --
fix/<short-description>
Commit Messages
Follow Conventional Commits:
feat: add wall alignment overlay toggle
fix: correct scale mpp when VLM returns implausible value
refactor: extract wall mask logic into separate module
docs: add pipeline testing guide
chore: update Tauri to 2.5.3
Types: feat, fix, refactor, docs, chore, test, perf.
Pull Request Checklist
Before submitting a PR, verify:
- Rust builds without warnings:
cargo clippy -- -D warnings - Rust formatted:
cargo fmt --check - TypeScript builds:
pnpm build - Lint passes:
pnpm lint - Pipeline tests pass:
cargo test --lib test_pipeline_e2e - No new
console.logleft in production code - Types are correct -- no
anytypes without justification - Commit messages follow conventional commits format
Adding a New Tauri Command
- Create the command function in the appropriate file under
src-tauri/src/commands/.
#[tauri::command]
pub fn my_new_command(
state: State<'_, AppState>,
param: String,
) -> Result<MyResponse, String> {
// ...
}
- Register it in
src-tauri/src/lib.rs:
.invoke_handler(tauri::generate_handler![
// ... existing commands
commands::my_module::my_new_command,
])
- Define the TypeScript types in
src/types/and call it from the frontend:
const result = await invoke<MyResponse>('my_new_command', { param: 'value' })
Adding a New Pipeline Step
- Create a new module file in
src-tauri/src/pipeline/. - Export the module in
src-tauri/src/pipeline/mod.rs. - Integrate it into the pipeline flow in
run_pipeline()or the relevant orchestrator. - Add an E2E test assertion in
test_e2e.rsif the step produces measurable output.