A relational DSL for authoring and rendering SVG floorplans.
Project description
porta
porta is two things:
- A DSL for concisely defining a relational floorplan; and
- A software package for deterministically converting a floorplan into a clean SVG map.
room hall "Great Hall" 40x20 root
room parlour "Parlour" 20x20 left-of hall
room kitchen "Kitchen" 20x20 right-of hall
room study "Study" ?x20 down-of parlour
The porta DSL
porta floorplans are defined in .porta files adhering to a strict specification.
Each room is defined in a single line relative to one or more anchor rooms,
forming a dependency graph all the way back to the initial root room. This model
creates a 1-to-1 correspondence between the floorplan and the final SVG map it
produces, allowing porta to rapidly and deterministically generate one from
the other.
Files are read line by line: a # starts a comment that runs to the end of the
line (a # inside a quoted name is literal), and blank lines are ignored.
For more on the porta DSL specification, see the following documentation:
- Rooms — the
roomstatement, room positioning, auto-dimensions (?), and the layout resolution procedure. - Doors — default doors & how to modify them, and
the
doorstatement for explicitly adding non-default doors.
The porta tool
Once a valid floorplan has been written, porta draw converts it into an
SVG map in a two-step process. First, the dependency graph is traversed
and the relations in the floorplan are converted into a coordinate system.
Second, that coordinate system is used to deterministically generate an
SVG file.
porta draw plan.porta -o plan.svg
The solved coordinate system can also be viewed and debugged directly as an ASCII grid:
porta draw plan.porta --debug-ascii
A plan that can't be solved (due to overlaps, missing anchors, gaps between a room and its anchor, etc) will fail and raise an error.
Installation
porta is published on PyPI and can be installed with pip:
pip install porta
Alternatively, install it from a checkout of this repo. Add the [dev] extra
to pull in the test and lint tools as well:
pip install -e . # editable install
pip install -e ".[dev]" # ... plus pytest, ruff, and mypy
Why porta?
porta is built to be:
- Text-based — a plan is plain text: editable in any editor, diffable, and version-controlled alongside your campaign notes. No WYSIWYG, no binary files.
- Concise — a terse syntax with strong defaults; a whole plan is a handful of short lines.
- Deterministic — no procedural generation and no randomness; the same plan always renders the same map.
- Relational — rooms are placed against other rooms, never drawn by hand or given raw coordinates.
- Spatial — the output is a flush, to-scale floor plan in tabletop conventions, not a flowchart or connectivity graph.
- Fast — placement is a single pass over a dependency graph, with no constraint solver to run.
- AI-friendly — terse, text-only, and predictable, so a language model can read and write plans reliably (this one falls out of the rest).
No existing tool hits all of these:
- Procedural and AI generators (Watabou, Inkarnate) aren't deterministic or controllable — they invent a layout instead of rendering yours.
- GUI map editors (Dungeondraft, Dungeon Scrawl) aren't text: mouse-driven, binary, and kept apart from your notes.
- Diagram tools (Mermaid, Graphviz, D2) give connectivity, not a spatial, to-scale map.
- Hand-written SVG is text, but neither concise nor relational — verbose and easy to get wrong.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file porta-1.0.0.tar.gz.
File metadata
- Download URL: porta-1.0.0.tar.gz
- Upload date:
- Size: 56.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ea60a3abb2f74d3cd9a159ebd8d5e87ef4e585a05f015b19e02f58a110b12ed
|
|
| MD5 |
937a73839af255958c712a24083f6dcc
|
|
| BLAKE2b-256 |
ddcde46229a0c9060ab70e14144a47baa7fb0c58a85d14541adee66fbd8d9483
|
File details
Details for the file porta-1.0.0-py3-none-any.whl.
File metadata
- Download URL: porta-1.0.0-py3-none-any.whl
- Upload date:
- Size: 23.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5155a57a5e6b528864c9d31ea6551dcea32ecc68d28f02660579857b7623ece
|
|
| MD5 |
b33e1eaf52c48ade8f572fd12d46e7d1
|
|
| BLAKE2b-256 |
d6d8e23011218f58683b7e8184e00e0f75640891ab10420c34fa98ea00867b79
|