Brush-based level editor for Godot 4.6+
Draw rooms, carve doors, paint terrain, and bake to optimized meshes — all inside the Godot editor.
Fair warning: This is a solo hobby project in early alpha. I built it to support another project and it grew from there. It's buggy, rough around the edges, and a bit directionless. If any of this looks useful to you, I'd genuinely appreciate help testing and filing issues. Contributions welcome -- just know you're signing up for an adventure, not a polished product.
The previous AI-generated logo has been retired. If you're a designer or artist and want to contribute a logo for HammerForge, I'd love to use it (with credit). Requirements: free to use under MIT, ideally SVG so it scales. Open an issue or PR if interested.
Level editors like Hammer and TrenchBroom proved that brush-based workflows are the fastest way to block out 3D spaces. HammerForge brings that paradigm into Godot so you never have to leave the editor:
- No live CSG -- brushes are lightweight preview nodes; CSG runs only at bake time, keeping the editor snappy even with hundreds of brushes.
- Two-click geometry -- drag a base rectangle, click to set height. Extrude faces to extend rooms. Type exact numbers any time.
- Paint floors and terrain -- grid-based floor paint with heightmaps, multi-material blending, auto-connectors (ramps/stairs), and foliage scatter.
- Bake when ready -- one click produces merged meshes, collision shapes, lightmap UVs, navmeshes, and LODs.
HammerForge is a single addons/ folder. No external tools, no custom builds, no export plugins. Drop it in, enable, draw.
| 19 subsystems + coordinator architecture | 1118 unit + integration tests with CI on every push |
| 15 brush shapes (box through dodecahedron) | 150 built-in prototype textures for instant greyboxing |
Quake .map + glTF .glb export |
.hflevel native format with threaded I/O |
| Customizable keymaps (JSON) | Plugin API for custom tools |
| Dark/light theme sync across all custom UI | Performance health monitor with recommendations |
Two-stage CAD drawing: drag base, click height. Brushes support Add and Subtract operations with pending cut staging, so you can preview subtractions before committing.
- 15 shapes -- box, cylinder, sphere, cone, wedge, pyramid, prisms, ellipsoid, capsule, torus, and platonic solids
- Extrude Up/Down (U / J) -- click any face and drag to extend
- Hollow (Ctrl+H) -- convert a solid brush to a room with configurable wall thickness
- Clip (Shift+X) -- split a brush along an axis-aligned plane
- Carve (Ctrl+Shift+R) -- boolean-subtract one brush from all intersecting brushes
- Numeric input -- type exact dimensions during any drag or extrude
- Resize gizmo with full undo/redo
Precision vertex-level editing for fine-tuning brush geometry:
- Vertex mode (V) -- select and move individual brush vertices with convexity enforcement
- Edge sub-mode (E) -- toggle to select, move, split, and merge edges
- Edge splitting (Ctrl+E) -- insert midpoint vertex on a selected edge
- Vertex merging (Ctrl+W) -- merge selected vertices to their centroid
- Wireframe overlay -- color-coded edge display (gray default, orange selected, yellow hovered)
- Clip to Convex -- repair non-convex brushes by recomputing the convex hull with UV inheritance
Draw arbitrary convex polygons and extrude them into brushes:
- Polygon tool (P) -- click to place vertices on the ground plane, Enter or auto-close to finish
- Convexity enforcement -- rejects concave vertex placements in real time
- Height extrusion -- drag to set height after closing the polygon
- Grid snapping -- vertices snap to the active grid
Create corridors and paths by placing waypoints:
- Path tool (;) -- click to place waypoints, Enter to finalize
- Rectangular cross-section -- configurable width and height per path
- Miter joints -- automatic gap-filling brushes at corners
- Auto-grouping -- all segment brushes share a group ID
- Auto-stairs -- step brushes along sloped segments with configurable step height
- Auto-railings -- top rails + posts on both sides with configurable height, thickness, and post spacing
- Auto-trim strips -- edge strips alongside path with material auto-assign
Geometry-aware snapping goes beyond a simple grid:
| Mode | Key | What it snaps to |
|---|---|---|
| Grid | G | Regular grid intersections |
| Vertex | V | Corners of existing brushes (8 per box) |
| Center | C | Center points of existing brushes |
Closest candidate within threshold wins. Modes combine freely. The Measure tool can set a custom snap reference line (right-click a ruler) for alignment along arbitrary axes. Texture Lock preserves UV alignment when moving or resizing. Move to Floor/Ceiling (Ctrl+Shift+F/C) raycasts to snap brushes vertically. UV Justify offers fit/center/left/right/top/bottom/stretch/tile alignment for selected faces.
Grid-based paint layers with chunked storage for large worlds:
- Tools: Brush (B), Erase (E), Rect (R), Line (L), Bucket (K), Blend
- Sculpting: Raise, Lower, Smooth, Flatten brushes for interactive terrain editing with configurable strength, radius, and falloff
- Shapes: Square, Circle with adjustable radius
- Heightmaps: import PNG/EXR or generate procedural noise -- per-vertex displacement via SurfaceTool
- Convert Selection to Heightmap: select brushes → rasterize top faces → create sculptable terrain layer
- Material blending: four-slot shader with per-cell blend weights painted directly on the grid
- Auto-connectors: ramp and stair mesh generation between layers at different heights
- Foliage & Scatter brush: circle/spline shapes, density preview via MultiMesh (Dots/Wireframe/Full), slope/height filtering, align-to-normal, commit as permanent MultiMeshInstance3D
- Region streaming: sparse chunk loading for open worlds
- Visual material browser -- thumbnail grid with search, pattern/color filters, and Prototypes/Palette/Favorites views
- 150 built-in prototype textures (15 patterns x 10 colors) -- click Refresh Prototypes for instant greyboxing with visual browsing
- Texture Picker (T key) -- eyedropper tool samples material from any face
- Hover preview -- hovering a thumbnail temporarily previews it on selected faces
- Right-click context menu -- Apply to Faces, Apply to Whole Brush, Toggle Favorite, Copy Name
- Face select mode for painting materials onto individual brush faces
- Surface paint with per-face splat layers, weight images, and live preview
- UV editor with per-vertex drag handles and reset-to-projection
- Material library persistence -- save/load palettes as JSON with usage tracking
- Data-driven entity types from
entities.json(point entities, brush entities like func_detail, func_wall, trigger volumes) - Source-style I/O connections -- wire output events to target inputs with parameter, delay, and fire-once options
- Smart auto-routed connection lines -- quadratic Bezier curves with arrowheads, parallel route offset, color-coded by output type (cyan=OnTrigger, red=OnDamage, yellow=OnUse, etc.) and dimmed by delay
- I/O wiring panel -- quick-wire form (output/target/input/param/delay/once), connection summary, and preset picker embedded in the Entities tab
- Connection presets -- 6 built-in patterns (Door+Light+Sound, Button→Toggle, Alarm Sequence, etc.) plus user-saved presets with target tag mapping
- Highlight Connected -- toggle to pulse-highlight all entities linked to the selected one, with summary counts in the context toolbar
- Declarative property forms -- dock auto-generates typed controls (string, int, float, bool, enum, color, vector3) from entity definitions
- Drag-and-drop placement from the entity palette
- Color-coded overlays -- cyan for func_detail, orange for triggers
- Visgroups -- named visibility groups ("walls", "detail", "lighting") with per-group show/hide
- Grouping (Ctrl+G / Ctrl+U) -- persistent groups that select and move together
- Cordon -- restrict bake to an AABB region with yellow wireframe; skip everything outside
- Reference cleanup -- deleting brushes auto-cleans group/visgroup membership and warns about dangling entity I/O connections
- Duplicator -- create N copies of a brush with progressive offset
- Prefabs -- save brush + entity groups as
.hfprefabfiles with variants, tags, and live-linked propagation. Drag from library to instantiate with new IDs and remapped I/O - Measurement (M key) -- persistent multi-ruler with angle display, Shift+Click chaining, and snap reference alignment
- Decal placement (N key) -- raycast decals onto brush surfaces with live preview
- Real-time subtract preview -- toggle wireframe AABB intersection overlays between additive and subtractive brushes
| Option | What it does |
|---|---|
| Bake | CSG assembly to merged meshes + trimesh collision |
| Chunked bake | Split output by spatial chunks |
| Cordon bake | Restrict to AABB region |
| Face materials | Bake per-face materials without CSG |
| Heightmap floors | Bypass CSG, bake displaced meshes directly with collision |
| LODs | Auto-generate level-of-detail meshes |
| Lightmap UV2 | Unwrap for lightmap baking |
| Navmesh | Bake navigation mesh |
| Dry run | Preview bake counts without building |
| Bake Selected | Bake only selected brushes (merged into existing output) |
| Bake Changed | Bake only dirty-tagged brushes since last successful bake |
| Preview modes | Full / Wireframe / Proxy toggle for ultra-fast iteration |
| MultiMesh | Consolidate repeated identical meshes into MultiMeshInstance3D |
| Bake Visible Only | Skip hidden visgroups and invisible brushes |
| Unwrap UV0 | Per-vertex planar UV projection for surfaces without UVs |
| Check Issues | Flag degenerate, floating, overlapping, non-manifold, and open-edge brushes |
| Bake estimate | Time estimate with "Chunking recommended" tip for large levels |
| Validate | Check level integrity before bake |
| .map export | Classic Quake or Valve 220 format |
| .glb export | glTF binary for external tools |
| Quick Play | Bake + validate spawn + run with FPS controller |
| Play from Camera | Quick Play from the editor camera position and yaw |
| Play Selected Area | Auto-cordon to selection, bake + play that region only |
| Export Playtest | Bake + pack scene + launch as standalone playable scene |
HammerForge's dock is designed to stay out of your way while keeping everything reachable:
- 4-tab dock (Brush, Paint, Entities, Manage) with collapsible sections -- persisted state, separators, indented content
- Dark/light theme sync -- all custom panels adapt to Godot's theme setting automatically
- Mode indicator banner -- color-coded strip shows current tool, gesture stage ("Step 1/2: Draw base -- 64 x 32"), and numeric input buffer
- Toast notifications -- transient messages for save/load/bake/error results
- Interactive tutorial wizard -- 5-step guided walkthrough (Draw → Subtract → Paint → Entity → Bake) with signal-driven auto-advance, progress bar, and persistent resume across sessions
- Dynamic contextual hints -- viewport overlay hints that appear when switching tools (e.g. "Click to place corner → drag to set size → release for height"), auto-dismiss after 4s with per-hint persistence
- Searchable shortcut dialog -- "?" button opens a filterable, categorized shortcut reference (replaces static popup)
- Smart contextual toolbar -- floating mini-toolbar in the 3D viewport shows context-sensitive actions (brush ops when brushes selected, UV tools when faces selected, shape picker in draw mode, axis locks while dragging)
- Command palette (Shift+? or F1 or Ctrl+K) -- searchable action palette with fuzzy search, "Did you mean" suggestions, and live gray-out for unavailable actions
- Coach marks -- first-use step-by-step guides for advanced tools (Polygon, Path, Carve, Vertex, Extrude, etc.) with "Don't show again" persistence
- Undo history browser -- thumbnail-equipped history panel (Manage tab) with double-click navigation to any undo point
- Operation replay timeline (Ctrl+Shift+T) -- visual timeline of recent operations with undo/redo replay to any recorded point
- Example library -- 5 built-in demo levels (Manage tab) with difficulty ratings, annotations, and one-click loading for learning
- Auto-mode hints -- "Drawing in Add mode" bar appears during drag with one-click Add/Subtract toggle
- Tool poll system -- buttons gray out with inline hints when an action can't run ("Select a brush to use these tools")
- Marquee selection -- drag-to-select brushes, entities, and faces with selection filter popover (by normal, material, similar, visgroup, type)
- Performance monitor -- health summary, brush/entity/vertex counts, chunk recommendations, color-coded ProgressBar
- Contextual selection tools -- hollow, clip, move, tie, duplicator appear in Brush tab only when brushes are selected
- Live dimensions -- real-time W x H x D display during drag gestures
- Operation feedback -- actionable error toasts with fix hints ("Wall thickness 6 is too large -- Use a thickness less than 5")
- Instant sync -- paint, material, and surface paint changes reflected immediately via signals (no polling)
- Customizable keymaps -- rebind any shortcut via JSON; toolbar labels auto-update
- User preferences -- grid defaults, recent files, UI state persist across sessions
HammerForge uses a coordinator + subsystems pattern:
plugin.gd EditorPlugin — input routing, toolbar, viewport overlay
└─ level_root.gd Thin coordinator — owns containers, exports, signals
├─ HFBrushSystem Brush CRUD, hollow, clip, tie, move, UV justify, caching
├─ HFDragSystem Two-stage draw lifecycle + preview management
├─ HFExtrudeTool Face extrusion (Up/Down) via FaceSelector
├─ HFPaintSystem Floor paint layers, heightmaps, blend, surface paint
├─ HFBakeSystem CSG assembly, mesh merge, LOD, navmesh, collision, incremental/selection bake, preview modes
├─ HFEntitySystem Entity CRUD, I/O connections, definition loading
├─ HFStateSystem Undo/redo snapshots, transactions, autosave
├─ HFFileSystem Threaded .hflevel / .map / .glb I/O
├─ HFValidationSystem Level integrity checks, bake issue detection
├─ HFGridSystem Grid rendering and follow mode
├─ HFVisgroupSystem Named visibility groups + brush grouping
├─ HFCarveSystem Boolean-subtract carve (progressive-remainder slicing)
├─ HFIOVisualizer Entity I/O connection lines in viewport (curved, color-coded, highlight pulse)
├─ HFIOPresets Reusable I/O connection presets (built-in + user-saved)
├─ HFSnapSystem Grid / Vertex / Center snap + custom reference lines
├─ HFSubtractPreview Wireframe AABB intersection overlay for subtract brushes
├─ HFVertexSystem Vertex/edge selection, move, split, merge with convexity validation
├─ HFSpawnSystem Player spawn lookup, validation, auto-fix, debug visualisation
├─ HFPrefabSystem Instance registry, variant cycling, live-linked propagation
└─ HFToolRegistry External tool loading and dispatch
├─ HFMeasureTool Multi-ruler measurement + snap reference (tool_id=100)
├─ HFDecalTool Decal placement with live preview (tool_id=101)
├─ HFPolygonTool Convex polygon → extruded brush (tool_id=102)
└─ HFPathTool Waypoint path → corridor brushes (tool_id=103)
Key design choices:
- No live CSG -- brushes are Node3D with box metadata; CSG runs only during bake
- RefCounted subsystems -- each receives a LevelRoot reference; no circular preloads
- Signal-driven UI -- signals on LevelRoot replace polling; batched emission prevents UI thrash
- Tag-based invalidation -- dirty tags on brushes/paint for selective reconciliation
- Command collation -- rapid operations merge into single undo entries within a 1-second window
- Transactions -- atomic multi-step operations (hollow, clip) with rollback on failure
- HFOpResult -- failable operations return structured results with actionable fix hints
- HFGesture -- base class for self-contained input tool gestures
- Explicit state machine --
HFInputStatemanages IDLE / DRAG_BASE / DRAG_HEIGHT / SURFACE_PAINT / EXTRUDE / VERTEX_EDIT modes - Type-safe calls -- no duck-typing between modules (dynamic dispatch only in undo/redo by design)
1. Copy addons/hammerforge into your project
2. Enable the plugin: Project -> Project Settings -> Plugins -> HammerForge
3. Open a 3D scene and click in the viewport to auto-create LevelRoot
4. Verify: dock appears with 4 tabs (Brush, Paint, Entities, Manage), toolbar shows D/S/+/-/P/▲/▼, snap buttons show G/V/C
See Install + Upgrade for upgrade steps and cache reset.
| Step | Action |
|---|---|
| 1. Draw | Tool = Draw, Mode = Add, Shape = Box -> drag base -> click height |
| 2. Extrude | Press U (Extrude Up) -> click a face -> drag -> release |
| 3. Subtract | Mode = Subtract -> draw a brush through a wall -> Apply Cuts -> Bake |
| 4. Material | Paint tab -> Materials -> Refresh Prototypes -> browse thumbnails -> Face Select Mode -> click faces -> Assign |
| 5. Paint floor | Paint Mode -> Brush tool (B) -> paint grid cells -> switch layers for different heights |
| 6. Bake | Manage tab -> Bake -> click Bake (or Quick Play to bake + run) |
Shortcuts marked with * are rebindable via user://hammerforge_keymap.json. Tool-specific keys (M, N, P, ;, A, Ctrl+Shift+P) are defined by their respective tools and not yet keymap-backed.
| Key | Action | Key | Action | |
|---|---|---|---|---|
| D * | Draw tool | B * | Brush (paint) | |
| S * | Select tool | E * | Erase (paint) | |
| U * | Extrude Up | R * | Rect (paint) | |
| J * | Extrude Down | L * | Line (paint) | |
| Ctrl+H * | Hollow | K * | Bucket (paint) | |
| Shift+X * | Clip | Ctrl+G * | Group selection | |
| Ctrl+Shift+R * | Carve | Ctrl+U * | Ungroup | |
| Ctrl+Shift+F * | Move to Floor | M | Measure tool (multi-ruler) | |
| Ctrl+Shift+C * | Move to Ceiling | N | Decal tool | |
| V * | Vertex mode | P | Polygon tool | |
| E * | Edge sub-mode (in vertex) | ; | Path tool | |
| Ctrl+E * | Split edge | Ctrl+W * | Merge vertices | |
| T * | Texture Picker | ? | Shortcuts popup | |
| Shift+? / F1 / Ctrl+K | Command palette | Ctrl+Shift+T | Operation timeline | |
| Shift+S * | Select Similar | Shift+T * | Apply Last Texture | |
| Shift+F * | Selection Filters | Ctrl+Shift+P | Quick group-to-prefab | |
| X / Y / Z * | Axis lock | A | Align mode (measure) |
1091 tests across 62 files using the GUT framework, including unit tests and end-to-end integration tests. All checks run on every push via GitHub Actions.
# Run all tests headless
godot --headless -s res://addons/gut/gut_cmdln.gd --path .
# Reset prefs for the editor smoke checklist
godot --headless -s res://tools/prepare_editor_smoke.gd --path .
# If class_names aren't imported
godot --headless --import --path .
# Format + lint
gdformat --check addons/hammerforge/
gdlint addons/hammerforge/| Document | Description |
|---|---|
| User Guide | Complete usage documentation |
| MVP Guide | Architecture and contributor reference |
| Install + Upgrade | Setup, upgrade, and cache reset |
| Design Constraints | Explicit tradeoffs and limits |
| Data Portability | .hflevel / .map / .glb workflow |
| Texture + Materials | Face materials, UVs, and surface paint |
| Prototype Textures | Built-in 150 SVG textures |
| Floor Paint Design | Grid paint system design |
| Editor Smoke Checklist | Repeatable live-editor verification flow |
| Development + Testing | Local setup, architecture, test checklist |
| Spec | Technical specification |
| Changelog | Version history |
| Roadmap | Planned features and priorities |
| Contributing | How to contribute |
| Demo Clips | Clip list and naming scheme |
| Sample Levels | Minimal and stress test scenes |
See ROADMAP.md for the full plan.
Recently shipped:
- Quality-of-Life & Polish (theme sync, undo history browser, multi-ruler measure tool, performance monitor, export playtest)
- Terrain & Organic Enhancements (brush-to-heightmap, foliage scatter, path tool extras)
- Learning & Discovery Aids (coach marks, operation replay timeline, fuzzy command palette, example library)
- I/O Connections & Entity Polish (curved auto-routed lines, connection presets, wiring panel, Highlight Connected)
- Bake & Quick Play optimizations (Bake Selected, Bake Changed, preview modes, Play from Camera, Play Selected Area)
- Prefab & Group Enhancements (variants, live-linked, tags/search, quick group-to-prefab)
- Improved selection & multi-select (marquee, selection filters, Select Similar, Apply Last Texture)
- Smart contextual toolbar + command palette with fuzzy search
Next up:
- Displacement sewing (stitch adjacent heightmap edges)
- Material atlasing for large scenes
- Merge tool (combine two adjacent brushes)
Later:
- Bezier patch editing
- Snap-to-edge and snap-to-perpendicular modes
- Multiple simultaneous cordons
- Preference packs for one-click workflow presets
This is a one-person project and there's more here than one person can properly test. If you try HammerForge and something breaks, please open an issue -- even a one-liner like "Hollow crashed on a cylinder" is helpful. Specific areas where help would make a real difference:
- Bug reports -- the test suite covers a lot, but editor-context bugs are hard to catch headless
- Playtesting -- try the workflows (draw, bake, quick play) and report what feels broken or confusing
- Edge cases -- large levels, unusual brush shapes, rapid undo/redo, plugin reload cycles
- Documentation -- if something in the user guide doesn't match reality, flag it
See CONTRIBUTING.md for how to get started.
Plugin not loading or dock missing
- Close Godot
- Delete
.godot/editor(and optionally.godot/imported) - Reopen and re-enable the plugin
Capture exit-time errors (PowerShell)
Start-Process -FilePath "C:\Godot\Godot_v4.6-stable_win64.exe" `
-ArgumentList '--editor','--path','C:\hammerforge' `
-RedirectStandardOutput "C:\Godot\godot_stdout.log" `
-RedirectStandardError "C:\Godot\godot_stderr.log" `
-NoNewWindow"class_names not imported" when running tests
Run godot --headless --import --path . first, then re-run the test command.
MIT License
Built for Godot 4.6+ | Last updated April 5, 2026