Last updated: April 9, 2026
This document describes how to move data in and out of HammerForge safely.
.hflevelfiles are the canonical save format for brushes, paint layers, materials, entities, and settings.- When region streaming is enabled, per-region paint data is stored in a sibling
<level>.hfregions/folder. - Files include a version field and default missing keys on load for backward compatibility.
- Per-face UV data includes
uv_format_version(current: 1). Legacy data (version 0, pre-April 2026) used a different UV transform order (scale+offset before rotation). On load, legacy faces are auto-migrated: uniform-scale faces get their offset adjusted; non-uniform-scale faces with rotation are baked tocustom_uvs. No manual intervention is needed. - Per-face vertex winding includes
winding_version(current: 1). Legacy data (version 0, pre-April 2026) used CCW vertex winding for manually-created faces, which rendered inside-out under Godot 4's CW front-face convention. On load,apply_serialized_faces()detects v0 faces and runs a centroid-based migration: each face's normal is checked against the outward direction from the brush center, and faces pointing inward have their vertices reversed to CW. Mesh-extracted faces (already CW) are left unchanged. No manual intervention is needed. - Autosaves write to
res://.hammerforge/autosave.hflevelby default. - Store
.hflevelin version control for reliable recovery.
- Entity I/O connections are stored per-entity in the
io_outputskey of each entity record. - Each connection is a Dictionary:
{output_name, target_name, input_name, parameter, delay, fire_once}. - Connections are captured by
capture_entity_info()and restored byrestore_entity_from_info(). - Missing
io_outputskey on load = no connections (backward-compatible).
- Brush entity class (
func_detail,func_wall,trigger_once,trigger_multiple) is stored in thebrush_entity_classkey of each brush record. - Missing key on load = no entity class (standard structural brush).
- Use
.mapto exchange basic brush layouts with other editors. - Import supports axis-aligned boxes and simple cylinders.
- Export writes box and cylinder primitives only and does not preserve per-face materials or paint data.
- Treat
.mapas a blockout exchange format, not a full fidelity export. - Multi-format export: Classic Quake and Valve 220 format adapters are available via the format selector in the dock File section. Valve 220 includes UV texture axes from FaceData.
Legacy .map files from Hammer, TrenchBroom, and other editors often carry floating-point representation drift in vertex coordinates. Two vertices that should be coincident may differ by a fraction of a unit, producing micro-gaps or non-planar faces after import.
MapIO.parse_map_text() automatically welds near-coincident parsed vertices before constructing brush geometry. The tolerance is controlled by MapIO.import_weld_tolerance (default 0.01 units). Vertices within this distance are averaged to a shared position via BFS grouping over a spatial hash with 27-cell neighbor lookup, so pairs that straddle a snap-grid boundary are still caught.
To adjust the tolerance:
MapIO.import_weld_tolerance = 0.05 # increase for very noisy legacy files
MapIO.import_weld_tolerance = 0.0 # disable welding entirelyAfter import, run Check Bake Issues (Manage tab) to detect any remaining non-planar faces or micro-gaps between brushes. The validation system offers auto-fix methods (weld_brush_vertices, fix_non_planar_faces) for post-import cleanup.
.glbexport writes the baked geometry only.- A successful bake is required before export.
- Use
Bake -> Export .glbwhen you need DCC or engine interoperability.
- The material palette can be saved and loaded independently via
MaterialManager.save_library()/load_library(). - Library files are JSON containing material resource paths — portable across projects.
- The library path can be stored alongside
.hflevelsaves.
- HammerForge ships with 150 built-in SVG prototype textures at
addons/hammerforge/textures/prototypes/. - Click Refresh Prototypes in Paint tab → Materials section to batch-load all textures into the palette.
- Once loaded, prototype materials are serialized in
.hflevelsaves alongside custom materials. - Prototype textures are included in the plugin directory and travel with the project automatically.
- Entity types and brush entity classes are loaded from
entities.json(data-driven, not hardcoded). - Custom entity definitions can be added by creating or editing
res://addons/hammerforge/entities.json. - Definitions include
classname,description,color,is_brush_entity,properties, and optionalscene_path.
.hfprefabfiles store reusable brush + entity groups as JSON.- Transforms are stored relative to the group centroid, so prefabs can be placed at any world position.
- Brush IDs and group IDs are stripped on capture; new ones are assigned on instantiation.
- Entity I/O connections are captured and remapped to new entity names when instantiated.
- Data encoding uses the same
HFLevelIO.encode_variant()/decode_variant()pipeline as.hflevel(handles Vector3, Transform3D, Basis, etc.). - Prefab files are saved to
res://prefabs/by default. The directory is created automatically on first save. - Prefabs are portable between projects — just copy
.hfprefabfiles to another project'sres://prefabs/folder.
- Autosave writes happen on a background thread.
- If a write fails (e.g., disk full, permissions), the
autosave_failedsignal fires and the dock shows a red warning label. - The next autosave interval retries automatically.
- Manual save is always available via Manage tab → File section.
- Design and iterate in HammerForge.
- Save
.hflevelto preserve full fidelity editing data. - Bake when you need runtime geometry.
- Export
.glbfor downstream tools or external engines.