{"id":46336775,"url":"https://github.com/huslage/topo-shadow-box","last_synced_at":"2026-03-04T19:03:31.630Z","repository":{"id":340627917,"uuid":"1166906697","full_name":"huslage/topo-shadow-box","owner":"huslage","description":"MCP Server to generate Topographic 3D Prints","archived":false,"fork":false,"pushed_at":"2026-02-25T19:00:02.000Z","size":264,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-25T21:24:15.356Z","etag":null,"topics":["3d-printing","claude-code","mcp-server","topographic-maps"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/huslage.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-25T18:32:26.000Z","updated_at":"2026-02-25T19:00:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/huslage/topo-shadow-box","commit_stats":null,"previous_names":["huslage/topo-shadow-box"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/huslage/topo-shadow-box","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huslage%2Ftopo-shadow-box","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huslage%2Ftopo-shadow-box/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huslage%2Ftopo-shadow-box/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huslage%2Ftopo-shadow-box/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/huslage","download_url":"https://codeload.github.com/huslage/topo-shadow-box/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huslage%2Ftopo-shadow-box/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30090038,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T18:31:08.343Z","status":"ssl_error","status_checked_at":"2026-03-04T18:31:07.708Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d-printing","claude-code","mcp-server","topographic-maps"],"created_at":"2026-03-04T19:03:30.923Z","updated_at":"2026-03-04T19:03:31.603Z","avatar_url":"https://github.com/huslage.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# topo-shadow-box\n\nAn MCP (Model Context Protocol) server that generates 3D-printable topographic shadow boxes. Given a geographic area, it fetches real elevation data and OpenStreetMap features, then produces multi-material 3MF files ready for slicing and printing.\n\n## Features\n\n- Terrain mesh from AWS Terrain-RGB elevation tiles (free, global coverage)\n- OpenStreetMap overlay: roads, water bodies, and buildings\n- GPX track visualization as raised strips on the terrain\n- Multiple output shapes: square, circle, hexagon, rectangle\n- Export to 3MF (multi-material), OpenSCAD `.scad`, or SVG map insert\n- Live 3D preview via a local Three.js viewer (port 3333)\n- Session save/load to resume work across server restarts\n\n## Installation\n\nDownload a prebuilt binary from GitHub Releases, or build from source with Go:\n\n```bash\ncd go\ngo build -o /usr/local/bin/topo-shadow-box ./cmd/topo-shadow-box\n```\n\n### Adding to Claude Code\n\n```\n/plugin marketplace add huslage/topo-shadow-box\n/plugin install topo-shadow-box@topo-shadow-box\n```\n\nThe MCP server starts automatically when you install the plugin.\n\n### Adding to Codex\n\nAdd this to `~/.codex/config.toml`:\n\n```toml\n[mcp_servers.topo-shadow-box]\ncommand = \"topo-shadow-box\"\nargs = [\"serve\"]\n```\n\nThen restart Codex.\n\n## Permissions\n\nThe first time Claude calls each tool, it will ask for permission. Click **\"Allow always\"** (not \"Allow\") so the approval is saved and you won't be asked again.\n\nIf you'd rather pre-approve everything upfront, add this to your `~/.claude/settings.json`:\n\n```json\n{\n  \"permissions\": {\n    \"allow\": [\"mcp__plugin_topo-shadow-box_topo-shadow-box__*\"]\n  }\n}\n```\n\n## CLI Usage\n\nThe Go binary supports two modes:\n\n- `topo-shadow-box serve` starts the MCP server (Claude Code plugin mode).\n- `topo-shadow-box [flags]` runs one-shot CLI generation and writes an output file.\n\n### Build the Binary\n\n```bash\ncd go\ngo build -o /usr/local/bin/topo-shadow-box ./cmd/topo-shadow-box\n```\n\n### Quickstart Examples\n\n```bash\n# Circle area -\u003e 3MF\ntopo-shadow-box --lat 35.99 --lon -78.90 --radius 5000 --output durham.3mf\n\n# Bounding box -\u003e OpenSCAD\ntopo-shadow-box --north 36.1 --south 35.9 --east -78.8 --west -79.0 --output area.scad\n\n# GPX track area -\u003e SVG\ntopo-shadow-box --gpx /path/to/ride.gpx --output ride.svg\n\n# Custom model options + subset of map features\ntopo-shadow-box \\\n  --lat 35.99 --lon -78.90 --radius 5000 \\\n  --output model.3mf \\\n  --width 150 \\\n  --vertical-scale 2.0 \\\n  --base-height 8 \\\n  --shape circle \\\n  --resolution 250 \\\n  --features roads,water \\\n  --color-terrain \"#8B7355\" \\\n  --color-water \"#4A90D9\"\n```\n\n### CLI Flag Reference\n\n| Flag | Default | Description |\n|------|---------|-------------|\n| `--lat`, `--lon`, `--radius` | — | Circular area input (`radius` in meters) |\n| `--north`, `--south`, `--east`, `--west` | — | Explicit bounding box input |\n| `--gpx` | — | GPX file path (uses GPX bounds + default padding) |\n| `--output`, `-o` | — | Output path; extension selects format (`.3mf`, `.scad`, `.svg`) |\n| `--width` | `200` | Model width in mm |\n| `--vertical-scale` | `1.5` | Elevation exaggeration multiplier |\n| `--base-height` | `10` | Solid base thickness in mm |\n| `--shape` | `square` | `square`, `circle`, `hexagon`, `rectangle` |\n| `--resolution` | `200` | Elevation grid resolution per axis |\n| `--features` | `roads,water,buildings` | CSV feature list; use empty string to skip features |\n| `--color-terrain` | `#C8A882` | Terrain color |\n| `--color-roads` | `#D4C5A9` | Roads color |\n| `--color-water` | `#4682B4` | Water color |\n| `--color-buildings` | `#E8D5B7` | Buildings color |\n| `--color-gpx-track` | `#FF0000` | GPX track color |\n\n### Validation Rules\n\n- Exactly one input mode is required:\n  - `--lat` + `--lon` + `--radius`\n  - `--north` + `--south` + `--east` + `--west`\n  - `--gpx`\n- `--output` is required.\n- `--shape` must be one of `square`, `circle`, `hexagon`, `rectangle`.\n- Colors must be `#RRGGBB`.\n- Output format is inferred from file extension.\n\n### Run as MCP Server\n\n```bash\ntopo-shadow-box serve\n```\n\n### CLI Troubleshooting\n\n- `error: --output is required`\n  - Add `--output \u003cpath\u003e` (or `-o \u003cpath\u003e`). The extension must be `.3mf`, `.scad`, or `.svg`.\n\n- `one of --lat/--lon/--radius, --north/--south/--east/--west, or --gpx is required`\n  - Provide exactly one input mode. Do not mix coordinate/bbox/GPX inputs.\n\n- `--lat/--lon/--radius ... are mutually exclusive` (or bbox/GPX equivalent)\n  - Remove extra input flags so only one area-definition method is used.\n\n- `cannot infer output format from extension ...`\n  - Use a supported output extension: `.3mf`, `.scad`, or `.svg`.\n\n- `invalid --shape ...`\n  - Use one of: `square`, `circle`, `hexagon`, `rectangle`.\n\n- Color format errors (`must be in #RRGGBB format`)\n  - Use 6-digit hex with leading `#`, e.g. `#C8A882`.\n\n- Network/data fetch failures during elevation or feature steps\n  - Retry command (transient network issues are common).\n  - Try smaller area or lower `--resolution` if requests are timing out.\n  - For feature-only failures, you can still generate terrain by setting `--features ''`.\n\n- GPX errors (`open gpx...`, parse failures, or no bounds)\n  - Verify the file exists and is valid GPX XML with track points.\n  - Try exporting the GPX again from your source app/device.\n\n- Preview tool reports no mesh generated (MCP mode)\n  - Run `generate_model` first, then call `preview`.\n\n## Example Agent Conversations\n\nThese show how to prompt Claude (or any MCP-capable agent) to generate a shadow box. The agent calls the tools automatically — you just describe what you want.\n\n---\n\n### Example 1: Shadow box from coordinates\n\n**User:**\n\u003e Make me a 3D-printable shadow box of downtown Asheville, NC. Hexagon shape, 150mm wide. Save it to my Desktop.\n\n**Agent:**\n\n```\n⏺ set_area_from_coordinates(lat=35.5951, lon=-82.5515, radius_m=2000)\n  ↳ Area set: 35.545°N–35.645°N, 82.596°W–82.507°W (≈4.0×4.0 km)\n\n⏺ validate_area()\n  ↳ OK — area 16.0 km², elevation relief 312 m\n\n⏺ fetch_elevation(resolution=200)\n  ↳ Elevation grid fetched: 200×200 (40 000 points), range 606–918 m\n\n⏺ fetch_features()\n  ↳ Fetched 87 roads, 12 water bodies, 43 buildings from OpenStreetMap\n\n⏺ set_model_params(width_mm=150, shape=\"hexagon\", vertical_scale=1.5)\n  ↳ Model params updated\n\n⏺ generate_model()\n  ↳ Terrain mesh … roads … water … buildings … frame — done (6 meshes)\n\n⏺ export_3mf(output_path=\"/Users/you/Desktop/asheville.3mf\")\n  ↳ Exported 6-material 3MF to /Users/you/Desktop/asheville.3mf (4.2 MB)\n```\n\n**Agent reply:**\n\u003e Done! `asheville.3mf` is on your Desktop. It has six material slots: terrain, roads, water, buildings, frame, and base. Open it in PrusaSlicer or Bambu Studio and assign a filament color to each slot.\n\n---\n\n### Example 2: Shadow box from a GPX track\n\n**User:**\n\u003e I have a GPX file of my morning ride at `/Users/you/rides/morning_ride.gpx`. Generate a shadow box showing the route with the terrain underneath. Circle shape. Export to `/tmp/ride.3mf`.\n\n**Agent:**\n\n```\n⏺ set_area_from_gpx(file_path=\"/Users/you/rides/morning_ride.gpx\", padding_m=500)\n  ↳ GPX loaded: 1 track, 2 043 points. Area set with 500 m padding.\n\n⏺ validate_area()\n  ↳ OK — area 28.4 km², elevation relief 487 m\n\n⏺ fetch_elevation(resolution=200)\n  ↳ Elevation grid fetched: 200×200, range 312–799 m\n\n⏺ fetch_features(include=[\"roads\", \"water\"])\n  ↳ Fetched 134 roads, 8 water bodies\n\n⏺ set_model_params(shape=\"circle\", vertical_scale=2.0)\n  ↳ Model params updated\n\n⏺ generate_model()\n  ↳ Terrain mesh … roads … water … GPX track strip … frame — done (5 meshes)\n\n⏺ export_3mf(output_path=\"/tmp/ride.3mf\")\n  ↳ Exported 5-material 3MF to /tmp/ride.3mf (5.8 MB)\n```\n\n**Agent reply:**\n\u003e Your ride shadow box is at `/tmp/ride.3mf`. The GPX track is its own material object so you can print it in a contrasting color. The circle footprint clips the terrain and roads cleanly to the boundary.\n\n---\n\n## Tool Reference\n\nSee [docs/tool-reference.md](docs/tool-reference.md) for the full tool reference, typical workflows, output formats, and data sources.\n\n## Development\n\nSee [docs/development.md](docs/development.md).\n\n## License\n\nSee [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuslage%2Ftopo-shadow-box","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhuslage%2Ftopo-shadow-box","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuslage%2Ftopo-shadow-box/lists"}