Skip to content

Contributing

Local setup, the test layers, and how to get a change merged.

Thanks for considering a contribution. This is a small, local-first project — the goal is to keep it approachable for both users and contributors.

Before you start

  • For anything bigger than a small fix (a new feature, a new engine adapter, a schema change), open an issue first to discuss the approach. It's a much shorter round trip than writing the code first and finding out it doesn't fit.
  • Read ARCHITECTURE.md for how the pieces fit together, especially the engine adapter pattern if you're adding a new generation backend.
  • Read CODE_OF_CONDUCT.md. We keep this simple: be respectful, assume good faith, and remember there's a person on the other end of every issue and PR.

Development setup

git clone https://github.com/vishwakulkarni/PoseForge.git
cd PoseForge
npm run setup
npm run dev

The setup command preserves an existing .env, installs locked API and web dependencies, initializes embedded PGlite, applies migrations, and verifies the bundled starter poses. Re-run it after pulling dependency or migration changes.

Open http://localhost:3000. Pages, /api, and /storage are served by the same process and origin.

Running tests

npm run test:all    # API tests, then web unit and component tests
npm test            # API only
npm run test:web    # web only
npm run test:e2e    # Playwright starts the complete app
LayerToolLocation
API unitsnode:testtests/*.test.js
UI units, hooks, reducersVitestweb/tests/*.test.ts
Components with a mocked APIVitest + Testing Library + MSWweb/tests/*.test.tsx
End-to-endPlaywrightweb/e2e/*.spec.ts

The API tests use Node's built-in runner — no extra framework dependency. Database tests use an isolated PGlite database by default. CI also runs them against PostgreSQL to keep the optional server mode compatible.

Playwright starts the complete development server itself. The CI workflow and the default local command cover both desktop and mobile viewports.

Before opening a PR, run the same quality gates CI uses:

npm run check                       # API syntax
npm test                            # API tests
npm --prefix web run typecheck
npm --prefix web run lint
npm --prefix web test
npm run docs:check
npm run build:web
npm run test:e2e

Working on the UI

  • Reach for web/components/ui/ before writing a new dialog, select, or toggle — those wrap Radix and already handle focus and ARIA.
  • Colours, radii and shadows come from the --pf-* tokens in web/app/globals.css. Don't hardcode hex values.
  • All network access goes through web/lib/api/client.ts. If you're calling fetch directly in a component, something has gone sideways.
  • Studio's interaction rules live in web/lib/studio/reducer.ts and are unit tested. Change behaviour there, not in the components.

Adding a new generation engine

This is the most common kind of contribution. Every engine lives in engines/ and implements the same small interface — see engines/engineInterface.md and any existing adapter (engines/openaiEngine.js is a good reference for a cloud API-based engine) as a template:

{
  key: "your-engine",
  label: "Your Engine",
  async isReady() { /* return { ready, reason? } */ },
  async generate({
    characterPhotoPaths,
    posePhotoPath,
    prompt,
    outputPath,
    outputSettings,
    apiKey,
    model,
  }) {
    /* write a PNG to outputPath, or throw */
  },
}

characterPhotoPaths contains one to four subjects in prompt order. outputSettings and model may be omitted by the caller, so adapters must provide safe defaults. See engines/engineInterface.md for the full contract.

Updating documentation

The repository Markdown files are the source of truth. scripts/sync-docs.js copies the contributor and user documentation into the in-app Docs site:

npm run docs:sync   # regenerate web/content/docs/*.mdx
npm run docs:check  # verify that committed copies are current

Commit the source Markdown and its generated MDX copy in the same change.

Register it in engines/index.js, and it will automatically show up in the Studio's engine dropdown and the Settings screen.

Commit style

We use Conventional Commits (feat:, fix:, docs:, refactor:, test:, chore:) — this keeps the changelog easy to generate and PR history easy to scan. Not strictly enforced by CI yet, but appreciated.

Pull requests

  • Keep PRs focused — one logical change per PR is much easier to review than a bundle of unrelated fixes.
  • Update CHANGELOG.md under "Unreleased" for any user-facing change.
  • CI runs the test suite and a syntax check on every PR — make sure it's green before requesting review.
  • Screenshots or a short clip are appreciated for any UI change.

Reporting bugs / requesting features

Use the issue templates — they ask for just enough detail to act on the report without a back-and-forth. Security issues should not go through public issues; see SECURITY.md.

On this page