This article is translated from my Japanese original on Qiita. The translation and editing were assisted by Claude (AI-assisted).
This is a personal project, not an official Mapbox product.
Introduction
How to build a custom indoor map from your own data is explained in detail in Build an indoor map with your own data in Mapbox GL JS.
When you build your first indoor map yourself, though, drawing room polygons one by one while thinking about real-world coordinates can be a fairly high bar. The goal of this post is to lower exactly that first hurdle, creating the data. I'll introduce a tool, indoor-generator, that creates and fixes Mapbox indoor data (the Indoor data model) from simple natural-language instructions. If there were a handy tool that an individual can use casually, I'd expect the range of uses to grow and indoor maps to be used more.
Floor plans are a different situation from, say, reading building outlines off satellite imagery. Vector data for the inside of a building is often available from the start. Even when you only have a raster image, it is usually sharp and detailed, unlike satellite imagery, so recognizing vector shapes from it is often realistic. That makes "image to indoor map" a good fit for a tool like Claude Code. (You still have to check and fix the details, of course.)
Below, I'll walk through making an indoor map of the 5th floor of PMO Shinbashi II Building (Tokyo) from a single floor-plan image.
Who is this for, and for what?
Where people usually get stuck
When you try to make an indoor map, you tend to stop around here:
- I don't know how to start
- What do I need?
- Which tools?
- What do I do with the indoor data or images I already have?
- I don't have any data at all
- I want a private tileset
- I don't know the details of Mapbox's indoor tileset (v3)
"Works well enough" now, not perfect later
On the other hand, some use cases look like this:
- Roughly correct relative positions are enough; exact positions don't matter
- Content that changes often (e.g. store guides)
- One-off, throwaway maps: trade shows, school festivals, sports days, food festivals
- Private indoor maps for a company floor plan, shared only inside the company or with a few people
- Positioning (blue dot) and routing aren't necessarily needed
What's missing is a tool that makes something that works well enough, easily, and lets you deploy it right away.
What the tool does
| Feature | What it means |
|---|---|
| Sources | Searches the web when needed (official floor counts, areas, floor guides) |
| Your own data | If you have a floor plan or an image, it uses that |
| Fixing and updating | Fix by natural language or by hand in the preview; deploy only when you want to |
How it works: Claude Code (skills in .claude/skills/) handles research, writing the config file and the conversation. Turning the config into GeoJSON is a fixed Python pipeline.
"Make an indoor map of PMO Shinbashi II 5F from this image"
→ locate the building (OSM) + footprint (OSM, or drawn from the floor plan) + web research
→ configs/<slug>.json ← the source of truth
→ Python pipeline
→ output/<slug>/indoor.geojson + live preview
→ refine by chat: "make the meeting room bigger", "undo"
Setup
Quick start
You use the tool by talking to Claude Code inside a clone of the repository. The skills that know how to research a building and run the pipeline (.claude/skills/ and CLAUDE.md) live in the repo, and Claude Code only loads what is in the folder you start it in (and its parents). Start it somewhere else and it knows nothing about this tool.
What you need
- Claude Code (the terminal CLI, the desktop app or the VS Code extension) and a sign-in. This needs a Claude subscription or an API account and uses your quota
- Python 3.10+ (what I develop with; older versions are untested) and git
- A Mapbox account and a public token (
pk.*) to load the map - Only if you upload and host a tileset: a secret token (
sk.*)
The commands below assume macOS / Linux (on Windows, use .venv\Scripts\...).
Steps
- Clone and set up:
git clone https://github.com/akiramur/indoor-generator.git
cd indoor-generator
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
cp .env.example .env # put your public token (pk.*) in MAPBOX_ACCESS_TOKEN
- Start Claude Code in that folder (in the desktop app or VS Code, open the cloned folder as the project):
claude
- Type your request into the Claude Code prompt as a chat message (not a shell command):
Make an indoor map of Marunouchi Building
Claude Code researches the building, writes configs/<slug>.json, generates output/<slug>/indoor.geojson and starts a live preview at http://127.0.0.1:8765. Ask for fixes in the same session ("make the north side of the 2nd floor a meeting room"). Claude Code may ask permission before running commands or fetching web pages; read what it asks and approve only what you're comfortable with.
The easiest way is, as in the examples below, just writing the building's name in English or Japanese.
Notes
-
.envis git-ignored. Thepk.*token is written intooutput/<slug>/index.html, so if you share that file, add a URL restriction to the token in the Mapbox console. - To try only the pipeline without Claude Code, the bundled sample works:
.venv/bin/python main.py build samples/building_config.json
.venv/bin/python main.py serve marubiru-sample # http://127.0.0.1:8765
- Researching and building one building takes a few minutes, including web search and fetching.
main.py costgives a rough Claude cost (converted at list prices).
Let's build one: PMO Shinbashi II, 5F
1. Hand over an image and ask
All I prepared was one image: the floor plan of the 5th-floor rental space. I opened Claude Code in the repo and asked:
Make an indoor map of PMO Shinbashi II 5F from the image below
2. What Claude Code does
The indoor-map and indoor-floor-image skills work through these steps. No one has to click to align anything.
-
Identify and research the building. It finds the building in OSM from the address, and looks up the number of floors, total floor area and the typical floor's area on the web. PMO Shinbashi II has 14 floors above ground and a typical floor of about 281 m². Where each fact came from is kept in
provenance.sourcesofconfigs/<slug>.json. - Decide the footprint. The footprint is the OSM building shape. OSM still had the old, pre-redevelopment rectangle for this site, so when it is old or coarse, the tool draws the footprint from the outer wall of the floor plan at real scale. It avoids extracting shapes from Mapbox's own map tiles (the buildings in Mapbox Streets), since the Mapbox Product Terms may not allow that.
-
Overlay the image on the building. The image is never bent; only scaled, rotated and moved so that the drawing's outline best covers the building's outline (
main.py basemap). Which way is up in the image is decided by Claude from the surrounding roads and satellite imagery and passed in explicitly (more on this one below). -
Trace the rooms. Claude reads the room outlines from the image (offices, meeting rooms, elevators, toilets, stairs…) and converts them to coordinates that fit the building (
main.py trace). Pictograms such as elevators, stairs and toilets also become points (POIs). -
Build and preview. It generates
indoor.geojsonand shows it in a live browser preview.
If you did it by hand, the core commands are these (normally Claude runs them):
.venv/bin/python main.py build configs/pmo-shimbashi2.json
.venv/bin/python main.py serve pmo-shimbashi2 # http://127.0.0.1:8765
3. The result
In the preview (Mapbox GL JS Standard style + the indoor block + IndoorControl) you switch floors with the control at the bottom right. The "Floor map from the source" checkbox on the left toggles the overlay of the original floor plan (the image at the top is with the overlay on).
What I've shown so far is the tool's preview for checking your work (it includes editing). Separately, I made a demo that displays the finished indoor maps with plain Mapbox GL JS only: a single page that doesn't use the tool's preview server and just loads the generated GeoJSON (one file per facility). Treat it as a minimal example of putting your own indoor map on a web page. (It doesn't include the floor-plan images; it only draws the generated rooms and facility icons.)
In the demo you can rotate and tilt the map, or hide the floors with the top button of IndoorControl to go back to the plain 3D building.
The demo's source is readable with your browser's view-source. It is only the page (index.html) and JSON files in data/ (the list of facilities, the icon definitions, and one GeoJSON per facility).
Note that map.style.indoorManager, which the demo uses to show and hide the 3D building as you change floors, is an experimental API with no published specification. If you copy it, watch out for future changes.
The 5F result:
| Item | Result |
|---|---|
| Rooms | 16 (15 traced from the image + 1 for the remaining common areas / corridors) |
| Traced from the image | about 49% of the area |
| Remaining common areas / corridors | about 51% (derived automatically: footprint minus the traced rooms) |
| Pictograms | 6 points (POIs) for elevators, stairs and toilets |
The rooms it got: men's and women's toilets, anteroom, elevator, emergency elevator, elevator hall, PS / DS / EPS, two stairs, a round meeting room, a meeting room, two booths, the office area and a lounge. Names and uses (category) come from the text in the image.
In terms of workflow, it reached the preview about 5 minutes after I typed the request once. The Claude cost estimate was about $0.9 (not a bill; converted at list prices).
These 5F numbers (the room count, the traced share, the time and the cost) were measured on an earlier version of the tool, so a run on the current version may give different figures.
4. The first result, and how to fix it
It isn't perfect from the start. Claude itself reports these points along with the result:
- Details such as toilet stalls and curved walls are simplified.
- Traced rooms can stick out of the footprint (OSM, or the shape drawn from the plan). Even then the policy is to keep the rooms rather than cut them (the share that ends up outside is reported in the
traceoutput). - Alignment is an automatic fit to the building's outline, not to landmarks.
- The image's orientation (up = east) was a visual judgement.
To fix things, ask in chat by name ("make the men's toilet larger"), or click a room in the preview and ask "this room should be…". By hand, Edit floor in the preview lets you move vertices, add, delete and merge rooms. For an image that's slightly off, use the "Floor map" mode: drag and scale it, then "Save this floor only". To go back one step, say "undo". Note that undo restores only the config file; room shapes you edited by hand in the preview don't come back (backups are in configs/.history/plans/), so before saving, use the edit mode's own Undo.
5. See how well-sourced it is, in numbers
main.py report shows how well each room is backed by data.
.venv/bin/python main.py report configs/pmo-shimbashi2.json
For this 5F, "traced from the image" was 49.2% of the area and "derived" was 50.8% ("listed" and "estimated" were 0%).
Because it separates traced, listed (name only), estimated and derived, you can see what to trust and what is a guess. For a multi-floor building, floors without a plan show up as "estimated", which tells you where to look next.
Another example: no image, search the web (Mitsui Outlet Park Tama Minamiosawa)
For PMO Shinbashi II I handed over the plan myself. If you don't have one, Claude looks for it on the web. As an example, here is the first prompt I typed for Mitsui Outlet Park Tama Minamiosawa (an outlet mall in western Tokyo):
Make an indoor map of Mitsui Outlet Park Tama Minamiosawa
No image, no URL, no floor count. But the screenshots below are not the result of that one sentence. They are the state after many rounds of fixes following the first build. I'll describe how it went later.
What Claude found on the web
Quoting from the research notes (output/<slug>/research.md) and the sources in the config, here's what actually happened:
| Found | How it was used |
|---|---|
| Official floor guide, 1F / 2F (images only; no machine-readable shapes or hotspots) | Read store outlines and names (images kept as URLs) |
| OSM relation / ways (Block A, the Villa building and the central island) | Locating the building. The footprint became OSM's shape plus the union of the stores |
Since the official site only had images, it went through the same "overlay the image → trace it" flow as the 5F. The difference is that even finding the images is automatic. For alignment, OSM had no named landmarks there, so it used corners of the parking blocks as control points, with an error of about 1–2 m. (The 1F in this example was fitted with an affine transform from control points, which was the method at the time, so the image is slightly deformed. The current tool only uses similarity transforms and never bends the image.)
The result (after repeated fixes)
| Item | Result |
|---|---|
| Floors | 2 (1F, 2F) |
| Store outlines | 66 rooms on 1F and 59 on 2F traced from the images (including stairs and parking) |
| Share of area traced | about 51% (the rest is outdoor walkways, courtyards and other common areas derived from the footprint) |
With store names, positions, shapes and use categories (retail / dining / service…) filled in, the preview also shows a list of stores on the right.
From the first sentence to here
The result of the first prompt was rough, with many store shapes off from the original drawing. From there I fixed it like this (from the session log):
- First build: typed the prompt above. It traced the stores from the official floor guide and made a first 1F and 2F.
- Shapes don't match: "the store shapes don't match the background (the original drawing); align them".
-
About 10 store-by-store fixes: I repeated comments like these, one store at a time:
- A store bites into its neighbour and ends up as an island
- The right side or a corner of a store is missing
- Two separate stores were merged into one
- A strange spike on a store's side
- Add stairs: no stairs had been included, so the shapes were read from the drawing and added (also recorded in the notes).
So what you get from the first sentence is only a starting point. I fixed things by conversation, one "this store looks wrong" or "this is missing" at a time, until it reached the state in the screenshot.
What isn't fixed
The research notes still list what is unknown:
- The central island has fine store boundaries, so position and shape are approximate.
- Uses are guessed from store names (I didn't import the official category table).
- Stairs vs. escalators can't be told from the drawing; a ladder shape with one arrow was judged to be stairs.
- Stores marked as closing soon are left as they were when published.
The tool gets you to "works well enough" automatically, but checking and fixing details is a human job. You can do that either by chatting with Claude or by hand in the preview (Edit floor). And since the source is an official site's drawing, the copyright notes below apply as they are (images are not committed, only the URL is kept; check the rights before publishing).
FAQ
Can I use it without uploading to Mapbox Tiling Service (MTS)?
Yes. The preview in this post loads the generated indoor.geojson directly as a Mapbox GL JS GeoJSON source. No upload or deploy is needed; you only need a public token.
If you make a few event venues and check them locally, that's all you need. You only need MTS when you want to hand it to many people or host it.
To upload, main.py publish combines all built buildings into one tileset. It's a dry run unless you pass --upload, and the default target is a development tileset (indoor-dev). The secret token (sk.*) is read from .env and never embedded in HTML.
What do processing and hosting cost?
Prices change, so check the official pages for current rates and free tiers:
- Mapbox Pricing (the Tilesets section has Processing and Hosting rates and free tiers; map display with Mapbox GL JS is here too)
- How Mapbox Tiling Service pricing works (what you are billed for)
Will it fit in the free tier?
A rough estimate against the free tiers on the official page as of 2026-10-21 (Processing: 10,000 MB and 20 CU per month; Hosting: 750 days per month; GL JS map loads: 50,000 per month). It's only a guide; check the official rates and your own usage for the real bill.
- Data size (MB): The GeoJSON of the 6 facilities in the demo totals about 1.3 MB. Even all 14 buildings I've made with this tool (including big halls and shopping malls) add up to about 5 MB. That's under 0.1% of the 10,000 MB free tier, so for a few to a few dozen indoor maps it's unlikely to matter.
- Processing (CU): The official page says a vector tileset processing job is often around 0.3–5 CU. With 20 CU a month, that's roughly 4 uploads at the pessimistic 5 CU, or about 60 at 0.3 CU. The more often you rebuild and upload, the more you use. While you're still fixing things, check in the preview and don't upload.
- Hosting (days): The tool publishes all buildings as one tileset. One tileset is 30 days a month, well within the free 750 days (an average of 25 tilesets).
- Map display (GL JS): Up to 50,000 loads a month are free. For a map that a limited audience sees for a short time, like a trade show or a school festival, that should be enough.
Conversely, uploading again and again, or publishing a map that many people view, can exceed the free tier.
What does Claude cost?
The tool estimates Claude's cost per build from Claude Code's session logs (main.py cost; not a bill, converted at list prices). For PMO Shinbashi II:
| How it was made | Estimate | Turns | Working time |
|---|---|---|---|
| PMO Shinbashi II 5F only (as above, one request) | about $0.9 | 1 | about 5 min |
| The same building with the other floors' plans built out too (including back-and-forth tuning, over 8 days) | about $9.8 | 37 | about 35 min |
The first row is the cost until the map first came out from one request (not including later fixes or interacting with the preview). The second row includes making 1F, 2F, 3F, 7F, 8F and so on, plus the fix conversation, so it's an order of magnitude more. The more you fix, the more you use.
What about copyright?
Be careful here. Floor maps on official sites and floor plans in leasing materials are generally copyrighted. This tool handles it like this:
- Third-party images are not committed to the repo (
configs/plans/*/maps/is git-ignored). The config keeps only the source URL; the image sits in a local cache. - The footprints and coordinates use © OpenStreetMap contributors (ODbL), so keep the attribution when you publish. When OSM has no footprint (e.g. an old building), it is drawn from the plan. Extracting shapes from Mapbox's map tiles may not be permitted by the product terms, so the tool avoids it.
- The importer that reads an official site's floor guide assumes occasional personal use, after checking the site's terms of use and robots.txt.
Whether the rights to the original drawing allow you to post images or to publish and distribute the map you made is for you to check. The tool can't solve that. The safest way, as in this post, is to build from your own (or your own facility's) plans.
What worked
- You don't type every store name. Store names and shapes are read from the official floor-guide image. For Tama Minamiosawa, about 125 areas across 1F and 2F went in without typing them in. By my feel, it's far less effort than doing it by hand.
- Research can be delegated. It looks up floor counts, areas and so on on the web, and keeps them in the config with their sources.
- Fixing is a conversation. Just say "this store bites into its neighbour" and the shape is fixed.
But reading isn't perfect. Misread store names and shifted shapes happen, so checking and fixing is always required.
What didn't work
To be honest, these were the struggles:
- Complex shapes. The 5F of PMO Shinbashi II has a round meeting space and diagonal walls, so reading outlines and alignment drift more than for a plain rectangular building. A big, complex building like an airport terminal needs even more work.
- Warping the image with control points. Pairing points on the image with points on the map and deforming the image didn't work, so I dropped it. Now the image is never bent; it's only scaled, rotated and moved.
-
Detecting which way is up. The image's up direction was sometimes not picked correctly automatically, because a long thin building looks nearly the same upside down. Claude reads the compass or north arrow and passes
--map-up/--north-deg, and when it's ambiguous the tool warns and asks. For this 5F as well, "up = east" and "up = west" fit equally well. From the surrounding roads and satellite imagery (the glass side faces the road to the south, the core side faces the neighbouring building to the north) I judged "up = east". That's a visual judgement, so if it looks reversed, say so and it gets fixed.
Caveats
- It isn't a magic one-shot map maker. The first result is "well enough", and you then fix it until it's done.
- Expect several rounds. On this 5F too, toilet stalls and curved walls stay simplified, and fixing them takes instructions like "make this bigger" or "align this line with the wall".
- Watch out for copyright (see above).
- Accuracy is "roughly correct relative positions", with alignment errors of a few meters. It is not a survey, so it isn't suitable for positioning or routing.
Summary
Until now it has been hard to tell where and how to start an indoor map, so the first step was a high bar. With this tool you get a first map from a floor-plan image and a chat request, then fix it by conversation, which I think lowers the bar quite a bit.
- From one floor-plan image and a one-line request, you can make a Mapbox indoor map (
facility > structure > floor > room) - The preview works without uploading; use MTS when you want to distribute it
- Fix it in natural language or by hand in the preview
- You can check how well-sourced the data is, in numbers
- It's not a one-shot, and the rights to the original drawing are for you to check
For maps of ever-changing supermarket store guides, one-off, throwaway guides for trade shows, school festivals and food festivals, or private indoor maps like a company floor plan, why not try making an indoor map of a place near you?
Bonus: demos of other facilities
The demo above also contains other facilities made with this tool. You switch facilities with the dropdown at the top left (the selected one goes into ?b= in the URL). Here they are as screenshots.
These are unofficial and for reference only, and the shapes include estimates based on official drawings and the like (the demo screen shows the same notice).
Tokyo Station, Marunouchi building
Tokyo International Forum, Hall C (a seating prototype)
Zoom in and you can see every seat, with its seat and row numbers.
LaLaport Tachikawa Tachihi
IKEA Tachikawa (2F)
Fukuoka Airport Domestic Terminal Building










Top comments (0)