{"id":"4bbfe88e-3254-4b80-a523-978ff2a3e5da","slug":"kalpak44-forma-dsl","kind":"mcp","name":"forma-dsl","summary":"A declarative DSL for parametric CAD and 3D modeling, with an MCP server, browser editor, and live WebGL previews. JavaScript monorepo published to npm.","owner":"kalpak44","repoUrl":"https://github.com/kalpak44/forma-dsl","license":"MIT","licenseTier":"permissive","trust":"community","stars":0,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-09-28T13:11:11.000Z","addedAt":"2026-10-14T11:07:40.220Z","logoUrl":"https://avatars.githubusercontent.com/u/6253795?u=c5a7a9c1e251c88716398907868c2a515040d4da&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["design-media","browser-web","developer-tools"],"tags":["dsl","javascript","parser","3d-modeling","computer-graphics","constructive-solid-geometry","declarative","language-design"],"runtime":"node","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-14T20:39:25.766Z","sample":false,"url":"https://conduits.dev/tools/kalpak44-forma-dsl","language":"JavaScript","transports":["stdio"],"install":{"npm":"forma-dsl-mcp"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# forma-dsl\n\n[![Release](https://github.com/kalpak44/forma-dsl/actions/workflows/release.yml/badge.svg)](https://github.com/kalpak44/forma-dsl/actions/workflows/release.yml)\n[![forma-dsl on npm](https://img.shields.io/npm/v/forma-dsl.svg?label=forma-dsl)](https://www.npmjs.com/package/forma-dsl)\n[![forma-dsl-cli on npm](https://img.shields.io/npm/v/forma-dsl-cli.svg?label=forma-dsl-cli)](https://www.npmjs.com/package/forma-dsl-cli)\n[![forma-dsl-mcp on npm](https://img.shields.io/npm/v/forma-dsl-mcp.svg?label=forma-dsl-mcp)](https://www.npmjs.com/package/forma-dsl-mcp)\n[![M8ven Verified](https://m8ven.ai/api/agent-verify/badge?score=100)](https://m8ven.ai/verified/verify?id=d3529b4756004447)\n\nA declarative DSL for 3D modeling and scene composition, reusable components, and live\npreviews. This is the monorepo: the library, the command line and the MCP server that consume\nit, the editor, and the reference manual.\n\n**[The site](https://kalpak44.github.io/forma-dsl/)** ·\n**[Try the editor](https://kalpak44.github.io/forma-dsl/editor/)** ·\n**[Read the reference](https://kalpak44.github.io/forma-dsl/docs/)**\n\n```bash\nnpx forma-dsl-cli render riser.forma -p height=32 -o riser.stl\n```\n\n![The demo typing a bracket, a flange, a component and a vase, solving each and re-solving as a slider moves](apps/docs/assets/demo.gif)\n\nThe [live demo](https://kalpak44.github.io/forma-dsl/#demo) types each document out and solves\nit as it goes, then re-solves as a parameter moves - in the browser, with the same kernel.\n\n```hcl\nparam height { type = number  default = 20  min = 8  max = 40 }\n\nmodel \"riser\" {\n  part \"body\" {\n    color = \"#6f7d8c\"\n    difference {\n      extrude {\n        height = var.height\n        rounded_rect { size = [40, 20]  radius = 4  center = true }\n      }\n      translate { offset = [0, 0, 3]  cylinder { radius = 5  height = var.height } }\n    }\n  }\n}\n```\n\n![The riser above, solved and rendered: a rounded 40 x 20 block with a 10 mm bore through the top](apps/docs/assets/example.png)\n\n## Workspaces\n\n| Package | Published | What it is |\n| --- | --- | --- |\n| [`packages/forma-dsl`](packages/forma-dsl) | [`forma-dsl`](https://www.npmjs.com/package/forma-dsl) | The language, its evaluator and the geometry kernel binding. One runtime dependency |\n| [`packages/forma-dsl-cli`](packages/forma-dsl-cli) | [`forma-dsl-cli`](https://www.npmjs.com/package/forma-dsl-cli) | The `forma` command: solve a document to STL in a build, with no browser. One runtime dependency, the library |\n| [`packages/forma-dsl-mcp`](packages/forma-dsl-mcp) | [`forma-dsl-mcp`](https://www.npmjs.com/package/forma-dsl-mcp) | An MCP server over stdio: it knows the language, solves what it writes, and produces `.forma` files |\n| [`apps/landing`](apps/landing) | no | The landing page: a live WebGL hero, a demo that types the language and solves it, and the privacy and terms sheets |\n| [`apps/editor`](apps/editor) | no | The browser editor: CodeMirror, three.js, Vite |\n| [`apps/docs`](apps/docs) | no | The reference manual, and the builder that renders it |\n\n### How the pieces are kept honest\n\nEvery workspace here **depends on the published entry point**, not on the library's sources:\nthe editor imports `forma-dsl`, never `../../packages/forma-dsl/src`. An export one of them\nneeds and the package does not have therefore fails in this repository rather than in\nsomeone's install.\n\nThe same rule governs what each workspace may *claim* about the language. None of them\nrestates the vocabulary - each reads it from the library's own registries, and a test holds\nthem to it:\n\n- **Syntax highlighting is generated, not transcribed.** The editor's\n  ([`language.js`](apps/editor/src/language.js)), the landing page's\n  ([`highlight.js`](apps/landing/src/highlight.js)) and the manual's\n  ([`build.mjs`](apps/docs/build.mjs)) all colour from `BLOCKS` and `FUNCTIONS`, so a block\n  added to the language is highlighted without anyone updating a list.\n- **Every example on the site renders.** The editor's four documents\n  ([`examples.test.js`](apps/editor/test/examples.test.js)) and the landing page's demos\n  ([`demos.test.js`](apps/landing/test/demos.test.js)) are solved by tests, so nothing shown\n  being typed is a document the library can no longer build.\n- **The MCP server's catalogue cannot drift.** It merges the registries into its own prose at\n  load time and exposes any disagreement as `catalogueDrift`, which\n  [`catalogue.test.js`](packages/forma-dsl-mcp/test/catalogue.test.js) asserts is empty. Its\n  worked examples are rendered at both ends of every parameter's range.\n- **The editor's completion offers the whole language.** It is built from `BLOCKS`,\n  `FUNCTIONS`, `CONSTANTS` and `TYPE_NAMES`, and\n  [`completion.test.js`](apps/editor/test/completion.test.js) asserts that no name in a\n  registry is missing from what the editor offers - so a block added to the language is\n  suggested without anyone updating a list.\n- **The manual has no dead cross-references.** `npm run build` resolves all 237 internal links\n  and fails rather than publishing a broken one.\n\n## Working on it\n\nNode 22.13 or newer - the floor the published packages declare.\n\n```bash\nnpm ci\nnpm run check   # lint, typecheck, tests, build, package contents: the whole gate, same as CI\n```\n\n| Command | What it does |\n| --- | --- |\n| `npm run dev` | the landing page, with hot reload |\n| `npm run dev:editor` | the editor |\n| `npm run mcp` | the MCP server, on stdio |\n| `npm run cli` | the `forma` command, from the source tree |\n| `npm test` | every workspace's tests |\n| `npm run test:coverage` | the same, against the thresholds CI enforces |\n| `npm run build` | the whole site into `dist/` |\n\n[CONTRIBUTING.md](CONTRIBUTING.md) has the house style, the stability policy and how a release\nis cut. [CHANGELOG.md](CHANGELOG.md) records what changed in each one.\n\nFound something exploitable? [SECURITY.md](SECURITY.md) says where to send it - please not a\npublic issue. [PRIVACY.md](PRIVACY.md) covers the published packages: neither makes a network\nrequest, and the MCP server writes only inside the directories your client declares.\n\n## License\n\nMIT - see [LICENSE](LICENSE).\n"}