Contributing
We welcome contributions of all kinds — bug fixes, new shape libraries, documentation improvements, and feature work.
Quick Start
- Fork the repository on GitHub
- Clone your fork and set up the dev environment (see Project Setup)
- Create a feature branch:
git checkout -b my-feature - Make your changes
- Run checks:
task check(orbun run typecheck && bun run test --run) - Commit and push
- Open a pull request against
master
Code Style
DocuShark follows these conventions — CI will catch violations, but knowing them upfront saves time:
TypeScript
| Rule | Rationale |
|---|---|
No any types | Use unknown with type guards instead |
| Immutable updates | All state mutations go through Immer |
| Pure functions | Shape handlers and math utilities should have no side effects |
| Small, focused files | One clear responsibility per file |
| Explicit over clever | Verbose, readable code beats clever one-liners |
Rust
Both Rust crates — the Tauri desktop backend (src-tauri/) and the standalone relay/ — follow standard Rust conventions; cargo fmt and cargo clippy should pass cleanly. If you touch the relay, run its own cargo check/cargo test from relay/ (see Project Setup).
Comments
Only comment code that needs clarification. Don't comment the obvious. Good function and variable names should make intent clear.
What to Work On
Good First Issues
Look for issues labeled good first issue on GitHub.
Shape Libraries
Adding new shape libraries is one of the easiest ways to contribute. Library shapes use a declarative approach — you define geometry with a PathBuilder function, and the framework generates all handler methods automatically:
- Create a new file under
/src/shapes/library/(e.g.,myShapes.ts) - Define shapes using
LibraryShapeDefinitionwith apathBuilderfunction that returns aPath2D - Add
ShapeMetadata(name, category, icon, property definitions) for the PropertyPanel - Define anchor points for connectors
- Export as an array and add a lazy loader in
shapeLibraryStore.ts - Add tests for hit testing, bounds, and anchors
See the Creating Shapes guide for a complete walkthrough with examples.
Documentation
Documentation lives in /docs-site/. It uses VitePress. Run the docs locally:
cd docs-site
bun install
bun run devTesting Requirements
All pull requests must pass:
- TypeScript type checking —
bun run typecheck - All existing tests —
bun run test --run - Rust compilation —
cargo check --manifest-path src-tauri/Cargo.toml
Writing Tests
- Test files go alongside their source file with
.test.tssuffix - Use Vitest globals (
describe,it,expect) — no imports needed - Always test math — geometry, coordinate, and transform functions require thorough unit tests
- Test stores by verifying state transitions, not internal implementation
describe('MyFeature', () => {
it('should do the expected thing', () => {
const result = myFunction(input);
expect(result).toBe(expected);
});
});Architecture Decisions
Before making significant architectural changes, please open an issue to discuss. Key constraints to keep in mind:
- Canvas rendering is not React — don't introduce React into the render loop
- Shapes are data, not classes — the ShapeRegistry pattern is intentional
- DocumentStore is the single source of truth — don't cache shape data elsewhere
- Camera owns all coordinate math — never manually apply pan/zoom
See How the Engine Fits Together for deeper context.
Commit Messages
Use conventional-ish commit messages:
feat: add swimlane shape to UML library
fix: connector routing ignores rotated shapes
docs: update collaboration setup guide
test: add tests for SpatialIndex edge cases
refactor: extract connector routing into separate moduleTIP
Found a bug or have a feature request? Open an issue on GitHub — even if you're not planning to fix it yourself.
