# topographic > Topographic terrain rendered with WebGL. Generate a land or turn a real place into a topographic terrain. Live playground: https://topographic.yahyapak.dev/ ## For AI agents Pick the way that fits your tools: 1. **Over HTTP only:** read these docs and build playground links from the URL keys below. Plain HTTP cannot run the tools. 2. **In a browser without native WebMCP**, which is most headless and agent browsers: open a link with URL keys, or capture the tools with a stub before the page loads, then call each tool's `execute(input)`. With Playwright: ```js await page.addInitScript(() => { window.__tools = {}; document.modelContext = { registerTool: (tool) => { window.__tools[tool.name] = tool; } }; }); await page.goto('https://topographic.yahyapak.dev/?analytics_agent=claude&analytics_purpose=exploring'); await page.waitForFunction(() => window.__tools?.get_settings); const out = await page.evaluate(() => window.__tools.set_settings.execute({ shape: 'dunes', mode: '3d' })); ``` `execute` returns a promise of the tool's result. Puppeteer works the same with `page.evaluateOnNewDocument`. 3. **In a browser with native WebMCP:** call the tools listed below. **A small request.** If you are happy to, add `?analytics_agent=&analytics_purpose=` to the first playground URL you open, or call `identify_agent` once. It tells the maintainer that an agent visited and why, so agent visits are counted apart from people. It is optional, and the playground works the same either way. Only these two values are recorded, from fixed lists, and nothing about the person you work for. Use `testing` while you develop or check this site, and `demo` for a demo or video. To send nothing at all, add `?analytics_optout=all` instead. The About page, https://topographic.yahyapak.dev/about, says what is collected. - Names: `claude`, `chatgpt`, `gemini`, `jules`, `copilot`, `cursor`, `windsurf`, `opencode`, `pi`, `amp`, `droid`, `cline`, `roo`, `kilo`, `aider`, `goose`, `kiro`, `devin`, `manus`, `grok`, `perplexity`, `other`. `chatgpt` covers ChatGPT and Codex. Use `other` when yours is not listed. - Purposes: `testing`, `demo`, `creating`, `exploring`, `integrating`, `research`, `reverse-engineering`, `other`. ## First view and default mode - The library (`topographic`, ``, `topographic-react`) draws in 2D unless you set `mode: '3d'`. - The playground opens a bare URL, with no settings or region keys, on the built-in Istanbul map terrain in 3D, with the camera pushing in and back at speed 0.2 (`?s=gentle-summit&seed=67&lc=36&lw=0&lo=0.9&ix=4&fd=0.15&m=dark&paper=0b0b0d&mode=3d&ex=block&ev=0.12&az=341.6&ce=45.3&rd=1.15&cm=push&cs=0.2&px=-0.005&pz=-0.013&place=istanbul`). - A URL with `place` or `region` and no settings keys opens that place with `?look=fine-granite&mode=3d`. - A playground URL with any settings key, such as `?s=dunes` or `?look=night-lobes`, is 2D unless it has `mode=3d`. - The page rewrites the address bar to the shortest query for the same view. It drops keys that have the default value, so `?s=dunes&mode=2d` becomes `?s=dunes`, and the view stays 2D. ## URL state The playground keeps its state in short query params. It writes only the values that differ from a base: the shape's defaults, or a library look by id such as `look=night-lobes` (the ids in [params.md](docs/params.md) > Looks). Other params override the look's values. Examples: - `?s=dunes&lc=24` - `?look=night-lobes&mode=3d&cm=orbit` - `?s=gentle-summit&seed=4&m=dark&ink=9fb0cc&paper=0b0b0d` ### Keys - `look`: a look id. Links made before 0.6.0 use the same ids. - `s`: shape. - `seed`: seed - `lc`: line count - `lw`: line width - `lo`: line opacity - `ix`: bold line every - `pk`: peaks - `sp`: spread - `rg`: roughness - `sh`: sharpness - `tr`: terracing - `va`: variant - `sd`: speed - `wp`: warp - `sk`: sparkle - `an`: anchor - `fd`: centre fade - `m`: theme, light, dark or auto - `ink`, `paper`: colours, as hex without `#` - `mode`: `3d` or `2d`; only `3d` is written, because 2D is the default once any settings key is set - `ex`: extent; only `block` is written, endless is the default - `ev`: elevation - `dl`: detail - `ql`: quality; only `low`, `medium` or `high` is written, auto is the default - `az`, `ce`, `rd`: camera azimuth, elevation and radius - `cm`: camera motion - `px`, `pz`: pan, written only when off centre The library's default camera is not written: azimuth 349.7, elevation 33.6, radius 1.92. The page updates the URL a few times a second at most, and again when a drag or pinch ends. ## Real places - **A box:** `?region=west,south,east,north`, or JSON `{"bbox":[west,south,east,north]}`. - **A named place:** `place=istanbul`, `place=cyprus`, `place=matterhorn`, `place=geirangerfjord`, `place=grand-canyon`, `place=yosemite`, `place=torres-del-paine`, `place=fuji`, `place=everest`, `place=kilimanjaro`, or one of the Map menu's other places: `mont-blanc` (Mont Blanc), `dolomites` (The Dolomites), `etna` (Mount Etna), `naples-vesuvius` (Naples & Vesuvius), `grossglockner` (Grossglockner), `triglav` (Triglav & the Julian Alps), `high-tatras` (High Tatras), `bay-of-kotor` (Bay of Kotor), `santorini` (Santorini), `teide` (Tenerife & Teide), `madeira` (Madeira), `skye` (Isle of Skye), `faroe-islands` (Faroe Islands), `lofoten` (Lofoten), `elbrus` (Mount Elbrus), `ararat` (Mount Ararat), `dead-sea` (Dead Sea), `wadi-rum` (Wadi Rum), `damavand` (Mount Damavand), `musandam` (Musandam), `socotra` (Socotra), `ngorongoro` (Ngorongoro Crater), `mount-kenya` (Mount Kenya), `rwenzori` (Rwenzori Mountains), `virunga` (Virunga Volcanoes), `simien` (Simien Mountains), `toubkal` (Toubkal & the High Atlas), `hoggar` (Hoggar Mountains), `tibesti` (Emi Koussi, Tibesti), `reunion` (Réunion), `drakensberg` (Drakensberg Amphitheatre), `cape-town` (Cape Town & Table Mountain), `sossusvlei` (Sossusvlei), `annapurna` (Annapurna Sanctuary), `k2` (K2 & the Baltoro), `nanda-devi` (Nanda Devi), `tiger-leaping-gorge` (Tiger Leaping Gorge), `guilin-yangshuo` (Guilin & Yangshuo), `hong-kong` (Hong Kong), `taroko` (Taroko Gorge), `jeju` (Jeju & Hallasan), `halong-bay` (Hạ Long Bay), `kinabalu` (Mount Kinabalu), `bromo-semeru` (Bromo & Semeru), `mayon` (Mayon Volcano), `klyuchevskaya` (Klyuchevskaya Sopka), `khan-tengri` (Khan Tengri), `ismoil-somoni` (Ismoil Somoni Peak), `aoraki` (Aoraki / Mount Cook), `milford-sound` (Milford Sound), `tongariro` (Tongariro), `uluru` (Uluru & Kata Tjuta), `blue-mountains` (Blue Mountains), `lord-howe` (Lord Howe Island), `puncak-jaya` (Puncak Jaya), `bora-bora` (Bora Bora), `mauna-kea` (Mauna Kea & Mauna Loa), `kauai` (Kauaʻi), `rapa-nui` (Rapa Nui), `denali` (Denali), `mount-rainier` (Mount Rainier), `crater-lake` (Crater Lake), `grand-teton` (Grand Teton), `death-valley` (Death Valley), `banff` (Lake Louise & Moraine Lake), `vancouver` (Vancouver & Howe Sound), `copper-canyon` (Copper Canyon), `popocatepetl` (Popocatépetl & Iztaccíhuatl), `atitlan` (Lake Atitlán), `pitons` (The Pitons), `fitz-roy` (Fitz Roy & Cerro Torre), `perito-moreno` (Perito Moreno Glacier), `aconcagua` (Aconcagua), `ushuaia` (Ushuaia & the Beagle Channel), `licancabur` (Licancabur & the Atacama), `la-paz` (La Paz & Illimani), `titicaca` (Lake Titicaca), `machu-picchu` (Machu Picchu), `colca-canyon` (Colca Canyon), `cordillera-blanca` (Huascarán & the Cordillera Blanca), `cotopaxi` (Cotopaxi), `galapagos` (Isabela & Fernandina), `santa-marta` (Sierra Nevada de Santa Marta), `roraima` (Mount Roraima), `auyan-tepui` (Auyán-tepui & Angel Falls), `rio-de-janeiro` (Rio de Janeiro), `dry-valleys` (McMurdo Dry Valleys), `mount-erebus` (Mount Erebus), `vinson` (Vinson Massif), `lemaire-channel` (Lemaire Channel), `deception-island` (Deception Island), `south-georgia` (South Georgia), `vatnajokull` (Vatnajökull), `eyjafjallajokull` (Eyjafjallajökull & Mýrdalsjökull), `svalbard` (Isfjorden, Svalbard), `ilulissat` (Ilulissat Icefjord), `scoresby-sund` (Scoresby Sund), `mount-thor` (Mount Thor, Baffin Island). - **With settings:** place params combine with the others, such as `?look=night-lobes&lc=40&place=istanbul`. While the heights load, the page sets `data-loading=terrain` and hides the default terrain, and `get_region` returns `loading: true` with the message `Loading terrain`. ## Controls - **3D:** drag to pan; right drag, or Shift, ⌘ or Ctrl with a drag, to turn; scroll to zoom; double-click to recentre. - **2D:** a horizontal drag changes `layout.anchor`. 0 keeps the summit to the side, and 1 centres it. ## Page - **Dock:** terrain previews, with a chevron that scrolls to the next one. - **Theme and colours:** theme, shuffle and the two colours sit in a 2×2 grid. - **Link tab:** shows a labelled still of the terrain the link opens. - **Share image:** `og.png`, Everest in 3D beside the headline and the code that draws it, with `twitter:card` set to `summary_large_image`. The docs page uses `og-docs.png`. ## Packages - [topographic](https://www.npmjs.com/package/topographic): core and the `` web component - [topographic-react](https://www.npmjs.com/package/topographic-react): React component and hook ## Docs - [Install](docs/install.md) - [API](docs/api.md) - [Parameters, shapes and looks](docs/params.md) - [WebMCP tools](docs/webmcp.md) - [Everything in one file](llms-full.txt) ## WebMCP tools on the playground page - `identify_agent`: Optional. Tells this site an AI agent is using it, so agent use is counted apart from people. Only your agent's name and a purpose from the lists are recorded, as anonymous analytics; nothing about the person you work for. Call it once, if you like; the playground works the same either way. - `list_shapes` (read-only): Lists the shapes, with ids, names and descriptions, and the looks, with ids, names and settings. Pass a look id to set_settings as look. - `get_settings` (read-only): Returns the current settings: the full resolved object, the minimal config JSON (only non-default values), and the graphics tier actually drawing (quality, fps, frameMs, mesh). - `set_settings`: Changes the background. Takes a partial settings object; values are merged into the current settings, clamped to their ranges, and applied live. A new theme.mode clears the earlier ink and paper unless you give them in the same call, as the page's theme button does. Returns the resulting config and any adjustments made. - `randomize`: Picks a new random seed. With shape: true, also picks a random shape. - `take_screenshot` (read-only): Renders the current background to a PNG and returns it as a data URL. Defaults to 1200 px wide at the screen aspect ratio. With region, only that slice of the current view, at full detail (for example a phone-shaped strip). - `record_video` (read-only): Renders a short 3D clip of the current terrain with a moving camera. Returns an MP4 or WebM data URL. Defaults to a 2 second orbit at 640×360. - `get_embed_code` (read-only): Returns code that reproduces the current background: html (web component), react, vanilla (JS) or json (config). - `get_install_instructions` (read-only): Returns install and setup instructions for npm, the web component, React or vanilla JS. Place tools: - `set_region`: Sets the map region that becomes the terrain. Give place, an id from the Map menu's catalog of about 100 places (the ten built-in ones are istanbul, cyprus, matterhorn, geirangerfjord, grand-canyon, yosemite, torres-del-paine, fuji, everest, kilimanjaro; an unknown id returns the full list), or a bbox in degrees. The same values are written to the page URL as ?place= for a named place, or ?region= for a box. Like Apply in the Map popover, it switches to 3D with the map terrain view: 36 lines, width 0, opacity 0.9, an index line every 4, a block at elevation 0.12, and the camera at azimuth 341.8, elevation 39.3, radius 1.32, pushing in and back at speed 0.2. Every place but Istanbul and the cities brings its own camera angle and elevation. - `get_region` (read-only): Returns the current region, its height range, load status and the URL query. loading is true and message is "Loading terrain" while a shared place is still fetching, before the default terrain is shown. - `clear_region`: Removes the region and returns to the procedural terrain and to the lines, camera, extent and elevation from before the region. Details and input schemas: [docs/webmcp.md](docs/webmcp.md). ## Analytics The playground counts visits and tool use without cookies, and counts AI agents apart from people. Browsers run by automation, such as Playwright, count as agents by themselves. Identifying is optional; see "For AI agents" at the top of this file. ## Quick start ```html ``` --- # Install Topographic terrain rendered with WebGL. Generate a land or turn a real place into a topographic terrain. ```sh npm install topographic ``` ## Web component ```html ``` ## React ```sh npm install topographic topographic-react ``` ```tsx import { Topography } from 'topographic-react'; export function Hero() { return (

Hello

); } ``` ## Vanilla JS ```js import { createTopography } from 'topographic'; const topography = createTopography(document.querySelector('#hero'), { shape: 'gentle-summit', lines: { count: 36, indexEvery: 5 }, theme: { mode: 'dark' }, }); topography.update({ terrain: { peaks: 3 } }); // live, clamped const png = await topographic.snapshot({ width: 1920, height: 1080 }); topography.destroy(); ``` ## Colours ```css topographic-view { --topographic-ink: #9fb3c8; /* line colour */ --topographic-paper: transparent; /* let the page show through */ } ``` --- # API ## createTopography(element, settings?, options?) Mounts a canvas inside `element` (it fills the element) and returns an instance. - `settings`: partial settings, see [params.md](params.md). Fields: `{ look, shape, location, seed, lines, terrain, motion, layout, theme, mode, elevation, extent, detail, quality, camera }`. `mode` is `'2d' | '3d'` and defaults to `'2d'`. `quality` is `'auto' | 'low' | 'medium' | 'high'` and defaults to `'auto'`. `auto` starts a phone at low and a desktop at high, then steps down if presented frames miss 60 Hz, or 120 Hz once a frame under 12 ms has been seen. It does not step back up. - `options`: `{ maxPixelRatio = 2, maxPixels = 4147200, forceWebGL1 = false, benchmark = false }`. `benchmark` keeps a 3D view drawing while it is visible so `stats` can be read. Instance: - `update(partialSettings)`: merges, clamps and applies live. Only changed uniforms reach the GPU. - `snapshot({ frame?, width?, height?, region?, motion?, patch?, field? }) => Promise`: renders one PNG off-screen. `frame` is the animation time in ms. Give one side to keep the aspect ratio. `region` (`{ x, y, width, height }`, fractions from the top-left) keeps only that slice of the view, drawn at full detail. `motion` draws the 3D view along that camera path at its pose for `frame`, like that moment of `record`. `patch` and `field` draw this image from temporary settings and a temporary height grid, then put the live view back, so the page does not flash and a second WebGL context is not required. The live canvas is not resized. Rejects without WebGL. In 3D it includes the current camera. - `record({ seconds?, fps?, width?, height?, frame?, format?, motion? }) => Promise`: renders a 3D clip with a moving camera. `format` is `'mp4'` (default) or `'webm'`. `motion` is `orbit`, `push`, `flyover`, `drone` or `still`. The live canvas is not resized. Rejects without WebGL or when the browser cannot encode that format. - `setHeightfield({ samples, size, aspect } | null)`: draws your own height grid until the `location` setting changes. `null` brings back the generated terrain. - `setInsets({ top, right, bottom, left } | null)`: the space page UI covers on each side of the view, in CSS px. The 3D picture slides (a lens shift, not a camera move) so the terrain centres in the part left free. 2D, `snapshot` and `record` ignore it and centre in their own frame. `insets` reads it back. - `clampPan(panX, panZ) => [x, z]`: the pan kept over the terrain as it is drawn now. - `pose`: `{ azimuth, elevation, radius, panX, panZ }`, where the 3D camera is now along its path. - `stats`: `{ fps, frameMs, mesh, quality }` while a 3D view is drawing. `frameMs` is the time spent drawing one frame. `mesh` is the segments along one side, or 0 in 2D. `quality` is the tier actually drawing: `low`, `medium` or `high`. - `destroy()`: stops the loop, removes observers and the canvas, and releases the WebGL context. - `settings`: the current resolved settings. - `status`: `'webgl2' | 'webgl1' | 'fallback' | 'lost' | 'destroyed'`. - `canvas`: the canvas element. Behaviour: - Uses WebGL2, then WebGL1. Without either, or while the context is lost, the element shows the paper colour. A restored context resumes. If the browser never restores it, the canvas is replaced and the view comes back on its own. Drawing does not call `gl.finish`, and the backing store is left alone when a resize reports the same size. - `prefers-reduced-motion: reduce` renders a single still frame. - Animation pauses when the element is off-screen or the tab is hidden. - Pixel budget: `quality` caps the device pixel ratio, the pixel count and the mesh. `maxPixelRatio` and `maxPixels` are the ceiling above that. ## `import 'topographic/element'` registers the element. Attributes: `look`, `shape`, `location`, `seed`, `theme`, `ink`, `paper`, `mode`, `elevation`, `extent`, `detail`, `quality`, `azimuth`, `camera-elevation`, `radius`, `camera-motion`, `camera-speed`, `pan-x`, `pan-z`, plus one per numeric setting (see [params.md](params.md)). Attribute changes apply live, and a removed attribute returns to its default. `element.topographic` is the instance, and `element.snapshot(opts)` is a shortcut. ## React: and useTopography `` renders a div with the background, and children on top. It is SSR-safe: the server renders an empty div. `useTopography(settings, options)` returns a ref to put on any element. `ref.topographic` is the instance while mounted. ## topographic/locations `import { LOCATIONS, loadLocation, fetchLocation } from 'topographic/locations'`. - `LOCATIONS`: the built-in places, each `{ id, name, bbox, aspect, defaults }`. `defaults` is `{ camera: { azimuth, elevation, radius }, elevation, extent, lines, layout }`. - `istanbul`: Istanbul, west 28.45, south 40.78, east 29.65, north 41.36 - `cyprus`: Cyprus, west 32.07126, south 34.41845, east 34.93823, north 35.92088 - `matterhorn`: Matterhorn & Zermatt, west 7.441, south 45.883, east 7.959, north 46.117 - `geirangerfjord`: Geirangerfjord, west 6.474, south 61.925, east 7.626, north 62.275 - `grand-canyon`: Grand Canyon, west -112.434, south 35.945, east -111.766, north 36.295 - `yosemite`: Yosemite Valley, west -119.755, south 37.647, east -119.415, north 37.823 - `torres-del-paine`: Torres del Paine, west -73.478, south -51.175, east -72.622, north -50.825 - `fuji`: Mount Fuji, west 138.433, south 35.278, east 139.007, north 35.582 - `everest`: Everest, west 86.757, south 27.892, east 87.093, north 28.084 - `kilimanjaro`: Kilimanjaro, west 37, south -3.303, east 37.72, north -2.837 - `loadLocation(id) => Promise<{ samples, size, aspect, minMeters, maxMeters, zoom }>`: a built-in place's 256 × 256 grid. Each place is its own dynamic import of 35 to 150 KB (25 to 115 KB compressed), so a page downloads only the places it uses. The `location` setting calls it for you. - `fetchLocation({ west, south, east, north }, { relief?, smooth?, tiles?, signal? }) => Promise<{ samples, size, aspect, minMeters, maxMeters, zoom, tiles }>`: downloads Terrarium elevation tiles (AWS Open Data) for any area and makes the same 256 × 256 grid as the playground. The shorter side must be at least 1.5 km, the longer side at most 300 km, and the sides within 3:1. `relief` is `dramatic` (default) or `measured`; `smooth` is `light`, `medium` (default) or `strong`; `tiles` is a Terrarium URL template with `{z}`, `{x}` and `{y}`. Pass the result as `location`. - `decodeGrid16(bytes) => Promise<{ samples, size }>`: reads a grid saved as a square 16-bit greyscale PNG, north at the top, the format of the built-in places. - `areaProblem(bbox)` returns `'order' | 'small' | 'large' | 'aspect' | null`, and `areaSpan(bbox)` the size in metres. ## Helpers `resolveSettings`, `mergeSettings`, `toUniforms`, `fromAttributes`, `toAttributes`, `toQuery`, `fromQuery`, `parseColor`, `resolveTheme`, plus the data exports `PARAMS`, `SHAPES` and `LOOKS`, and `findLook(id)`. --- # Parameters Every setting, generated from `packages/core/src/params.ts`. Out-of-range values are clamped; integers are rounded. | Setting | Element attribute | Range | Default | What it does | |---|---|---|---|---| | `lines.count` | `line-count` | 6 to 60 (integer) | 30 | How many contour lines cross the field. | | `lines.width` | `line-width` | 0 to 1 | 0.26 | Stroke width of each contour line. | | `lines.opacity` | `line-opacity` | 0 to 1 | 0.4 | How strongly lines show against the paper. | | `lines.indexEvery` | `index-every` | 0 to 10 (integer) | 5 | Every Nth line is drawn bolder, like the index contours on a map. 0 turns it off. | | `terrain.peaks` | `peaks` | 1 to 6 (integer) | 1 | Number of summits merged into the terrain. | | `terrain.spread` | `spread` | 0 to 1 | 0.5 | How far extra peaks sit from the main summit. | | `terrain.roughness` | `roughness` | 0 to 1 | 0 | Noise added to the slopes, from smooth hills to rocky ground. | | `terrain.sharpness` | `sharpness` | 0 to 1 | 0.5 | Below 0.5 summits flatten; above 0.5 they sharpen into peaks. | | `terrain.terracing` | `terracing` | 0 to 1 | 0 | Groups lines into stepped bands. | | `terrain.variant` | `variant` | 0 to 1 | 0.5 | A knob that depends on the shape (for drifting lobes: three lobes to four). | | `motion.speed` | `speed` | 0 to 3 | 1 | Animation speed. 0 holds a still frame. | | `motion.warp` | `warp` | 0 to 1 | 0.47 | How much the lines wobble with the flow. | | `motion.sparkle` | `sparkle` | 0 to 1 | 0.6 | Small bright dots travelling along the lines. | | `layout.anchor` | `anchor` | 0 to 1 | 0 | 0 keeps the summit to the side, 1 centres it. | | `layout.fade` | `fade` | 0 to 1 | 0.7 | Fades lines behind a central text column. | Other settings: - `look` (attribute `look`, React prop `look`): one of the looks below, by id. It sets the shape, seed, groups, colours and camera pose. The other settings next to it override its values. An unknown look is ignored with one console warning. In `update()`, a look replaces the design and keeps the view: `mode`, `elevation`, `extent`, `detail`, `quality`, `view2d`, and the camera motion and pan. - `shape` (attribute `shape`, React prop `shape`): one of the shapes below. Unknown shapes fall back to `drifting-lobes` with one console warning. - `location` (attribute `location`, React prop `location`): a real place instead of the generated terrain. A built-in id (`istanbul`, `cyprus`, `matterhorn`, `geirangerfjord`, `grand-canyon`, `yosemite`, `torres-del-paine`, `fuji`, `everest`, `kilimanjaro`), or a height grid `{ samples, size, aspect }` such as one from `fetchLocation()`. A built-in id also sets `camera.azimuth`, `camera.elevation`, `camera.radius`, `elevation`, `extent: 'block'`, `lines` (`{ count: 36, width: 0, opacity: 0.9, indexEvery: 4 }`) and `layout.fade: 0.15`, under the values you set. It does not set `mode`. Default `null`, the generated terrain. Unknown ids fall back to `null` with one console warning. See [api.md](api.md). - `seed` (attribute `seed`): integer 0 to 999999. The same seed gives the same terrain; 0 is the original look. - `theme.mode` (attribute `theme`): `auto` (follows the OS), `light` or `dark`. - `theme.ink` / `theme.paper` (attributes `ink`, `paper`): any CSS colour; paper may be `transparent`. Without them, the CSS variables `--topographic-ink` and `--topographic-paper` are used, then the mode defaults. - `mode` (attribute `mode`): `2d` (the library default) or `3d`. The playground opens a bare URL on Istanbul in 3D; see llms.txt. 3D draws the same contour field as a terrain. The same seed gives the same map in both. - `elevation` (attribute `elevation`): 0 to 1, default 0.62. 3D height. 0 is flat like the 2D map; higher values make the terrain taller, with a rounded crest. - `extent` (attribute `extent`): `endless` (default) continues the terrain past the view. `block` is a finite tabletop whose cut sides carry thin ink layer lines. - `detail` (attribute `detail`): 0 to 1, default 0.5. Mesh resolution, from 32² to 160². Use a low value on a slow device. - `quality` (attribute `quality`): `auto` (default), `low`, `medium` or `high`. `auto` starts a phone at low and a desktop at high, then steps down if frames miss 60 Hz, or 120 Hz once that refresh has been seen. It does not step back up. The other values stay put. The tier caps the pixel ratio, the pixel count and the mesh size. - `camera.azimuth` (attribute `azimuth`): degrees around the terrain. Any finite number. Default 349.7. - `camera.elevation` (attribute `camera-elevation`): degrees above the horizon, 2 to 80. The camera never goes below the terrain. Default 33.6. - `camera.radius` (attribute `radius`): distance from the terrain centre, 0.4 to 6.5. Default 1.92. - `camera.motion` (attribute `camera-motion`): `still` (default), `orbit`, `push`, `flyover` or `drone`. The terrain's own `motion.speed` still morphs the field, so the two motions are independent. - `camera.speed` (attribute `camera-speed`): 0 to 3, default 1. How fast the camera moves along its path. 1 is the path's own pace, such as an orbit in about 26 seconds; 0 holds the camera. - `camera.panX` / `camera.panZ` (attributes `pan-x`, `pan-z`): where the camera looks, moved from the terrain centre across the ground (east and south), -6 to 6, default 0. The camera and every motion path turn around that point. The renderer keeps it over the terrain. ## Shapes | Id | Name | Description | |---|---|---| | `drifting-lobes` | Drifting lobes | Three soft lobes drifting off to the side, morphing towards four. | | `granite` | Granite | Many small lumpy lobes with a stone-grain tint. | | `five-petals` | Five petals | A breathing five-petal summit. | | `seed-pod` | Seed pod | Two long lobes slowly turning, like a seed pod. | | `gentle-summit` | Gentle summit | One soft, slightly oval hill leaning with the flow. | | `long-ridge` | Long ridge | A long winding ridge with rounded ends. | | `dunes` | Dunes | Long wind ripples with no summits. | ## Looks A look is a named, finished design. The order is the order of the playground's dock. `survey-map` and `rocky` set no colours, so they follow the page's theme. - `survey-ridge` (Survey ridge): `{"shape":"long-ridge","seed":113,"terrain":{"roughness":0.12},"lines":{"count":46,"indexEvery":5,"opacity":0.55,"width":0.12},"layout":{"fade":0.15},"theme":{"mode":"dark","paper":"#141414","ink":"#e8e6e1"},"camera":{"azimuth":349.7,"elevation":33.6,"radius":1.92}}` - `fine-granite` (Fine granite): `{"shape":"granite","seed":191,"lines":{"count":54,"width":0.1,"opacity":0.62},"layout":{"fade":0.15},"theme":{"mode":"dark","paper":"#0b0b0d","ink":"#d7d2c8"},"camera":{"azimuth":79.7,"elevation":30,"radius":1.92}}` - `wide-lobes` (Wide lobes): `{"shape":"drifting-lobes","seed":157,"terrain":{"peaks":3,"spread":0.75,"variant":0.4},"lines":{"count":30,"width":0.16},"layout":{"fade":0.15},"theme":{"mode":"dark","paper":"#12141a","ink":"#c9c2b4"},"camera":{"azimuth":79.7,"elevation":30,"radius":1.92}}` - `rose-pod` (Rose pod): `{"shape":"seed-pod","seed":71,"motion":{"speed":0.55},"lines":{"count":24,"width":0.18},"layout":{"fade":0.15},"theme":{"mode":"dark","paper":"#1a1214","ink":"#f0b2a8"},"camera":{"azimuth":294.7,"elevation":34,"radius":2.3}}` - `terraces` (Terraces): `{"shape":"gentle-summit","seed":131,"terrain":{"terracing":0.85,"peaks":2},"lines":{"count":36,"width":0.14},"layout":{"fade":0.15},"theme":{"mode":"dark","paper":"#16130f","ink":"#e0b089"},"camera":{"azimuth":294.7,"elevation":34,"radius":2.3}}` - `high-dunes` (High dunes): `{"shape":"dunes","seed":227,"terrain":{"roughness":0.35},"lines":{"count":40,"width":0.14},"layout":{"fade":0.15},"theme":{"mode":"dark","paper":"#101614","ink":"#c6d6a8"},"camera":{"azimuth":14.7,"elevation":34,"radius":1.92}}` - `moss-granite` (Moss granite): `{"shape":"granite","seed":53,"terrain":{"roughness":0.22},"lines":{"count":40,"width":0.14},"layout":{"fade":0.15},"theme":{"mode":"dark","paper":"#101614","ink":"#9dcec0"},"camera":{"azimuth":79.7,"elevation":30,"radius":1.92}}` - `sea-dunes` (Sea dunes): `{"shape":"dunes","seed":97,"lines":{"count":48,"width":0.12},"layout":{"fade":0.15},"theme":{"mode":"dark","paper":"#0e1a22","ink":"#8ec4d4"},"camera":{"azimuth":14.7,"elevation":34,"radius":1.92}}` - `night-flower` (Night flower): `{"shape":"five-petals","seed":179,"lines":{"count":44,"indexEvery":4,"width":0.12},"layout":{"fade":0.15},"theme":{"mode":"dark","paper":"#10151c","ink":"#a9c7e4"},"camera":{"azimuth":79.7,"elevation":30,"radius":1.92}}` - `night-lobes` (Night lobes): `{"shape":"drifting-lobes","seed":11,"terrain":{"variant":0.15},"lines":{"count":22,"width":0.18},"layout":{"fade":0.15},"theme":{"mode":"dark","paper":"#0b0b0d","ink":"#9fb0cc"},"camera":{"azimuth":294.7,"elevation":34,"radius":2.3}}` - `violet-pod` (Violet pod): `{"shape":"seed-pod","seed":211,"motion":{"warp":0.7},"lines":{"count":30,"width":0.16},"layout":{"fade":0.15},"theme":{"mode":"dark","paper":"#16131a","ink":"#b9a4e0"},"camera":{"azimuth":294.7,"elevation":34,"radius":2.3}}` - `ink-petals` (Ink petals): `{"shape":"five-petals","seed":37,"lines":{"count":26,"width":0.2},"layout":{"fade":0.15},"theme":{"mode":"dark","paper":"#16131a","ink":"#cbb6ea"},"camera":{"azimuth":79.7,"elevation":30,"radius":1.92}}` - `stepped-petals` (Stepped petals): `{"shape":"five-petals","seed":233,"terrain":{"terracing":0.72},"lines":{"count":28,"width":0.16},"layout":{"fade":0.15},"theme":{"mode":"light","paper":"#f6eef2","ink":"#6b3050"},"camera":{"azimuth":79.7,"elevation":30,"radius":1.92}}` - `day-lobes` (Day lobes): `{"shape":"drifting-lobes","seed":83,"terrain":{"variant":0.92},"lines":{"count":28,"width":0.16},"layout":{"fade":0.15},"theme":{"mode":"light","paper":"#f6eef2","ink":"#5c3348"},"camera":{"azimuth":294.7,"elevation":34,"radius":2.3}}` - `still-dunes` (Still dunes): `{"shape":"dunes","seed":163,"motion":{"speed":0},"lines":{"count":26,"width":0.14},"layout":{"fade":0.15},"theme":{"mode":"light","paper":"#f3ece4","ink":"#7a3e2e"},"camera":{"azimuth":14.7,"elevation":34,"radius":1.92}}` - `rocky-spine` (Rocky spine): `{"shape":"long-ridge","seed":181,"terrain":{"roughness":0.62,"sharpness":0.22},"lines":{"count":34,"width":0.18},"layout":{"fade":0.15},"theme":{"mode":"light","paper":"#efe6d6","ink":"#5c3a28"},"camera":{"azimuth":324.7,"elevation":34,"radius":1.92}}` - `pale-dunes` (Pale dunes): `{"shape":"dunes","seed":23,"lines":{"count":34,"width":0.16},"layout":{"fade":0.15},"theme":{"mode":"light","paper":"#efe6d6","ink":"#6b4630"},"camera":{"azimuth":14.7,"elevation":34,"radius":1.92}}` - `stone-grain` (Stone grain): `{"shape":"granite","seed":127,"terrain":{"roughness":0.5},"lines":{"count":32,"width":0.16},"layout":{"fade":0.15},"theme":{"mode":"light","paper":"#e7e2d8","ink":"#3a342c"},"camera":{"azimuth":79.7,"elevation":30,"radius":1.92}}` - `open-pod` (Open pod): `{"shape":"seed-pod","seed":149,"lines":{"count":20,"width":0.16},"layout":{"fade":0.15,"anchor":1},"theme":{"mode":"light","paper":"#f4f1ea","ink":"#2c2c2a"},"camera":{"azimuth":349.7,"elevation":38,"radius":1.92}}` - `quiet-hill` (Quiet hill): `{"shape":"gentle-summit","seed":197,"lines":{"count":14,"width":0.14},"layout":{"fade":0.05},"theme":{"mode":"light","paper":"#f7f4ee","ink":"#2c2c2a"},"camera":{"azimuth":294.7,"elevation":34,"radius":2.3}}` - `bloom` (Bloom): `{"shape":"five-petals","seed":101,"terrain":{"terracing":0.45},"lines":{"count":20,"width":0.18},"layout":{"fade":0.15},"theme":{"mode":"light","paper":"#f3efe6","ink":"#3c4a36"},"camera":{"azimuth":79.7,"elevation":30,"radius":1.92}}` - `soft-summit` (Soft summit): `{"shape":"gentle-summit","seed":67,"lines":{"count":16,"width":0.16},"layout":{"fade":0.15},"theme":{"mode":"light","paper":"#e5eef0","ink":"#1e4650"},"camera":{"azimuth":294.7,"elevation":34,"radius":2.3}}` - `paper-ridge` (Paper ridge): `{"shape":"long-ridge","seed":41,"terrain":{"sharpness":0.35},"lines":{"count":22,"width":0.16},"layout":{"fade":0.15},"theme":{"mode":"light","paper":"#f7f4ee","ink":"#3d4c63"},"camera":{"azimuth":324.7,"elevation":34,"radius":1.92}}` - `centred-lobes` (Centred lobes): `{"shape":"drifting-lobes","seed":223,"terrain":{"variant":0.55},"lines":{"count":24,"width":0.16},"layout":{"fade":0.15,"anchor":1},"theme":{"mode":"light","paper":"#e7eef6","ink":"#243656"},"camera":{"azimuth":349.7,"elevation":38,"radius":1.92}}` - `survey-map` (Survey map): `{"shape":"gentle-summit","lines":{"count":44,"indexEvery":5,"opacity":0.55},"terrain":{"peaks":3,"spread":0.6,"roughness":0.2},"motion":{"speed":0.4,"sparkle":0},"camera":{"azimuth":294.7,"elevation":34,"radius":2.3}}` - `rocky` (Rocky): `{"shape":"long-ridge","terrain":{"roughness":0.55,"sharpness":0.3},"lines":{"count":36},"camera":{"azimuth":324.7,"elevation":34,"radius":1.92}}` --- # WebMCP tools In browsers that support [WebMCP](https://github.com/webmachinelearning/webmcp), the playground page registers these tools with `document.modelContext.registerTool()`. Older builds that expose `navigator.modelContext` are used as a fallback. Without either, nothing is registered and the page works as normal. ## For AI agents Pick the way that fits your tools: 1. **Over HTTP only:** read these docs and build playground links from the URL keys below. Plain HTTP cannot run the tools. 2. **In a browser without native WebMCP**, which is most headless and agent browsers: open a link with URL keys, or capture the tools with a stub before the page loads, then call each tool's `execute(input)`. With Playwright: ```js await page.addInitScript(() => { window.__tools = {}; document.modelContext = { registerTool: (tool) => { window.__tools[tool.name] = tool; } }; }); await page.goto('https://topographic.yahyapak.dev/?analytics_agent=claude&analytics_purpose=exploring'); await page.waitForFunction(() => window.__tools?.get_settings); const out = await page.evaluate(() => window.__tools.set_settings.execute({ shape: 'dunes', mode: '3d' })); ``` `execute` returns a promise of the tool's result. Puppeteer works the same with `page.evaluateOnNewDocument`. 3. **In a browser with native WebMCP:** call the tools listed below. **A small request.** If you are happy to, add `?analytics_agent=&analytics_purpose=` to the first playground URL you open, or call `identify_agent` once. It tells the maintainer that an agent visited and why, so agent visits are counted apart from people. It is optional, and the playground works the same either way. Only these two values are recorded, from fixed lists, and nothing about the person you work for. Use `testing` while you develop or check this site, and `demo` for a demo or video. To send nothing at all, add `?analytics_optout=all` instead. The About page, https://topographic.yahyapak.dev/about, says what is collected. - Names: `claude`, `chatgpt`, `gemini`, `jules`, `copilot`, `cursor`, `windsurf`, `opencode`, `pi`, `amp`, `droid`, `cline`, `roo`, `kilo`, `aider`, `goose`, `kiro`, `devin`, `manus`, `grok`, `perplexity`, `other`. `chatgpt` covers ChatGPT and Codex. Use `other` when yours is not listed. - Purposes: `testing`, `demo`, `creating`, `exploring`, `integrating`, `research`, `reverse-engineering`, `other`. Written against the spec at webmachinelearning/webmcp commit `d0e4e0e0f039358cc9d93f90074116622bfebd53` (https://github.com/webmachinelearning/webmcp/blob/d0e4e0e0f039358cc9d93f90074116622bfebd53/index.bs). Tools are removed by aborting their registration `AbortSignal`, and read-only tools set `annotations.readOnlyHint`. - `identify_agent`: Optional. Tells this site an AI agent is using it, so agent use is counted apart from people. Only your agent's name and a purpose from the lists are recorded, as anonymous analytics; nothing about the person you work for. Call it once, if you like; the playground works the same either way. - `list_shapes` (read-only): Lists the shapes, with ids, names and descriptions, and the looks, with ids, names and settings. Pass a look id to set_settings as look. - `get_settings` (read-only): Returns the current settings: the full resolved object, the minimal config JSON (only non-default values), and the graphics tier actually drawing (quality, fps, frameMs, mesh). - `set_settings`: Changes the background. Takes a partial settings object; values are merged into the current settings, clamped to their ranges, and applied live. A new theme.mode clears the earlier ink and paper unless you give them in the same call, as the page's theme button does. Returns the resulting config and any adjustments made. - `randomize`: Picks a new random seed. With shape: true, also picks a random shape. - `take_screenshot` (read-only): Renders the current background to a PNG and returns it as a data URL. Defaults to 1200 px wide at the screen aspect ratio. With region, only that slice of the current view, at full detail (for example a phone-shaped strip). - `record_video` (read-only): Renders a short 3D clip of the current terrain with a moving camera. Returns an MP4 or WebM data URL. Defaults to a 2 second orbit at 640×360. - `get_embed_code` (read-only): Returns code that reproduces the current background: html (web component), react, vanilla (JS) or json (config). - `get_install_instructions` (read-only): Returns install and setup instructions for npm, the web component, React or vanilla JS. ## Input schemas ### identify_agent ```json { "type": "object", "additionalProperties": false, "required": [ "name", "purpose" ], "properties": { "name": { "type": "string", "enum": [ "claude", "chatgpt", "gemini", "jules", "copilot", "cursor", "windsurf", "opencode", "pi", "amp", "droid", "cline", "roo", "kilo", "aider", "goose", "kiro", "devin", "manus", "grok", "perplexity", "other" ], "description": "Your agent or harness. chatgpt covers ChatGPT and Codex. Use other when yours is not listed." }, "purpose": { "type": "string", "enum": [ "testing", "demo", "creating", "exploring", "integrating", "research", "reverse-engineering", "other" ], "description": "testing: developing or checking this site. demo: recording a demo, video or screenshots of topographic. creating: making a background, image, video or 3D view for someone. exploring: trying styles, places and settings. integrating: getting code to embed in a site or app. research: evaluating or comparing tools. reverse-engineering: studying how the playground or the library is built. other: anything else." } } } ``` ### list_shapes ```json { "type": "object", "properties": {} } ``` ### get_settings ```json { "type": "object", "properties": {} } ``` ### set_settings ```json { "type": "object", "additionalProperties": false, "properties": { "look": { "type": "string", "enum": [ "survey-ridge", "fine-granite", "wide-lobes", "rose-pod", "terraces", "high-dunes", "moss-granite", "sea-dunes", "night-flower", "night-lobes", "violet-pod", "ink-petals", "stepped-petals", "day-lobes", "still-dunes", "rocky-spine", "pale-dunes", "stone-grain", "open-pod", "quiet-hill", "bloom", "soft-summit", "paper-ridge", "centred-lobes", "survey-map", "rocky" ], "description": "A named design from list_shapes. It sets the shape, seed, lines, terrain, motion, layout, colours and camera pose, and keeps the view. The other keys in the same call override its values." }, "shape": { "type": "string", "enum": [ "drifting-lobes", "granite", "five-petals", "seed-pod", "gentle-summit", "long-ridge", "dunes" ], "description": "The land shape of the procedural terrain." }, "style": { "type": "string", "enum": [ "drifting-lobes", "granite", "five-petals", "seed-pod", "gentle-summit", "long-ridge", "dunes" ], "description": "Old name of shape, accepted until the next release. Use shape." }, "seed": { "type": "integer", "minimum": 0, "maximum": 999999, "description": "Same seed, same terrain. 0 is the original look." }, "lines": { "type": "object", "additionalProperties": false, "properties": { "count": { "type": "integer", "minimum": 6, "maximum": 60, "description": "How many contour lines cross the field." }, "width": { "type": "number", "minimum": 0, "maximum": 1, "description": "Stroke width of each contour line." }, "opacity": { "type": "number", "minimum": 0, "maximum": 1, "description": "How strongly lines show against the paper." }, "indexEvery": { "type": "integer", "minimum": 0, "maximum": 10, "description": "Every Nth line is drawn bolder, like the index contours on a map. 0 turns it off." } } }, "terrain": { "type": "object", "additionalProperties": false, "properties": { "peaks": { "type": "integer", "minimum": 1, "maximum": 6, "description": "Number of summits merged into the terrain." }, "spread": { "type": "number", "minimum": 0, "maximum": 1, "description": "How far extra peaks sit from the main summit." }, "roughness": { "type": "number", "minimum": 0, "maximum": 1, "description": "Noise added to the slopes, from smooth hills to rocky ground." }, "sharpness": { "type": "number", "minimum": 0, "maximum": 1, "description": "Below 0.5 summits flatten; above 0.5 they sharpen into peaks." }, "terracing": { "type": "number", "minimum": 0, "maximum": 1, "description": "Groups lines into stepped bands." }, "variant": { "type": "number", "minimum": 0, "maximum": 1, "description": "A knob that depends on the shape (for drifting lobes: three lobes to four)." } } }, "motion": { "type": "object", "additionalProperties": false, "properties": { "speed": { "type": "number", "minimum": 0, "maximum": 3, "description": "Animation speed. 0 holds a still frame." }, "warp": { "type": "number", "minimum": 0, "maximum": 1, "description": "How much the lines wobble with the flow." }, "sparkle": { "type": "number", "minimum": 0, "maximum": 1, "description": "Small bright dots travelling along the lines." } } }, "layout": { "type": "object", "additionalProperties": false, "properties": { "anchor": { "type": "number", "minimum": 0, "maximum": 1, "description": "0 keeps the summit to the side, 1 centres it." }, "fade": { "type": "number", "minimum": 0, "maximum": 1, "description": "Fades lines behind a central text column." } } }, "theme": { "type": "object", "additionalProperties": false, "properties": { "mode": { "type": "string", "enum": [ "auto", "light", "dark" ] }, "ink": { "type": "string", "description": "CSS colour of the lines." }, "paper": { "type": "string", "description": "CSS colour of the background, or 'transparent'." } } }, "mode": { "type": "string", "enum": [ "2d", "3d" ], "description": "2d is the map. 3d is the same map as a terrain. The library defaults to 2d; the playground opens a bare URL on Istanbul in 3d." }, "elevation": { "type": "number", "minimum": 0, "maximum": 1, "description": "3D height. 0 is flat like the map; higher values make the terrain taller, with a rounded crest." }, "extent": { "type": "string", "enum": [ "block", "endless" ], "description": "block is a finite tabletop with cut sides. endless continues past the view. The playground defaults to endless." }, "detail": { "type": "number", "minimum": 0, "maximum": 1, "description": "3D mesh resolution. 0 is coarsest, 1 is finest." }, "quality": { "type": "string", "enum": [ "auto", "low", "medium", "high" ], "description": "Graphics budget. auto follows the device and steps down if frames miss 60 Hz, or 120 Hz when that refresh is seen. low, medium and high stay put." }, "camera": { "type": "object", "additionalProperties": false, "properties": { "azimuth": { "type": "number", "description": "Degrees around the terrain. Any finite number." }, "elevation": { "type": "number", "minimum": 2, "maximum": 80, "description": "Degrees above the horizon. Never below the terrain." }, "radius": { "type": "number", "minimum": 0.4, "maximum": 6.5, "description": "Distance from the terrain centre." }, "motion": { "type": "string", "enum": [ "still", "orbit", "push", "flyover", "drone" ], "description": "How the camera moves. still holds the pose." }, "speed": { "type": "number", "minimum": 0, "maximum": 3, "description": "How fast the camera moves along its path. 1 is the path's own pace, such as an orbit in about 26 seconds; 0 holds it." }, "panX": { "type": "number", "minimum": -6, "maximum": 6, "description": "Moves the point the camera looks at east across the ground. 0 is the terrain centre; kept over the terrain." }, "panZ": { "type": "number", "minimum": -6, "maximum": 6, "description": "Moves the point the camera looks at south across the ground. 0 is the terrain centre; kept over the terrain." } } } } } ``` ### randomize ```json { "type": "object", "properties": { "shape": { "type": "boolean", "description": "Also randomize the shape." } } } ``` ### take_screenshot ```json { "type": "object", "properties": { "width": { "type": "integer", "minimum": 16, "maximum": 4096 }, "height": { "type": "integer", "minimum": 16, "maximum": 4096 }, "region": { "type": "object", "additionalProperties": false, "description": "Part of the view, in fractions 0..1 from its top-left corner. Width or height alone keeps the region's shape.", "properties": { "x": { "type": "number", "minimum": 0, "maximum": 1 }, "y": { "type": "number", "minimum": 0, "maximum": 1 }, "width": { "type": "number", "minimum": 0, "maximum": 1 }, "height": { "type": "number", "minimum": 0, "maximum": 1 } }, "required": [ "x", "y", "width", "height" ] } } } ``` ### record_video ```json { "type": "object", "properties": { "format": { "type": "string", "enum": [ "mp4", "webm" ] }, "motion": { "type": "string", "enum": [ "still", "orbit", "push", "flyover", "drone" ] }, "seconds": { "type": "number", "minimum": 0.5, "maximum": 8 }, "width": { "type": "integer", "minimum": 160, "maximum": 1280 }, "height": { "type": "integer", "minimum": 160, "maximum": 720 } } } ``` ### get_embed_code ```json { "type": "object", "properties": { "format": { "type": "string", "enum": [ "html", "react", "vanilla", "json" ] } }, "required": [ "format" ] } ``` ### get_install_instructions ```json { "type": "object", "properties": { "target": { "type": "string", "enum": [ "npm", "web-component", "react", "vanilla" ] } } } ``` ## Place tools A region is `?region=west,south,east,north` in degrees, or JSON such as `{"bbox":[28.45,40.78,29.65,41.36]}`. Named examples: `place=istanbul` (Istanbul), `place=cyprus` (Cyprus), `place=matterhorn` (Matterhorn & Zermatt), `place=geirangerfjord` (Geirangerfjord), `place=grand-canyon` (Grand Canyon), `place=yosemite` (Yosemite Valley), `place=torres-del-paine` (Torres del Paine), `place=fuji` (Mount Fuji), `place=everest` (Everest), `place=kilimanjaro` (Kilimanjaro). Istanbul is the whole metro area, about 101 × 64 km, Cyprus the whole island, about 261 × 166 km, and each landscape a box of 30 to 80 km around its main feature. A region draws its real heights; the seed, the terrain params and `motion.warp` have no effect on it. In the page, the **Map** button picks a region, and its Apply also switches to 3D with `lc=36&lw=0&lo=0.9&ix=4&ex=block&ev=0.12&az=341.8&ce=39.3&rd=1.32`; Cyprus and each landscape set their own `ev`, `az` and `ce`. `set_region` sets the same view. A minimap above the dock shows the applied area; in 3D it turns with the camera, and its compass turns the camera back to north up, which is azimuth 0. - `set_region`: Sets the map region that becomes the terrain. Give place, an id from the Map menu's catalog of about 100 places (the ten built-in ones are istanbul, cyprus, matterhorn, geirangerfjord, grand-canyon, yosemite, torres-del-paine, fuji, everest, kilimanjaro; an unknown id returns the full list), or a bbox in degrees. The same values are written to the page URL as ?place= for a named place, or ?region= for a box. Like Apply in the Map popover, it switches to 3D with the map terrain view: 36 lines, width 0, opacity 0.9, an index line every 4, a block at elevation 0.12, and the camera at azimuth 341.8, elevation 39.3, radius 1.32, pushing in and back at speed 0.2. Every place but Istanbul and the cities brings its own camera angle and elevation. - `get_region` (read-only): Returns the current region, its height range, load status and the URL query. loading is true and message is "Loading terrain" while a shared place is still fetching, before the default terrain is shown. - `clear_region`: Removes the region and returns to the procedural terrain and to the lines, camera, extent and elevation from before the region. ### set_region ```json { "type": "object", "additionalProperties": false, "properties": { "place": { "type": "string", "description": "A place id from the Map menu's catalog, such as istanbul or fitz-roy. Ignored when a bbox is also given." }, "west": { "type": "number", "description": "West edge, degrees." }, "south": { "type": "number", "description": "South edge, degrees." }, "east": { "type": "number", "description": "East edge, degrees." }, "north": { "type": "number", "description": "North edge, degrees." }, "bbox": { "type": "array", "items": { "type": "number" }, "minItems": 4, "maxItems": 4, "description": "[west, south, east, north] in degrees." }, "region": { "type": "string", "description": "west,south,east,north or JSON with a bbox array." } } } ``` ### get_region ```json { "type": "object", "properties": {} } ``` ### clear_region ```json { "type": "object", "properties": {} } ```