procedural-art · two Claude skills · no image model

Ararat & other mountains

Every picture here was computed. Real elevation data, a perspective camera and a few thousand lines of Python produce the line engravings; a ray marcher with a physical sky produces the photographs; a path tracer written from scratch produces the glass. No generative image model touched any pixel. Two Claude skills package all of it, so you can point them at any mountain on Earth.

Try any mountain →type a peak, pick a style, save a header. Runs in your browser.

Print styles
6
Landforms tested
7
Lines of Python + JS
~6,500
Image models used
0
Plate I

One mountain, six prints

Masis and Sis, as seen from Yerevan. The same elevation grid and the same hidden-line buffer feed every style; only the drawing changes.

39.7019° N 44.2986° E
Masis 5137 m · Sis 3896 m
view from Yerevan, 58 km
3000 × 1000 · 5–15 s per style
Ararat in the survey style: engraved ridgelines on parchment with an orange sun in the saddle
render.py --style survey · engraved ridgelines, sun in the saddleSave image
Plate II

Any landform

Before drawing, the engine measures the ground around the summit: how steep the peak is for its footprint, what stands in front of it, how rough it is, whether the target sits below a plateau. Cones keep the original framing; horns, ranges and canyons get their own.

Plate II · detail

The Matterhorn fix

The first engine treated every mountain like Ararat, so the Matterhorn drowned in its own massif. Drag across the plate to compare.

base 1429 → 2441 m
scene half-width 30.7 → 10.8 km
camera 3.4 → 2.0 · relief ×1.1
Fuji, Ararat, Mauna Kea: 0/255 pixel change
Matterhorn with landform-aware framing: the horn fills the frame, sun in open sky Matterhorn with the old cone framing: jagged ridges and a buried sun
Cone rulesLandform-aware
Plate III

Toward a photograph

The same elevation, ray-marched through a physical atmosphere: Rayleigh and Mie scattering, soft terrain shadows, valley mist, a lenticular cloud with multiple scattering. Lakes reflect the terrain with Fresnel and ripple normals; trees, villages and city lights are instanced near the camera.

sky: 28 samples / ray
shadows: 70-step march to the sun
3000 × 1000: 3–12 min on one core
resumable in row bands
Photographic render of Mount Fuji reflected in Lake Kawaguchi with a lenticular cloud and shoreline forest
Fuji across Lake Kawaguchi · --water-level auto --waves 0.12 --trees 0.8 · camera 4 m above the waterSave image
Photographic render of Ararat at golden hour with haze and a lenticular cloud
Ararat from the plain · golden hour, sun placed to light the faces the camera seesSave image
A dirt lane past a stone-walled house, orchards and poplar rows, with Ararat and Little Ararat behind
A village lane on the Ararat plain · camera 3 m up, house 60 m away · --trees 0.8 --villages 0.7 --cam-height 0.003Save image
Ararat behind orchards, poplar rows and villages
Orchards and villages · --trees 0.8 --villages 0.7Save
Ararat as a dark silhouette at blue hour above the street lights of Yerevan
Yerevan at blue hour · lamps on the real streets (© OpenStreetMap contributors) · --sun-el -5 --city 0.8Save
Sunset into blue hour over Yerevan · real sun path for 3 December, 16:55–18:10 · every frame rendered, so shadows move · timelapse.py
The same evening, 4:5 for phones · --layout center --hfov 10.5
Plate IV

Glass, from scratch

A Monte Carlo path tracer in plain numpy. Scenes are small JSON files: spheres, boxes, prisms, cut gems, hollow glasses with liquid in them. Light is sampled two ways and weighted, so glass and copper clean up many times faster than the first version.

glass to RMSE 0.04: 121 s → 18 s
copper: 126 s → 10 s
table caustic: 86 s → 35 s
spectral dispersion via Abbe number
Path-traced prism splitting a window's sunlight into a rainbow on linen, with a crystal ball and cut gems
Prism and crystal · scenes/prism_and_crystal.json · 60 samples / pixelSave image
Path-traced wine glass, water tumbler, crystal ball and coloured marbles casting coloured caustic shadows
Wine and marbles · ~70 sppSave
Path-traced crystal ball, glass of pomegranate juice, pomegranates and a copper sphere
Pomegranates · the first sceneSave
Plate V

Then paint it

A stroke renderer turns any image into a painting. Big brushes block in, small ones follow the contours of the picture where it still differs; watercolour is built from transparent washes with wet edges and granulation instead.

oil 3000 × 1000: ~50 s
watercolour: ~20 s
presets: oil, impasto, gouache, watercolour, ink
works on photos too
The Fuji lake render painted as a watercolour The Fuji lake render
RenderWatercolour
Ararat painted in sumi-e ink wash
Ararat · --style inkSave
The pomegranate still life painted with thick impasto strokes
Still life · --style impastoSave
Try it

Studios in your browser

Each studio is one HTML file with a 512 × 512 elevation grid inside it. Orbit the mountain, move the light, change the ink, and save a 3000 × 1000 PNG. No server, no install.

Try any mountain

Or skip the file: the Any mountain page runs the same engine on any peak you type, fetching the elevation as you go.

about 0.76 MB each
Canvas 2D, no libraries
built by build_studio.py
Plate VI

How it works

Two pipelines share one data source. Both skills ship the same dem.py.

Prints

elevation tilesterrarium PNG → metres view-aligned gridrows away from the viewer floating horizonhide what's behind G-bufferrow that owns each pixel survey · stipple · nocturne topo: true contours riso: two inks, halftone woodcut: carved mass

Rows are projected near to far; a point is drawn only if it rises above everything drawn before it in its column. The buffer that remembers which row owns each pixel lets every style sample height, shade and snow per pixel.

Photographs

heightfield40 m grid, Earth curve ray marchup to 900 steps sun shadowsoft, 70 steps atmosphereRayleigh + Mie, mist, clouds near fieldwater, trees, villages, lights postACES tone map, grain, bokeh paint.py (optional)oil · watercolour · ink

Each pixel's ray walks the heightfield until it hits ground, then asks the sky how much light reaches that point and how much air sits between it and the camera. Everything is resumable in row bands, so a slow render survives a time-limited shell.

Colophon

Make your own

Both skills are plain folders of Python and Markdown. Install them in Claude and ask for a mountain.

Python 3 · numpy · scipy
pillow · matplotlib · contourpy
ffmpeg for video
no API keys

procedural-terrain-art

Any real mountain in six print styles, orbit videos, and a self-contained interactive studio page.

  • headers and banners at the right sizes
  • labels in the local script
  • landform-aware framing

procedural-realism

Photographic terrain with lakes, forests, villages and night lights, sun timelapses, a JSON-driven path tracer, and a painterly finisher.

  • real sun paths by date and time
  • glass, metal, liquids, dispersion
  • paint any image, including photos

Claude Code

/plugin marketplace add dogum/procedural-art
/plugin install procedural-art@procedural-art

Claude.ai and Cowork

  1. Download both .skill files above.
  2. Settings → Capabilities → Skills → upload each one.

Then ask

  1. “A woodcut X header of Mount Hood from Portland.”
  2. “Mont Blanc reflected in Lac Blanc at golden hour, no image model.”
  3. “Turn this photo into a watercolour.”