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.mdfor 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 devThe 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| Layer | Tool | Location |
|---|---|---|
| API units | node:test | tests/*.test.js |
| UI units, hooks, reducers | Vitest | web/tests/*.test.ts |
| Components with a mocked API | Vitest + Testing Library + MSW | web/tests/*.test.tsx |
| End-to-end | Playwright | web/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:e2eWorking 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 inweb/app/globals.css. Don't hardcode hex values. - All network access goes through
web/lib/api/client.ts. If you're callingfetchdirectly in a component, something has gone sideways. - Studio's interaction rules live in
web/lib/studio/reducer.tsand 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 currentCommit 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.mdunder "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.