Declarative sheet bases
BaseActorSheet and BaseItemSheet handle drag-drop wiring, tab state, and fromUuid resolution. You write domain logic, not plumbing.
A modern SDK for building FoundryVTT v13+ systems and modules. Declarative APIs, schema-to-type inference, zero lock-in.
Every FoundryVTT sheet you've written has the same structural plumbing: drag-drop handlers, _prepareContext ceremony, fromUuid lookups, tab state machines. VTTForge turns it into one declarative class.
class CharacterSheet extends ActorSheetV2 { // 36 lines of identical drag-drop wiring #createDragDropHandlers() { return this.options.dragDrop.map(d => { d.callbacks = { dragstart: this._onDragStart.bind(this), drop: this._onDrop.bind(this), }; return new DragDrop(d); }); } async _prepareContext(options) { const context = await super._prepareContext(options); context.tabs = { primary: this._prepareTabs("primary"), /* every group, every sheet… */ }; return context; } async _onDropItem(event, data) { const item = await fromUuid(data.uuid); if (!item) return; // type-switching, validation, transfer… } }
import { BaseActorSheet } from "@vttforge/core"; class CharacterSheet extends BaseActorSheet() { static PARTS = { main: { template: "systems/demo/sheet.hbs" }, }; static TABS = { primary: { tabs: ["abilities", "inventory", "bio"] }, }; static DRAG_DROP = [{ dragSelector: ".item" }]; // fromUuid already resolved, just handle your domain. async onDropItem(item, event) { await this.actor.createEmbeddedDocuments("Item", [item.toObject()]); } }
Every API is validated against a production FoundryVTT system before it ships. Where Foundry already does something well, we don't reinvent it.
BaseActorSheet and BaseItemSheet handle drag-drop wiring, tab state, and fromUuid resolution. You write domain logic, not plumbing.
One defineSchema() drives both runtime validation and your TypeScript types via InferSchema<T>. Stop double-typing your data models.
@vttforge/styles nests under Foundry's system layer with a vendored prefix, no specificity wars, no !important. Inherits Theme V2 for free.
createMigrationRunner() ships idempotent, versioned data migrations with a clean rollback story, runs once at world load, logs to chat.
The Vite plugin watches .hbs templates and hot-swaps them in a running Foundry world. Tweak markup without reloading a world.
Every runtime error carries a VTTF-NNNN code from an append-only registry. Codes are stable across majors, log scrapers and IDE tooltips resolve forever.
Cherry-pick what you need. @vttforge/core is enough for a system; the rest layer on top.
| package | what it does | status |
|---|---|---|
| @vttforge/core | Runtime: BaseActorSheet, BaseItemSheet, SystemConfig, registerSystem, fields(), InferSchema, createMigrationRunner, VttfError | v0.1 in progress |
| @vttforge/styles | Design tokens, sheet primitives, drag-drop affordances, opt-in themes via CSS cascade layers | v0.1 in progress |
| @vttforge/vite-plugin | Vite plugin: HMR for .hbs, CSS pipeline (PostCSS), manifest sync | v0.2 planned |
| @vttforge/cli | vttforge init / dev / build, scaffold systems and modules in TS or JS | v0.3 planned |
| @vttforge/testing | Quench helpers for system and module tests | v1.0 planned |
| @vttforge/types | Shared TypeScript types, full class-level inference, Drizzle-style $inferData | v1.0 planned |
The repo ships a real Foundry v13 system you can boot in Docker, tabbed character sheet, drag-drop inventory, demo migration. Requires Docker + a foundryvtt.com license.
Clone the repo, fill in your Foundry license, run one compose command. The bundled examples/simple-system mounts read-only at localhost:30000.
# clone & install git clone https://github.com/vttforge/vttforge cd vttforge corepack enable && pnpm install pnpm build # fill in your foundryvtt.com license cp .env.example .env # boot Foundry v13 with the example system mounted docker compose -f docker-compose.dev.yml up # http://localhost:30000
Once @vttforge/cli ships in v0.3, scaffolding a new system or module takes one command. Dev server with HMR for Handlebars templates is in the v0.2 plugin.
# scaffold a system, or a module npx @vttforge/cli init my-system \ --type system --lang ts npx @vttforge/cli init my-module \ --type module --lang ts cd my-system # dev server with HMR for .hbs vttforge dev \ --foundry-data ~/Library/Application\ Support/FoundryVTT/Data # production build vttforge build
Every package is on npm. Scaffold one, file an issue with the boilerplate you keep writing by hand, or open the design system to see what ships with it.