Skip to content

Contributing

We welcome contributions of all kinds — bug fixes, new shape libraries, documentation improvements, and feature work.

Quick Start

  1. Fork the repository on GitHub
  2. Clone your fork and set up the dev environment (see Project Setup)
  3. Create a feature branch: git checkout -b my-feature
  4. Make your changes
  5. Run checks: task check (or bun run typecheck && bun run test --run)
  6. Commit and push
  7. Open a pull request against master

Code Style

DocuShark follows these conventions — CI will catch violations, but knowing them upfront saves time:

TypeScript

RuleRationale
No any typesUse unknown with type guards instead
Immutable updatesAll state mutations go through Immer
Pure functionsShape handlers and math utilities should have no side effects
Small, focused filesOne clear responsibility per file
Explicit over cleverVerbose, 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:

  1. Create a new file under /src/shapes/library/ (e.g., myShapes.ts)
  2. Define shapes using LibraryShapeDefinition with a pathBuilder function that returns a Path2D
  3. Add ShapeMetadata (name, category, icon, property definitions) for the PropertyPanel
  4. Define anchor points for connectors
  5. Export as an array and add a lazy loader in shapeLibraryStore.ts
  6. 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:

bash
cd docs-site
bun install
bun run dev

Testing Requirements

All pull requests must pass:

  1. TypeScript type checkingbun run typecheck
  2. All existing testsbun run test --run
  3. Rust compilationcargo check --manifest-path src-tauri/Cargo.toml

Writing Tests

  • Test files go alongside their source file with .test.ts suffix
  • 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
typescript
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 module

TIP

Found a bug or have a feature request? Open an issue on GitHub — even if you're not planning to fix it yourself.

Released under the AGPL-3.0 License.