# How Gabled, Hipped, and Skillion Roofs Are Generated in Arnis Using the RoofType Enum

> Discover how Arnis generates gabled, hipped, and skillion roofs using the RoofType enum. Learn about the specialized geometric algorithms and stair block placement in this deep dive.

- Repository: [Louis Erbkamm/arnis](https://github.com/louis-e/arnis)
- Tags: internals
- Published: 2026-03-20

---

**The `RoofType` enum in [`src/element_processing/buildings.rs`](https://github.com/louis-e/arnis/blob/main/src/element_processing/buildings.rs) acts as a dispatcher that routes to specialized functions—`generate_gabled_roof`, `generate_hipped_roof_rectangular`/`generate_hipped_roof_square`, and `generate_skillion_roof`—each implementing distinct geometric algorithms to create height maps and place stair blocks.**

Arnis is a procedural Minecraft world generator that converts OpenStreetMap (OSM) data into detailed block structures. When processing building elements, the generator uses the **RoofType enum** to determine which algorithmic approach will create the roof geometry. Each variant triggers a specific implementation that calculates height maps, places ridge lines, and orients stair blocks to match real-world roof architecture.

## The RoofType Enum and Dispatch Architecture

### Enum Definition and OSM Mapping

The `RoofType` enum is defined between lines 18–27 in [`src/element_processing/buildings.rs`](https://github.com/louis-e/arnis/blob/main/src/element_processing/buildings.rs). It enumerates the supported roof geometries that can be parsed from OSM tags or assigned procedurally. The enum includes variants for `Flat`, `Gabled`, `Hipped`, `Skillion`, `Pyramidal`, and `Dome`.

OSM string values are mapped to these variants through the `parse_roof_type` helper function (lines 2272–2279). This parser normalizes raw OSM data into the strongly-typed enum used by the generation pipeline:

```rust
fn parse_roof_type(roof_shape: &str) -> RoofType {
    match roof_shape {
        "gabled"                     => RoofType::Gabled,
        "hipped" | "half-hipped"     => RoofType::Hipped,
        "skillion"                   => RoofType::Skillion,
        // ... additional mappings
        _ => RoofType::Flat,
    }
}

```

### The generate_roof Dispatcher

The `generate_roof` function (lines 3117–3130) serves as the central dispatcher. It accepts a `RoofType` and delegates to the specific generation routine. This match-based architecture isolates the geometric logic for each roof style while providing a unified interface for the building processor:

```rust
match roof_type {
    RoofType::Flat      => generate_flat_roof(...),
    RoofType::Gabled    => generate_gabled_roof(...),
    RoofType::Hipped    => { /* rectangular vs. square decision */ },
    RoofType::Skillion  => generate_skillion_roof(...),
    RoofType::Pyramidal => generate_pyramidal_roof(...),
    RoofType::Dome      => generate_dome_roof(...),
}

```

## Gabled Roof Generation Algorithm

The `generate_gabled_roof` function (lines 81–115) implements the classic dual-sloped roof with a central ridge. The algorithm follows three distinct phases: ridge calculation, height-map generation, and block placement.

First, the function determines the ridge orientation. If the optional `roof:orientation` OSM tag is present, it aligns the ridge along the specified axis (X or Z). Without explicit orientation, the generator defaults to the shorter building dimension to create aesthetically proportional slopes.

Height calculation follows a strict linear progression from the ridge outward. The algorithm computes the maximum distance from the ridge line to the building perimeter, then derives a height boost limited to that distance. This enforces a consistent **1-block-per-row slope**, ensuring the roof angle remains walkable and visually consistent in Minecraft's block grid.

Block placement utilizes the shared `place_roof_blocks_with_stairs` helper. Outer perimeter cells receive stair blocks facing outward to create the roof overhang, while interior cells receive stairs only where a lower-height neighbor exists, generating the characteristic sloping side-faces of a gabled structure.

## Hipped Roof Generation Algorithm

Hipped roofs slope downward from a central ridge or peak toward all four walls. The implementation splits between rectangular and square/complex footprints to optimize the geometry calculation.

### Rectangular Hipped Roofs

The `generate_hipped_roof_rectangular` function (lines 56–95) handles elongated buildings. It establishes a ridge line along the longer axis of the footprint. Height calculation uses the **minimum distance to any edge** from each interior point, scaled by a ridge-peak height parameter. This creates the characteristichipped profile where all four sides have visible slope.

Stair orientation is determined by the nearest edge. The generator compares each cell's position against the four perimeter boundaries and orients stairs to face outward toward the closest wall, creating the seamless hip corners.

### Square and Complex Hipped Roofs

For square or irregular footprints, `generate_hipped_roof_square` (lines 57–84) employs a radial distance calculation. It computes each cell's normalized distance from the building center rather than edge proximity. This approach generalizes to complex polygonal footprints where a simple ridge line is insufficient.

The quadrant-based stair placement orients blocks according to the cell's position relative to the center (northeast, northwest, southeast, southwest), ensuring consistent slope direction toward all corners.

## Skillion Roof Generation Algorithm

The `generate_skillion_roof` function (lines 38–63) implements the mono-pitch or shed roof—a single sloping plane rising from one wall to the opposite wall.

The algorithm establishes a linear gradient across the X-axis (west to east). The maximum roof height is dynamically clamped between 4 and 10 blocks using the calculation `(building_size / 3).clamp(4, 10)`. This prevents excessively steep roofs on small structures while ensuring visibility on large warehouses.

Each column's height follows the formula `base_height + slope_progress * max_roof_height`, where `slope_progress` represents the normalized position from the western edge (0.0) to the eastern edge (1.0).

Stair placement is the simplest of all roof types. Every cell receives identical east-facing stair blocks placed atop the roof surface, creating the uniform single-direction slope without complex corner logic.

## Summary

- The **RoofType enum** in [`src/element_processing/buildings.rs`](https://github.com/louis-e/arnis/blob/main/src/element_processing/buildings.rs) provides a type-safe abstraction over OSM `roof:shape` tags, with variants for Gabled, Hipped, Skillion, and other common styles.
- The **`generate_roof` dispatcher** (lines 3117–3130) matches on the enum and delegates to specialized geometry functions, isolating the algorithmic complexity of each roof style.
- **Gabled roofs** calculate a central ridge line and enforce a 1-block-per-row slope outward, using outer-facing stairs for edges and neighbor-aware stairs for interior slopes.
- **Hipped roofs** split between rectangular footprints (ridge along long axis, minimum distance height calculation) and square/complex footprints (radial distance from center), with quadrant-based stair orientation.
- **Skillion roofs** apply a linear X-axis gradient with clamped height limits (4–10 blocks), placing uniform east-facing stairs across the entire surface.

## Frequently Asked Questions

### How does Arnis parse OSM roof tags into the RoofType enum?

Arnis uses the `parse_roof_type` helper function located at lines 2272–2279 in [`src/element_processing/buildings.rs`](https://github.com/louis-e/arnis/blob/main/src/element_processing/buildings.rs). This function takes the string value from the OSM `roof:shape` tag and matches it against known patterns: `"gabled"` maps to `RoofType::Gabled`, `"hipped"` or `"half-hipped"` map to `RoofType::Hipped`, and `"skillion"` maps to `RoofType::Skillion`. Unrecognized values default to `RoofType::Flat`.

### What is the maximum height of a generated skillion roof?

The skillion roof generator enforces a dynamic height constraint calculated as `(building_size / 3).clamp(4, 10)`. This means the maximum peak height is always clamped between 4 and 10 blocks regardless of building size. Small structures will have a minimum height of 4 blocks, while very large buildings will cap at 10 blocks to prevent unrealistically steep slopes in the Minecraft block grid.

### How do hipped roof generators handle non-rectangular building footprints?

The implementation splits hipped roof generation into two strategies based on footprint geometry. For rectangular buildings, `generate_hipped_roof_rectangular` (lines 56–95) establishes a ridge along the longer axis and calculates height based on minimum distance to any edge. For square or complex polygons, `generate_hipped_roof_square` (lines 57–84) uses a radial algorithm, calculating each cell's height based on normalized distance from the building center rather than edge proximity, allowing it to generalize to irregular shapes.

### Where are the roof block placement helpers defined?

The shared helper `place_roof_blocks_with_stairs` is defined in [`src/element_processing/buildings.rs`](https://github.com/louis-e/arnis/blob/main/src/element_processing/buildings.rs) and is called by multiple roof generators. It iterates over the calculated height map and determines stair orientation based on local slope direction. Additional material helpers `get_stair_block_for_material` and `create_stair_with_properties` handle the abstraction of stair block selection and orientation properties, ensuring that roof blocks match the building's material palette while facing the correct cardinal direction.