Content/Skills/terrain-data/SKILL.md
Generate heightmaps, map reference images, and water feature splines (rivers, lakes, oceans) from real-world geographic data. Downloads Mapbox tiles server-side and produces UE5-compatible heightmaps plus landscape splines for water bodies.
npx skillsauth add kevinpbuckley/vibeue terrain-dataInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generates heightmaps and water feature splines from real geographic coordinates via the VibeUE terrain API. Requires an active VibeUE API key configured in chat settings.
preview_elevation — fetch elevation stats + suggested settings (costs 1 API call). Returns suggestedZScale, suggestedXYScales (resolution → XY scale), height range.generate_heightmap — generate the 16-bit PNG using suggested settingsget_map_image — satellite/topo reference image for the same areaattach_image — attach the satellite image so you can see the terrain colors and features for material/painting decisionslandscape skill⚠️ CRITICAL — Landscape Scale: When creating the landscape, use suggestedXYScales[resolution] from step 1 as the X and Y scale. Do NOT use the default value of 100. Use suggestedZScale for the Z scale. Example: scale=unreal.Vector(suggestedXYScales["1009"], suggestedXYScales["1009"], suggestedZScale)
get_water_features — fetch rivers, lakes, and oceans for the same lng/lat/map_size. Saves full JSON to Saved/Terrain/ and returns a compact summary with the file path.json_str = open(file_path).read()ue5_rings, waterways use ue5_points. Both are origin-centered.Create a landscape from the terrain around Mount Fuji
Generate a heightmap for San Francisco at coordinates -122.4194, 37.7749
Build a real-world landscape from the Swiss Alps near Zermatt (lng=7.7480, lat=46.0207)
Get the terrain around the Grand Canyon and make a landscape
Generate heightmap for Tokyo at 139.6917, 35.6895 with a satellite reference image
terrain_data(action="preview_elevation", lng=138.7274, lat=35.3606)
Response:
{
"min_height": 340.0,
"max_height": 3776.0,
"height_range": 3436.0,
"suggested_base_level": 340,
"suggested_height_scale": 27,
"suggestedZScale": 741,
"suggestedXYScales": { "505": 3429, "1009": 1714, "2017": 857, "4033": 429, "8129": 213 },
"tile_zoom": 13,
"tile_count": 9
}
Use suggestedXYScales["1009"] (or whichever resolution you chose) as the X and Y scale when calling create_landscape. Use suggestedZScale for the Z scale.
terrain_data(
action="generate_heightmap",
lng=138.7274, lat=35.3606,
base_level=340,
height_scale=27,
format="png"
)
Response:
{
"success": true,
"file": "C:/Project/Saved/Terrain/heightmap_35.3606_138.7274.png",
"min_height_m": 340.0,
"max_height_m": 3776.0,
"dimensions": "1081x1081"
}
terrain_data(
action="get_map_image",
lng=138.7274, lat=35.3606,
style="satellite-v9"
)
Response:
{
"success": true,
"file": "E:/Project/Saved/Terrain/map_satellite_v9_35.3606_138.7274.png",
"style": "satellite-v9",
"size_bytes": 1981147
}
⚠️ CRITICAL: After downloading a satellite image, ALWAYS attach it so you can see the terrain colors and features. This lets you make informed decisions about material layers and painting.
attach_image(file_path="E:/Project/Saved/Terrain/map_satellite_v9_35.3606_138.7274.png")
attach_image is a tool call (like terrain_data or manage_skills), NOT a Python function. Do NOT put it inside execute_python_code. Call it directly as a tool.
After attaching, you will see the satellite image in your next response. Use it to:
Use the landscape skill to import the heightmap file:
QuadsPerSection=63, SectionsPerComponent=2, ComponentCount=8x8 → 1009×1009 resolutionsuggestedXYScales["1009"] from preview (e.g. 1714 for a 17.28km map). Do NOT use the default 100 — that makes the landscape ~17x too small!suggestedZScale from preview (e.g. 741 for Mount Fuji).png path returned in step 2Example:
result = unreal.LandscapeService.create_landscape(
location=unreal.Vector(0, 0, 0),
rotation=unreal.Rotator(0, 0, 0),
scale=unreal.Vector(1714, 1714, 741), # XY from suggestedXYScales["1009"], Z from suggestedZScale
sections_per_component=2,
quads_per_section=63,
component_count_x=8,
component_count_y=8,
landscape_label="MyLandscape"
)
| Parameter | Default | Notes |
|-----------|---------|-------|
| lng / lat | required | Decimal degrees. Positive = East/North |
| format | png | png = 16-bit grayscale, raw = binary, zip = PNG + info |
| map_size | 17.28 | km — Cities: Skylines standard |
| base_level | 0 | Use suggested_base_level from preview |
| height_scale | 100 | Use suggested_height_scale from preview |
| water_depth | 40 | Cities: Skylines water units |
| gravity_center | 0 | 0=off, 2=N, 4=E, 6=S, 8=W (tilts terrain for water flow) |
| level_correction | 0 | 0=none, 2=flatten coastlines, 3=aggressive |
| blur_passes | 10 | Adjust per terrain character! 5–10=rugged, 15–25=hills, 25–40=smooth/flat. See Terrain Character Guide |
| plains_height | 140 | Meters — threshold between plains and mountains |
| save_path | auto | Saves to <ProjectDir>/Saved/Terrain/ by default |
| Style | Description |
|-------|-------------|
| satellite-v9 | Aerial imagery (best for landscape texturing) |
| outdoors-v11 | Topo with trails and contours |
| streets-v11 | Street map |
| light-v10 / dark-v10 | Minimal |
resolution=N⚠️ Never use the default 1081×1081 for UE landscapes — it requires 36×36 components and will timeout. Always pass resolution= matching your landscape config.
| resolution= | Components | Quads | Sections | km at UE scale=100 | |-------------|-----------|-------|----------|--------------------| | 505 | 8×8 | 63 | 1 | ~0.5 km | | 1009 | 8×8 | 63 | 2 | ~1.0 km | | 1009 | 16×16 | 63 | 1 | ~1.0 km | | 2017 | 16×16 | 63 | 2 | ~2.0 km | | 4033 | 32×32 | 63 | 2 | ~4.0 km | | 8129 | 32×32 | 127 | 2 | ~8.1 km |
"km at scale=100" is the UE world size when landscape XY scale = 100 cm/quad (default). Adjust scale to match real geography (see below).
terrain_data's map_size (default: 17.28 km) controls the geographic area captured. To make the UE landscape match actual geography:
UE XY Scale (cm/quad) = (map_size_km × 100,000) / (resolution − 1)
Example: map_size=20, resolution=2017 → (20 × 100,000) / 2016 ≈ 992 cm/quad (~9.9 m/quad)
Set this as the landscape's X and Y scale when creating it.
20000 / height_scale cm — e.g., height_scale=27 → Z scale ≈ 741⚠️ ALWAYS calculate Z Scale from height_scale. Do NOT guess. Use this formula when creating the landscape:
z_scale = 20000 / height_scale
Derivation: pixel encoding is pixel = elevation_m × heightScale × 64 / 100 and UE interprets height_cm = pixel × z_scale / 128. Setting height_cm = elevation_m × 100 (meters→cm) gives z_scale = 20000 / heightScale.
| height_scale | Z Scale | Terrain Type Example | |-------------|---------|---------------------| | 27 | 741 | Tall mountains (Mt. Fuji, Alps) | | 50 | 400 | Moderate mountains (Appalachians) | | 100 | 200 | Hills, canyons (Grand Canyon) | | 150 | 133 | Low hills, mesas | | 200 | 100 | Gentle rolling terrain | | 250 | 80 | Very flat terrain, gentle domes |
For Cities: Skylines, export as PNG and import via the standard heightmap importer (1081 default is fine there).
⚠️ CRITICAL: The suggested_height_scale from preview_elevation maximizes detail, but also amplifies noise. You MUST adjust blur_passes based on the terrain character.
After preview_elevation, look at the height_range and think about what the terrain actually looks like:
| height_range | suggested_height_scale | Terrain Character | blur_passes | |-------------|----------------------|-------------------|-------------| | > 2000m | Low (< 50) | Rugged mountains — keep default blur | 5–10 | | 500–2000m | Moderate (50–100) | Mixed terrain — moderate smoothing | 10–15 | | 100–500m | High (100–200) | Hills/mesas — needs more smoothing | 15–25 | | < 100m | Very high (200–250) | Flat/gentle — needs heavy smoothing | 25–40 |
Smooth terrain (granite domes, rolling hills, plains, gentle slopes):
blur_passes (20–40) to remove data noiseheight_scale amplifies every pixel of noise — smoothing counteracts thisRugged terrain (jagged peaks, canyons, volcanic craters):
blur_passes (5–10) to preserve detailheight_scale means less noise amplification, so less smoothing neededIf you get a terrain that looks jagged/spiky when the real place is smooth:
height_scale was too high without enough blur_passesblur_passes=30 or higher20000 / height_scale, NOT an arbitrary value like 200Fetches waterways and water bodies for a map area using the same Mapbox Vector Tile source as the heightmap. Use the exact same lng, lat, and map_size as your heightmap call.
terrain_data(action="get_water_features", lng=-105.0, lat=39.7, map_size=17.28)
Response includes:
file — path to the saved JSON file (e.g. Saved/Terrain/water_features_42.9720_-71.3480_10km.json)num_waterways / num_water_bodies — countswaterway_class_breakdown — object with class counts, e.g. {"stream": 191, "river": 26, "ditch": 12}waterways[] — summary of each waterway: name, class, estimated_width_m, num_pointswater_bodies[] — summary of each water body: name, class, num_ring_pointsmessage — instructions on how to use the saved file, coordinate system infoue5_coordinate_note — critical info about coordinate offset for water planesThe saved JSON file contains the full data with:
waterways[] — rivers, streams, canals. Each has name, class, estimated_width_m, points (lng/lat array), ue5_points (array of {x, y, z} objects in UE5 coords)water_bodies[] — lakes, ponds, oceans. Each has name, class, rings (lng/lat array of arrays), ue5_rings (array of arrays of {x, y, z} objects in UE5 coords)⚠️ CRITICAL FIELD NAMES:
ue5_points (NOT points — those are lng/lat)ue5_rings (NOT polygon or ring)class (NOT waterway_class or type)ue5_points and ue5_rings are landscape-center-relative (origin-centered):
| Issue | Fix |
|-------|-----|
| NO_API_KEY | Set your VibeUE API key in chat settings |
| 429 rate limit | 100 requests/day (free), 1000/day (paid) |
| Flat heightmap | height_range < 50m — use height_scale: 250 for detail |
| Clipped mountains | Lower height_scale or increase base_level |
| Jagged/spiky terrain | Increase blur_passes (20–40 for smooth terrain) and check Z scale formula |
| Terrain doesn't match real place | Check terrain character guide — smooth places need high blur_passes |
| Timeout | Large map sizes at high zoom may hit Vercel's 10s limit — try smaller map_size |
| No waterways returned | Area may have no mapped water features (desert, urban grid) — check satellite image |
| Landscape too small | You used XY scale=100 (default) instead of the correct value from suggestedXYScales. Recreate with the correct scale |
| Black screenshots after camera move | Camera inside terrain. Use ActorService.get_actor_view_camera() to frame from TOP view instead of guessing Z height |
| Water features timeout | PBF tile fetch uses 45s timeout — large map_size at high zoom may still be slow |
| Field name errors | Use ue5_points (not points), ue5_rings (not polygon), class (not waterway_class) |
testing
Procedurally design an AAA-style open-world FPS map blockout (roads, POIs, fields, forests/treelines, railway/bridges) from a VibeUE-generated landscape, validate it through gated checks, and materialize the plan into real engine geometry (splines, paint layers, foliage, actors).
tools
Create and manage Niagara particle systems - system lifecycle, adding/copying emitters, user parameters, system script settings, scratch-pad authoring
development
Configure Niagara emitter internals - modules, renderers, rapid iteration parameters, graph positioning, and scratch-pad authoring (Custom HLSL + node graph)
tools
Create and modify Blueprint assets, variables, functions, and components