Skip to content
Sample of Hash-driven Procedural City Skyline

shader_legends_3 · DaveHoskinsHashCity

Hash-driven Procedural City Skyline

A 2D orthographic night-time cityscape whose per-column building heights come from 1D FBM noise and whose lit windows are a per-cell hash threshold. A vertical sky gradient (deep purple → warm orange) and a small moon disc complete the scene. The result reads as a recognisable skyline at sunset and is built from < 20 lines of effective shader code — the canonical example of 'small-hash, big-picture' shader work.

Original: https://www.shadertoy.com/results?query=dave+hoskins+city

▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.

Family
shader_legends_3
Source
shader_legends_3
Evolution
noise_field
Render
layered_field
Complexity
medium
Agents
0
Year
2014
Author
Dave Hoskins (Shadertoy user 'Dave_Hoskins')

Math essence

For each column c: h(c, t) = fbm_1d(c * building_freq + drift * t, 4 octaves); top_c = ground - h * height_max. For each pixel (x, y) with y <= top_c paint facade = facade_color * (0.5 + 0.6 * (top_c - y) / height_max) * (0.85 + 0.30 * hash11(c, seed)). For each window cell (col // (ww+pad), row // (wh+pad)) whose hash > lit_threshold, paint window_color with a per-window warm jitter. A small 5x5 box-blur bloom around lit windows adds the light-leak glow.

Parameters

Name Type Default Range Description
dim int 400 160–800 Square output size in pixels.
building_freq float 0.06 0.02–0.2 1D FBM sample rate per column.
height_max float 0.55 0.2–0.8 Maximum building height in canvas units.
ground float 0.78 0.55–0.9 Y of the street/ground line.
window_w int 6 3–12 Window width in pixels.
window_h int 9 4–18 Window height in pixels.
window_pad int 2 1–6 Gap between adjacent windows.
lit_threshold float 0.62 0.4–0.85 Per-cell hash threshold above which a window is lit.
window_color rgb 1,0.85,0.45 null–null Lit-window tint (warm).
sky_top rgb 0.06,0.05,0.14 null–null Sky colour at the top of the canvas.
sky_bottom rgb 0.55,0.28,0.2 null–null Sky colour at the horizon.
facade_color rgb 0.1,0.1,0.16 null–null Building facade tint.
moon_color rgb 0.95,0.92,0.78 null–null Moon disc colour.
drift float 0.04 -0.3–0.3 Per-step drift of the 1D FBM sample (scrolls the skyline).

Reference

First 60 lines of reference.py. Full source: library_external/shader_legends_3/DaveHoskinsHashCity/reference.py

from __future__ import annotations

from typing import ClassVar

import numpy as np


def _hash11(x: np.ndarray, seed: int) -> np.ndarray:
    """Dave Hoskins's single-component integer hash, returns float in [0, 1)."""
    p = np.int64(x) * np.int64(374761393) + np.int64(seed) * np.int64(668265263)
    p = p & np.int64(0xFFFFFFFF)
    p = (p ^ (p >> np.int64(13))) * np.int64(1274126177)
    p = p & np.int64(0xFFFFFFFF)
    p = p ^ (p >> np.int64(16))
    return (p & np.int64(0xFFFFFFFF)).astype(np.float32) / np.float32(0xFFFFFFFF)


def _hash12(x: np.ndarray, y: np.ndarray, seed: int) -> np.ndarray:
    """Dave Hoskins-style 2D hash → [0, 1)."""
    p = np.int64(x) * np.int64(374761393) + np.int64(y) * np.int64(668265263) + np.int64(seed)
    p = p & np.int64(0xFFFFFFFF)
    p = (p ^ (p >> np.int64(13))) * np.int64(1274126177)
    p = p & np.int64(0xFFFFFFFF)
    p = p ^ (p >> np.int64(16))
    return (p & np.int64(0xFFFFFFFF)).astype(np.float32) / np.float32(0xFFFFFFFF)


def _value_noise_1d(x: np.ndarray, seed: int) -> np.ndarray:
    """Bilinearly smoothed 1D value noise from a deterministic hash."""
    xi = np.floor(x).astype(np.int64)
    xf = (x - xi).astype(np.float32)
    u = xf * xf * (3.0 - 2.0 * xf)
    n0 = _hash11(xi, seed)
    n1 = _hash11(xi + 1, seed)
    return n0 * (1.0 - u) + n1 * u


def _fbm_1d(x: np.ndarray, octaves: int, seed: int, lac: float = 2.0, gain: float = 0.5) -> np.ndarray:
    total = np.zeros_like(x, dtype=np.float32)
    amp = np.float32(1.0)
    freq = np.float32(1.0)
    norm = np.float32(0.0)
    for k in range(octaves):
        total = total + amp * _value_noise_1d(x * freq, seed + k * 17)
        norm = norm + amp
        amp = amp * np.float32(gain)
        freq = freq * np.float32(lac)
    return total / max(norm, 1e-6)


class DaveHoskinsHashCity:
    """Hash-driven procedural city skyline — Dave Hoskins (Shadertoy).

    Dave Hoskins's *City* shader (Shadertoy) is a single line of GLSL
    that turns a per-column 1D noise sample into a building height,
    and then walks down the building drawing lit windows whose on/off
    state is decided by another hash of the column-and-row integer
    pair.  It is the canonical example of "small-hash, big-picture"
    shader work: every pixel of the cityscape comes from < 20 lines
    of code yet reads as a recognisable skyline at night.

Try running it locally

The reference implementation is self-contained Python with numpy. Install the package and run:

python library_external/shader_legends_3/DaveHoskinsHashCity/reference.py

Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.

More from shader_legends_3

Sample of Animated FBM Nebula with Chromatic Aberration

Animated FBM Nebula with Chromatic Aberration

shader_legends_3 · AshleyGAnimNebula

A multi-coloured, slowly rotating cosmic gas cloud built from 5 layers of FBM noise at different scales, each layer rotated by a different angle that varies with time.

View →
Sample of Atmospheric Perspective Landscape

Atmospheric Perspective Landscape

shader_legends_3 · HubertyAtmospheric

A painterly 2D landscape built from depth-graded FBM bands: a soft sky gradient with a sun disc and cloud streaks, a low-amp haze band in the upper-middle, rolling green midground hills, and a sharp foreground silhouette of trees and grass.

View →
Sample of Bokeh Blur with Light Leaks

Bokeh Blur with Light Leaks

shader_legends_3 · TaterBokeh

A 2D bokeh effect built by stamping 50-200 soft Gaussian discs onto a near-black backdrop, each at a hash-determined centre, radius, and warm-to-cool colour.

View →
Sample of Recursive Spherical Displacement Wireframe

Recursive Spherical Displacement Wireframe

shader_legends_3 · IQDisplacementSphere

A wireframe sphere whose surface is recursively displaced by spherical harmonics of the form amp * sin(N * theta) * cos(M * phi), rendered as overlapping latitude and meridian polylines plus random surface dots.

View →
Sample of Volumetric Clouds from Cellular + FBM

Volumetric Clouds from Cellular + FBM

shader_legends_3 · BigWingsClouds

A painterly cumulus-cloud sky built from a Worley/cellular noise layer (cloud puffs) gated by a low-frequency FBM (large-scale cloud coverage) and a high-frequency FBM (in-cloud detail).

View →

See all shader_legends_3 artworks →