earthwalker17/map-of-middle-earth

A cinematic floating miniature diorama of Middle-earth rendered with three.js WebGPU + TSL: terrain from community GIS data, atmosphere, vegetation, effects and 24 landmarks, captured deterministically for the film Journey Through Middle-Earth. Non-commercial fan project.

TypeScript

4

341 commits

updated Oct 6, 2026

See the code

See what people are saying

SourceMessageScoreDate

Opus 5.5 built the entire Middle-earth from LOTR with Three.js (r/ClaudeAI)

I used Claude Opus 5.5 to build a miniature 3D Middle-earth from scratch, then turn that world into a 3:47 cinematic journey. The project ended up with: * terrain and geography generation * Three.js / WebGPU scene architecture * 24 procedural landmarks * lighting, atmosphere, water, smoke, lava and…

77

Oct 7, 2026

README

Map of Middle-Earth

A cinematic floating miniature of Middle-earth, rendered with three.js WebGPU,
and the world of the short film Journey Through Middle-Earth.

CI License: MIT (code) three.js r186 WebGPU + TSL TypeScript strict

Journey Through Middle-Earth: watch the film on YouTube
▶ Watch Journey Through Middle-Earth on YouTube

The floating map of Middle-earth at golden hour
The map at golden hour: 1,600 × 960 km of Middle-earth on a floating slab, rendered in the browser (the same view as the day / night pair below).

A miniature Middle-earth that you can fly over, from the Grey Havens to Mount Doom. The terrain is built from community GIS data, 24 landmarks are modelled in code, and the sky, water, smoke and light are all rendered live: nothing is pre-rendered. It runs in the browser with three.js WebGPU, and the film was captured from it frame by frame. The look aims at the bigatures of Peter Jackson's films: a physical model under real light, never a toy.

Status: V1 is complete (v1.0.0): the locked static world and the finished film, 227.75 s at 1080p24. The film is a west → east grand tour via Rohan, loosely on Frodo's road from the Shire to Mount Doom, with a luminous gold route line, floating labels, title cards and an original orchestral score. Watch it on YouTube.

Erebor, the Lonely Mountain, in low evening sun Lake-town on its piles in the Long Lake Hobbiton in late-afternoon light
Erebor · Lake-town · Hobbiton


The Doors of Durin by night Lothlórien at dusk The Argonath
The Doors of Durin · Lothlórien · The Argonath


Minas Morgul and its beam The Black Gate between the Towers of the Teeth, Mount Doom's plume beyond Mount Doom with its plume and lava flows, Barad-dûr beyond
Minas Morgul · The Black Gate · Mount Doom

Day and night

The whole map by day and by moonlight
The map: 11:00 and 23:00, settlement lights and Mordor's fires under the moon.

Minas Tirith in the early morning and with the beacon lit
Minas Tirith: early morning, and the beacon lit on Mindolluin.

Rivendell in October afternoon light and under a full moon
Rivendell: an October afternoon, and a full moon over the gorge.

Highlights

  • Real geography. Coastlines, rivers, lakes and relief come from the ME-DEM elevation model and the ME-GIS vector layers. A Python bake snaps rivers to their valleys, solves lake levels and derives the landcover. Heights are exaggerated, as on a relief model, and the world sits on a floating slab.
  • 24 landmarks, from Hobbiton to Barad-dûr. Each one is declared once: terrain stamps, procedural architecture from a shared TypeScript kit (plus one Blender-generated model, the Argonath), lights, trees, emitters and camera bookmarks. Shared systems turn those declarations into the scene.
  • Atmosphere and grade. Regional haze and colour grades, cumulus and cloud shadows, valley mist, a moonlit night sky, and an ash pall over Mordor lit red from below by Mount Doom.
  • Surfaces. A layered terrain material (strata, scree, snow, volcanic crust and lava), tree crown archetypes from broadleaf and conifer to holly and shrub with a far canopy shell, rivers and lakes with reflections, and weathered stone, timber and roofs.
  • Light that lights things. Lava, beacons, braziers, the Morgul beam and the glow of whole settlements spill light onto the rock, water and foliage around them.
  • Stateless effects. Plumes, waterfalls, spray, mist and sparks are driven by an effect clock, never by simulation history, so any frame of the film can be rendered on its own.
  • Offline quality, deterministic frames. Every frame is a pure function of a scene state. Stills and film frames use jittered multi-sample accumulation, subtle depth of field on close heroes, halation, a film grade and grain, and they are bit-identical from run to run on the same browser and GPU driver.
  • QA built in. Headless capture through Chrome's WebGPU readback, pixel-hash locks, a CPU camera probe with framing gates, blind A/B reviews and a performance gate for the real-time preview.

How it works

Third-party data is baked once into a deterministic world. Landmarks only declare what they need, and a small set of shared systems realizes it. A timeline turns time into a complete SceneState, and the renderer turns that state into pixels: in the interactive explorer, or accumulated offline for stills and film frames.

flowchart TB
  S["ME-DEM · ME-GIS · Arda<br/>(fetched, never committed)"] -->|"pnpm bake (Python)"| B["baked world<br/>heights · water · landcover"]
  A["data/world<br/>places · regions · looks"] --> W
  B --> W["World + HeightField"]
  T["Timeline.evaluate(t)<br/>→ SceneState"] --> Y
  L["24 landmark declarations<br/>stamps · kit · lights · emitters"] --> W
  W --> Y["systems<br/>terrain · water · vegetation · environment<br/>landmarks · emission · effects"]
  Y --> R["WebGPU / TSL render × spp<br/>DOF · grade · grain"]
  R --> E["explorer"]
  R --> C["readback → stills · QA · film frames"]

The contracts are in docs/ARCHITECTURE.md. The roadmap and the current state are in docs/PROJECT_STATE.md.

PathWhat lives there
src/the renderer: core / timeline, world services, terrain, water, vegetation, environment, landmarks, emission, effects, materials, diorama slab, camera, render (post, capture)
tools/the Python bake, capture / QA / review, the film renderer (pnpm film), the score (tools/music, Python), checks and the camera probe, Blender model scripts
data/world, data/tour, data/qaauthored world data, the film's route, shot list and picture-locked timeline, QA shots / sets / locks
docs/architecture, project state, early research briefs, README images

Running it

You need Google Chrome with hardware WebGPU (the capture tools drive the installed Chrome; other WebGPU browsers are untested for the explorer), Node 24 (≥ 22.12), pnpm 11 (corepack enable picks the pinned version) and uv for the Python bake and the score. Allow about 2.5 GB of disk for the data, the bake and its Python environment. The film also needs an FFmpeg 8 full build (see The film). Blender 4.5 is only needed to rebuild the Argonath model, which is committed (pnpm models; set MOME_BLENDER to its binary off Windows).

pnpm install
pnpm data:fetch   # ≈ 1.2 GB of source data and CC0 textures (their own terms)
pnpm bake         # builds data/baked (Python 3.12 via uv)
pnpm dev          # explorer at localhost:5173 (?quality=review|final)
pnpm shots --shot minas-tirith-close --quality final --spp 12   # a still

The explorer and the captures need the fetched data and the bake; there is no prebuilt world. The explorer has orbit controls and a panel for the QA shots and landmark bookmarks, time of day, day of the year (sun and moon), field of view and exposure. Stills are written to renders/shots/latest/ (1920×1080 by default). pnpm typecheck and pnpm check run without any third-party data. Without a bake, pnpm check runs the place, landmark-definition, asset-credit, light-gate, static effects (textures, presets, declarations) and film-structure checks, and skips the baked-world gates (rivers, stamps, hydro), the landmark build and bookmark framing gates, the effects' world placement, particle and budget checks and the compiled-film gates.

The project was developed on a Windows 11 laptop with 8 GB of RAM and an Intel UHD iGPU, and the real-time preview tier is tuned for that machine. The capture, bake and QA tooling (GPU job lock, memory guard) is written for and tested on Windows. The bake and captures first wait for free RAM (2.5 / 1.8 GB); if they wait in vain (e.g. on macOS, where Node under-reports free memory), set MOME_MEM_GUARD=0.

The film

Journey Through Middle-Earth runs 227.75 s (5,466 frames at 24 fps, 1920×1080). It is rendered from the picture-locked timeline (data/tour/timeline.json, film hash 1c3edf71) at the final tier: 12 samples per pixel, up to 48 on fast moves for the motion blur of a 180° shutter, subtle depth of field on the four close hero holds (Hobbiton, Rivendell, the Argonath, Mount Doom) and film grain. The finished film is on YouTube. Its files live in the gitignored final/ folder: journey-through-middle-earth-1080p.mp4 (H.264, AAC 320k), the master journey-through-middle-earth-1080p-master.mov (ProRes 422 HQ 10-bit, 24-bit PCM) and ABOUT.txt (provenance); neither they nor the score are distributed with this repository.

To reproduce them (with the data fetched and baked: the cue export compiles the film on the baked world), render the score first (uv; the fetch puts the CC0 samples and the sfizz renderer, ≈ 1.5 GB, in data/music-src/):

uv run --project tools/music python tools/music/fetch.py
node --import tsx tools/check/film.ts --cues renders/music/cues-v2.json   # the cue sheet of the locked picture
pnpm music --cues renders/music/cues-v2.json --label v4-lock             # → renders/music/<stamp>-v4-lock/master.wav

Then render the picture in its own PowerShell window. tools/capture/film-overnight.ps1 runs pnpm film --render with no time budget, resumes after a failure and holds off idle sleep; -Chrome sets MOME_CHROME to a private copy of Chrome 154.0.8037.95, the build the world was locked on, so an auto-update cannot change pixels mid-render. A run refuses another Chrome, another film hash, a dirty tree or a commit that changes the render inputs.

Start-Process pwsh -ArgumentList '-NoExit','-File','tools\capture\film-overnight.ps1','-Run','renders\film\<dir>','-Chrome',"$env:LOCALAPPDATA\map-of-middle-earth\chrome-154.0.8037.95\chrome.exe",'-FilmArgs:"--tier final --spp 12 --spp-ladder 36:16,48:24,72:32,96:48 --shutter 0.5 --label final-1080p"'
$env:MOME_CHROME = "$env:LOCALAPPDATA\map-of-middle-earth\chrome-154.0.8037.95\chrome.exe"
pnpm film --verify-resume --run renders\film\<dir>   # re-renders sample frames: same sha256?
pnpm film --assemble --run renders\film\<dir> --audio renders\music\<stamp>-v4-lock\master.wav --mp4 <abs>.mp4 --master <abs>.mov

This needs FFmpeg 8.x (full build) on PATH, or MOME_FFMPEG / MOME_FFPROBE, and about 11 GB of free disk for what stays (≈ 5 GB of ProRes chunks, ≈ 5 GB for the master, ≈ 0.5 GB for the mp4), plus a temporary concat copy of the chunks while assembling (--assemble first checks for 2.2 × the chunks' size + 1 GB free). The final render took 11.1 h on the dev laptop (one unattended overnight run, 2026-10-05 → 06).

Roadmap

SessionStatus
1Foundation and geography: world data, systems, capture and QA✅
2World look: bake v2, atmosphere, regional grades, terrain and vegetation✅
3All 24 landmarks: kit, stamps, emission, Blender pipeline✅
4Look and still effects: sky, night, water, effects, lens and grade, hero polish✅
4.5Static world locked (v0.5.0), README, repository polish✅
5The journey: camera rig and timeline, gold route line, titles, picture lock, original score, 720p review cut✅
6Final render (1080p24, final tier), V1 release (v1.0.0)✅

Deferred work and polish candidates are listed under "V2 candidates" in docs/PROJECT_STATE.md.

Credits

The geography comes from the ME-DEM project of the Outerra Worlds Forum (elevation model by monks and Redrobes, place names by monks, SeerBlue and Redrobes, later maintained by jvangeld), the ME-GIS vector layers created for ME-DEM by monks and SeerBlue and improved by jvangeld (andrewheiss/ME-GIS), and the Arda packaging by bburns, with the GeoPackage conversion by tetrakai1 (bburns/Arda). The data authors are being asked for their blessing for this use. Terrain detail textures are from Poly Haven (CC0). The fonts are Cinzel, Cinzel Decorative, Cormorant Garamond, and EB Garamond (SIL OFL 1.1). The score is played by the VSCO 2 Community Edition samples of Versilian Studios (CC0) through sfizz (BSD-2-Clause), both used at render time only and never redistributed. The project is built with three.js, Vite, TypeScript, Playwright, sharp and Blender, and the film is encoded with FFmpeg (LGPL-2.1+ / GPL depending on the build; called as an external program, not shipped). Every asset and source is listed in CREDITS.md.

License

  • Code and original models (public/models): MIT.
  • Fonts: SIL Open Font License 1.1 (each family's OFL.txt sits in public/fonts/).
  • Third-party geographic data is not part of this repository. pnpm data:fetch downloads it from the authors' repositories, and their terms apply: ME-GIS asks users to request permission before use, and the licence of the Arda DEM and vectors is uncertain.
  • Renders (docs/images/) show terrain derived from that data. They are not covered by the MIT licence and no reuse licence is granted; they are here to illustrate the project.
  • The film and its score (the rendered picture and audio, not the code that makes them) are project renders and recordings. They are not covered by the MIT licence and no reuse licence is granted. The film is published on YouTube; neither its files nor the score are part of this repository.

Disclaimer

A non-commercial fan project. It is not affiliated with or endorsed by the Tolkien Estate, Middle-earth Enterprises, HarperCollins, New Line Cinema, Warner Bros., Wētā Workshop, or any data author, font designer or artist credited in CREDITS.md. The Lord of the Rings, The Hobbit and Middle-earth are trademarks of their respective owners. The project contains no film footage, artwork, logos or typography from the films, no Tengwar or Cirth, and its music is original.

cinematic
computer-graphics
deterministic
diorama
fan-project
fantasy-map
gis
heightmap
lord-of-the-rings
middle-earth
miniature
offline-rendering
procedural-generation
terrain-rendering
threejs
tolkien
tsl
typescript
vite
webgpu

earthwalker17/map-of-middle-earth

A cinematic floating miniature diorama of Middle-earth rendered with three.js WebGPU + TSL: terrain from community GIS data, atmosphere, vegetation, effects and 24 landmarks, captured deterministically for the film Journey Through Middle-Earth. Non-commercial fan project.

TypeScript

4

341 commits

updated Oct 6, 2026

See the code

See what people are saying

SourceMessageScoreDate

Opus 5.5 built the entire Middle-earth from LOTR with Three.js (r/ClaudeAI)

I used Claude Opus 5.5 to build a miniature 3D Middle-earth from scratch, then turn that world into a 3:47 cinematic journey. The project ended up with: * terrain and geography generation * Three.js / WebGPU scene architecture * 24 procedural landmarks * lighting, atmosphere, water, smoke, lava and…

77

Oct 7, 2026

README

Map of Middle-Earth

A cinematic floating miniature of Middle-earth, rendered with three.js WebGPU,
and the world of the short film Journey Through Middle-Earth.

CI License: MIT (code) three.js r186 WebGPU + TSL TypeScript strict

Journey Through Middle-Earth: watch the film on YouTube
▶ Watch Journey Through Middle-Earth on YouTube

The floating map of Middle-earth at golden hour
The map at golden hour: 1,600 × 960 km of Middle-earth on a floating slab, rendered in the browser (the same view as the day / night pair below).

A miniature Middle-earth that you can fly over, from the Grey Havens to Mount Doom. The terrain is built from community GIS data, 24 landmarks are modelled in code, and the sky, water, smoke and light are all rendered live: nothing is pre-rendered. It runs in the browser with three.js WebGPU, and the film was captured from it frame by frame. The look aims at the bigatures of Peter Jackson's films: a physical model under real light, never a toy.

Status: V1 is complete (v1.0.0): the locked static world and the finished film, 227.75 s at 1080p24. The film is a west → east grand tour via Rohan, loosely on Frodo's road from the Shire to Mount Doom, with a luminous gold route line, floating labels, title cards and an original orchestral score. Watch it on YouTube.

Erebor, the Lonely Mountain, in low evening sun Lake-town on its piles in the Long Lake Hobbiton in late-afternoon light
Erebor · Lake-town · Hobbiton


The Doors of Durin by night Lothlórien at dusk The Argonath
The Doors of Durin · Lothlórien · The Argonath


Minas Morgul and its beam The Black Gate between the Towers of the Teeth, Mount Doom's plume beyond Mount Doom with its plume and lava flows, Barad-dûr beyond
Minas Morgul · The Black Gate · Mount Doom

Day and night

The whole map by day and by moonlight
The map: 11:00 and 23:00, settlement lights and Mordor's fires under the moon.

Minas Tirith in the early morning and with the beacon lit
Minas Tirith: early morning, and the beacon lit on Mindolluin.

Rivendell in October afternoon light and under a full moon
Rivendell: an October afternoon, and a full moon over the gorge.

Highlights

  • Real geography. Coastlines, rivers, lakes and relief come from the ME-DEM elevation model and the ME-GIS vector layers. A Python bake snaps rivers to their valleys, solves lake levels and derives the landcover. Heights are exaggerated, as on a relief model, and the world sits on a floating slab.
  • 24 landmarks, from Hobbiton to Barad-dûr. Each one is declared once: terrain stamps, procedural architecture from a shared TypeScript kit (plus one Blender-generated model, the Argonath), lights, trees, emitters and camera bookmarks. Shared systems turn those declarations into the scene.
  • Atmosphere and grade. Regional haze and colour grades, cumulus and cloud shadows, valley mist, a moonlit night sky, and an ash pall over Mordor lit red from below by Mount Doom.
  • Surfaces. A layered terrain material (strata, scree, snow, volcanic crust and lava), tree crown archetypes from broadleaf and conifer to holly and shrub with a far canopy shell, rivers and lakes with reflections, and weathered stone, timber and roofs.
  • Light that lights things. Lava, beacons, braziers, the Morgul beam and the glow of whole settlements spill light onto the rock, water and foliage around them.
  • Stateless effects. Plumes, waterfalls, spray, mist and sparks are driven by an effect clock, never by simulation history, so any frame of the film can be rendered on its own.
  • Offline quality, deterministic frames. Every frame is a pure function of a scene state. Stills and film frames use jittered multi-sample accumulation, subtle depth of field on close heroes, halation, a film grade and grain, and they are bit-identical from run to run on the same browser and GPU driver.
  • QA built in. Headless capture through Chrome's WebGPU readback, pixel-hash locks, a CPU camera probe with framing gates, blind A/B reviews and a performance gate for the real-time preview.

How it works

Third-party data is baked once into a deterministic world. Landmarks only declare what they need, and a small set of shared systems realizes it. A timeline turns time into a complete SceneState, and the renderer turns that state into pixels: in the interactive explorer, or accumulated offline for stills and film frames.

flowchart TB
  S["ME-DEM · ME-GIS · Arda<br/>(fetched, never committed)"] -->|"pnpm bake (Python)"| B["baked world<br/>heights · water · landcover"]
  A["data/world<br/>places · regions · looks"] --> W
  B --> W["World + HeightField"]
  T["Timeline.evaluate(t)<br/>→ SceneState"] --> Y
  L["24 landmark declarations<br/>stamps · kit · lights · emitters"] --> W
  W --> Y["systems<br/>terrain · water · vegetation · environment<br/>landmarks · emission · effects"]
  Y --> R["WebGPU / TSL render × spp<br/>DOF · grade · grain"]
  R --> E["explorer"]
  R --> C["readback → stills · QA · film frames"]

The contracts are in docs/ARCHITECTURE.md. The roadmap and the current state are in docs/PROJECT_STATE.md.

PathWhat lives there
src/the renderer: core / timeline, world services, terrain, water, vegetation, environment, landmarks, emission, effects, materials, diorama slab, camera, render (post, capture)
tools/the Python bake, capture / QA / review, the film renderer (pnpm film), the score (tools/music, Python), checks and the camera probe, Blender model scripts
data/world, data/tour, data/qaauthored world data, the film's route, shot list and picture-locked timeline, QA shots / sets / locks
docs/architecture, project state, early research briefs, README images

Running it

You need Google Chrome with hardware WebGPU (the capture tools drive the installed Chrome; other WebGPU browsers are untested for the explorer), Node 24 (≥ 22.12), pnpm 11 (corepack enable picks the pinned version) and uv for the Python bake and the score. Allow about 2.5 GB of disk for the data, the bake and its Python environment. The film also needs an FFmpeg 8 full build (see The film). Blender 4.5 is only needed to rebuild the Argonath model, which is committed (pnpm models; set MOME_BLENDER to its binary off Windows).

pnpm install
pnpm data:fetch   # ≈ 1.2 GB of source data and CC0 textures (their own terms)
pnpm bake         # builds data/baked (Python 3.12 via uv)
pnpm dev          # explorer at localhost:5173 (?quality=review|final)
pnpm shots --shot minas-tirith-close --quality final --spp 12   # a still

The explorer and the captures need the fetched data and the bake; there is no prebuilt world. The explorer has orbit controls and a panel for the QA shots and landmark bookmarks, time of day, day of the year (sun and moon), field of view and exposure. Stills are written to renders/shots/latest/ (1920×1080 by default). pnpm typecheck and pnpm check run without any third-party data. Without a bake, pnpm check runs the place, landmark-definition, asset-credit, light-gate, static effects (textures, presets, declarations) and film-structure checks, and skips the baked-world gates (rivers, stamps, hydro), the landmark build and bookmark framing gates, the effects' world placement, particle and budget checks and the compiled-film gates.

The project was developed on a Windows 11 laptop with 8 GB of RAM and an Intel UHD iGPU, and the real-time preview tier is tuned for that machine. The capture, bake and QA tooling (GPU job lock, memory guard) is written for and tested on Windows. The bake and captures first wait for free RAM (2.5 / 1.8 GB); if they wait in vain (e.g. on macOS, where Node under-reports free memory), set MOME_MEM_GUARD=0.

The film

Journey Through Middle-Earth runs 227.75 s (5,466 frames at 24 fps, 1920×1080). It is rendered from the picture-locked timeline (data/tour/timeline.json, film hash 1c3edf71) at the final tier: 12 samples per pixel, up to 48 on fast moves for the motion blur of a 180° shutter, subtle depth of field on the four close hero holds (Hobbiton, Rivendell, the Argonath, Mount Doom) and film grain. The finished film is on YouTube. Its files live in the gitignored final/ folder: journey-through-middle-earth-1080p.mp4 (H.264, AAC 320k), the master journey-through-middle-earth-1080p-master.mov (ProRes 422 HQ 10-bit, 24-bit PCM) and ABOUT.txt (provenance); neither they nor the score are distributed with this repository.

To reproduce them (with the data fetched and baked: the cue export compiles the film on the baked world), render the score first (uv; the fetch puts the CC0 samples and the sfizz renderer, ≈ 1.5 GB, in data/music-src/):

uv run --project tools/music python tools/music/fetch.py
node --import tsx tools/check/film.ts --cues renders/music/cues-v2.json   # the cue sheet of the locked picture
pnpm music --cues renders/music/cues-v2.json --label v4-lock             # → renders/music/<stamp>-v4-lock/master.wav

Then render the picture in its own PowerShell window. tools/capture/film-overnight.ps1 runs pnpm film --render with no time budget, resumes after a failure and holds off idle sleep; -Chrome sets MOME_CHROME to a private copy of Chrome 154.0.8037.95, the build the world was locked on, so an auto-update cannot change pixels mid-render. A run refuses another Chrome, another film hash, a dirty tree or a commit that changes the render inputs.

Start-Process pwsh -ArgumentList '-NoExit','-File','tools\capture\film-overnight.ps1','-Run','renders\film\<dir>','-Chrome',"$env:LOCALAPPDATA\map-of-middle-earth\chrome-154.0.8037.95\chrome.exe",'-FilmArgs:"--tier final --spp 12 --spp-ladder 36:16,48:24,72:32,96:48 --shutter 0.5 --label final-1080p"'
$env:MOME_CHROME = "$env:LOCALAPPDATA\map-of-middle-earth\chrome-154.0.8037.95\chrome.exe"
pnpm film --verify-resume --run renders\film\<dir>   # re-renders sample frames: same sha256?
pnpm film --assemble --run renders\film\<dir> --audio renders\music\<stamp>-v4-lock\master.wav --mp4 <abs>.mp4 --master <abs>.mov

This needs FFmpeg 8.x (full build) on PATH, or MOME_FFMPEG / MOME_FFPROBE, and about 11 GB of free disk for what stays (≈ 5 GB of ProRes chunks, ≈ 5 GB for the master, ≈ 0.5 GB for the mp4), plus a temporary concat copy of the chunks while assembling (--assemble first checks for 2.2 × the chunks' size + 1 GB free). The final render took 11.1 h on the dev laptop (one unattended overnight run, 2026-10-05 → 06).

Roadmap

SessionStatus
1Foundation and geography: world data, systems, capture and QA✅
2World look: bake v2, atmosphere, regional grades, terrain and vegetation✅
3All 24 landmarks: kit, stamps, emission, Blender pipeline✅
4Look and still effects: sky, night, water, effects, lens and grade, hero polish✅
4.5Static world locked (v0.5.0), README, repository polish✅
5The journey: camera rig and timeline, gold route line, titles, picture lock, original score, 720p review cut✅
6Final render (1080p24, final tier), V1 release (v1.0.0)✅

Deferred work and polish candidates are listed under "V2 candidates" in docs/PROJECT_STATE.md.

Credits

The geography comes from the ME-DEM project of the Outerra Worlds Forum (elevation model by monks and Redrobes, place names by monks, SeerBlue and Redrobes, later maintained by jvangeld), the ME-GIS vector layers created for ME-DEM by monks and SeerBlue and improved by jvangeld (andrewheiss/ME-GIS), and the Arda packaging by bburns, with the GeoPackage conversion by tetrakai1 (bburns/Arda). The data authors are being asked for their blessing for this use. Terrain detail textures are from Poly Haven (CC0). The fonts are Cinzel, Cinzel Decorative, Cormorant Garamond, and EB Garamond (SIL OFL 1.1). The score is played by the VSCO 2 Community Edition samples of Versilian Studios (CC0) through sfizz (BSD-2-Clause), both used at render time only and never redistributed. The project is built with three.js, Vite, TypeScript, Playwright, sharp and Blender, and the film is encoded with FFmpeg (LGPL-2.1+ / GPL depending on the build; called as an external program, not shipped). Every asset and source is listed in CREDITS.md.

License

  • Code and original models (public/models): MIT.
  • Fonts: SIL Open Font License 1.1 (each family's OFL.txt sits in public/fonts/).
  • Third-party geographic data is not part of this repository. pnpm data:fetch downloads it from the authors' repositories, and their terms apply: ME-GIS asks users to request permission before use, and the licence of the Arda DEM and vectors is uncertain.
  • Renders (docs/images/) show terrain derived from that data. They are not covered by the MIT licence and no reuse licence is granted; they are here to illustrate the project.
  • The film and its score (the rendered picture and audio, not the code that makes them) are project renders and recordings. They are not covered by the MIT licence and no reuse licence is granted. The film is published on YouTube; neither its files nor the score are part of this repository.

Disclaimer

A non-commercial fan project. It is not affiliated with or endorsed by the Tolkien Estate, Middle-earth Enterprises, HarperCollins, New Line Cinema, Warner Bros., Wētā Workshop, or any data author, font designer or artist credited in CREDITS.md. The Lord of the Rings, The Hobbit and Middle-earth are trademarks of their respective owners. The project contains no film footage, artwork, logos or typography from the films, no Tengwar or Cirth, and its music is original.

cinematic
computer-graphics
deterministic
diorama
fan-project
fantasy-map
gis
heightmap
lord-of-the-rings
middle-earth
miniature
offline-rendering
procedural-generation
terrain-rendering
threejs
tolkien
tsl
typescript
vite
webgpu