HammerForge Design Constraints¶
Last updated: October 22, 2026
This document makes the current tradeoffs explicit so level designers and developers know what HammerForge optimizes for.
Editing Model¶
- Live editing uses lightweight DraftBrush previews for speed. Final geometry is produced at bake time.
- Cut brushes are staged as Pending Cuts until applied or baked.
- Committed cuts can be frozen for restoration or cleared for performance.
Brush Geometry¶
- Brush shapes are primitives and platonic solids, or a Custom convex solid made by a cut, a merge, the Polygon and Path tools, a vertex edit or Convert to Brushes. A brush is never an arbitrary mesh: Convert to Brushes refuses a concave or open one.
- A box, or any other primitive, is never thinner than 0.1 on a side, because it is built from its size. A Custom brush is built from its faces and keeps a thinner size. A piece a cut leaves under 0.1 is Custom for that reason.
- Subtractive operations only affect baked output, not the live DraftBrush meshes.
- Collision is generated from solid brushes only. A
func_clipbrush gives collision and no mesh, and a stair with Ramp collision bakes a slope in place of its steps' collision.
Face Materials + UVs¶
- Face materials use a projection per face: Planar X, Y or Z, Box UV, the face's own plane (Face), or Cylindrical.
- UV editing is per face and not a full unwrap workflow.
- Preview complexity is capped. When a brush has many painted faces, the preview falls back to a simplified mesh to stay responsive.
- Prototype textures (150 built-in SVGs) are pre-packaged for greyboxing. They are not user-editable or extensible -- add custom materials via the Add button for project-specific textures.
Floor Paint + Heightmaps¶
- Floor paint is grid-based and produces axis-aligned floors and walls.
- Heightmaps displace floors only. Walls remain flat.
- Heightmap blending uses four slots (A-D) with per-cell blend weights for B/C/D.
- Region streaming loads only nearby paint data; distant regions are written to their
.hfrsidecar and then unloaded. A region whose write fails stays loaded rather than losing the paint.
Import / Export Limits¶
.mapimport/export preserves basic brush shapes and point entities. Axis-aligned brushes import as boxes, and a box thinner than 0.1 on a side is widened to 0.1. Rotated or complex brushes import as CUSTOM with face vertices rather than being forced to cylinders.- Face materials still do not round-trip as Godot materials; Valve 220 can carry UV axes when FaceData is present.
- Face planes are converted between
FaceDatawinding and.mapplane winding in both directions, so exported hulls are not inside out and imported ones are not either. - Input that does not parse is refused before the level is modified.
.glbexport includes only baked geometry.- Per-project entity types overlay
res://hammerforge_entities.jsononto the pluginentities.json(same classname replaces). - A world brush whose every face is a clip texture imports as
func_clip, and afunc_clipexports with every face named clip.
Prefabs¶
- Prefabs capture brush and entity state as dictionaries — they do not store Node references or scene paths.
- Transforms are centroid-relative. The centroid is computed from all selected nodes at capture time.
- Brush IDs, group IDs, and visgroup membership are cleared on capture to avoid conflicts on instantiation.
- Entity I/O connections are remapped using a name map (old entity name → new entity name) on instantiation.
- Prefab files (
.hfprefab) use JSON withHFLevelIOencoding for Godot types (Vector3, Transform3D, etc.). - The cut preview system does not render intersections for prefab preview — only placed brushes.
Cut Preview¶
- Cut preview includes DraftBrushes (not only leftover CSGShape3D nodes) and uses each brush's mesh bounds. It is still not a live full-level CSG boolean.
- It cuts only what the bake cuts: a brush tied to an entity class is never cut, and a cutter tied to one cuts nothing (
HFBakeSystem.is_structural_brush()). - The preview is debounced (0.15s) to avoid rebuilding on every frame during rapid edits.
- Maximum 50 intersection overlays are rendered simultaneously. Beyond that, intersections are silently dropped.
- Up to 8 cuts at once get a live CSG intersection of their real shape. The rest, and any cut still waiting on its CSG result, are drawn as the wireframe of the overlap's bounds.
Performance Considerations¶
- Export templates initialize only the runtime level core: brush, entity, bake, paint, and file systems. Authoring systems such as grid, drag, snap, selection, previews, prefab editing, validation, undo, displacement, and bevel remain editor-only.
- Chunked baking splits the baked mesh so the game can cull it piece by piece. It does not make a bake shorter: chunked at the recommended size, a bake took about as long as an unchunked one (Performance and Limits).
- Very large paint layers should be split to reduce regeneration cost.