Skip to content

Repository files navigation

Beaty Biodiversity Museum Indoor Mapping

This repository stores indoor mapping data for the Beaty Biodiversity Museum. The files are GeoJSON, which is a standard text format for map features such as points, lines, and polygons.

The long-term goal is to keep the data easy to review in common map tools while moving it closer to indoor mapping conventions such as Apple's Indoor Mapping Data Format (IMDF), now also published as an OGC Community Standard.

Supporting documentation:

  • DATA_SOURCES.md explains source data, local review decisions, and derivation methods.
  • DATA_DICTIONARY.md defines local fields, local category values, and terms that need museum confirmation.

IDMF Viewer

This repository includes a viewer for exploring the canonical files in geojson/. It provides layer controls, ground and basement filtering, feature search, fixture-to-fixture routing, and an inspector for useful IDMF properties and issue provenance.

Visit the live demo here: https://apps.beatymuseum.ubc.ca/map

Routes are constrained to locally confirmed LineStrings in geojson/navigation_path.geojson. Access projections in navigation_access.geojson connect fixtures to that network, while deduplicated physical viewing locations live in navigation_stop.geojson. Junctions are generated from path geometry during validation and display rather than stored. Routing minimizes total distance across these approved segments. Unit polygons are never treated as free routing space, and the viewer reports that no approved route is available instead of inventing a shortcut.

The Museum Floor Unit is derived from the Basement Level minus its Ramp Units. Rebuild it after changing either source geometry:

python3 -m pip install -r requirements.txt
python3 scripts/build_gallery_unit.py
python3 scripts/build_preview_geojson.py

Navigation revisions are generated as approval artifacts before canonical data changes. Rebuild the approved corridor-centering proposal with python3 scripts/build_navigation_proposals.py centered; applying it requires explicit review and uses python3 scripts/build_navigation_proposals.py apply-centered.

Local development

Install the exact JavaScript dependencies:

cp .env.example .env
npm ci

Run the viewer locally in development mode:

npm run dev

Open http://localhost:3000/map. The /map suffix is required because the application uses that base path.

To test a production build locally:

npm run build
npm run start

The build reads the canonical map layers from geojson/. The build script also copies those files into the standalone Next.js output. preview.geojson is a review artifact and is not loaded by the viewer.

.env.example contains the local base path. The deployment manifest owns the production application name and /map ingress path; the indoor_mapping inventory record supplies APP_HOST, APP_PORT, and any deployment-root override.

Run the complete local validation before publishing a change:

npm run check

Production deployment

Production deployment is owned by ansible-deploy. From an activated controller checkout, deploy a reviewed revision with:

./scripts/deploy indoor_mapping <revision>

Controller-driven deployment reads deploy/deployment.yml, runs deploy/build.sh on the controller, and transfers the resulting standalone artifact. The managed host does not need the repository or GitHub access. Inventory owns host placement and APP_HOST/APP_PORT; the repository owns installation, readiness, and the default release root. The deployed process remains bound to loopback and is exposed only through nginx. deploy/install.sh initializes once and delegates later deployments to deploy/update.sh. Usage events are stored outside immutable releases at $SERVICE_CREATOR_DEPLOY_ROOT/data/usage.sqlite3, so normal updates preserve them. Explicit install.sh --reinstall repeats initialization without changing map data. Normal updates replace only the immutable application release. The manifest adapters are the only production deployment route; the former checkout-based deploy, update, and readiness scripts have been removed.

Anonymous usage logging

The viewer records completed searches, selected features, requested routes, opened exhibit images, and anonymous session timestamps. It does not record map zooms, pans, touch coordinates, or individual keystrokes. Records are kept for 365 days by default.

Local data is stored in .data/usage.sqlite3. Set USAGE_DB_PATH to override the location and USAGE_RETENTION_DAYS to change retention. Export the current database to CSV with:

npm run usage:export -- usage-events.csv

A read-only summary dashboard is available at /map/analytics. It uses HTTP Basic authentication, defaulting to username beaty and password beaty. Set ANALYTICS_USERNAME and ANALYTICS_PASSWORD in production to override those credentials.

Visitor problem reports

The in-map Report a problem form sends a structured issue to GitHub without giving visitors access to GitHub credentials or arbitrary issue fields. Configure GITHUB_ISSUE_TOKEN with a fine-grained token limited to Issues: read/write on this repository. GITHUB_ISSUE_REPOSITORY selects the fixed destination and defaults to beatybiodiversitymuseum/indoor-mapping.

Reports receive only the needs review label so the map-data ingestion workflow cannot process visitor text before a maintainer reviews it. The persistent per-session submission limit defaults to five reports per hour and can be changed with REPORT_RATE_LIMIT_PER_HOUR.

What's Here

The current map data is in the geojson/ folder:

File What it contains Current feature type
geojson/manifest.json IMDF package metadata n/a
geojson/address.geojson Museum postal address address
geojson/venue.geojson Confirmed overall venue boundary around Beaty, BRC, AERL, and the overhang venue
geojson/building.geojson Confirmed building records for Beaty, BRC, and AERL building
geojson/footprint.geojson Confirmed OSM-derived building and overhang footprints footprint
geojson/level.geojson Confirmed underground museum gallery level level
geojson/unit.geojson Confirmed Museum Floor unit unit
geojson/opening.geojson Doors, entrances, exits, ramps, and other passages opening
geojson/anchor.geojson Starter anchor point for the gallery unit anchor
geojson/amenity.geojson Restrooms, waste bins, visitor services, and equipment amenity
geojson/exhibit.geojson Permanent exhibits, including windows, drawers, shadowboxes, floor displays, and standalone displays exhibit
geojson/occupant.geojson Occupants, currently empty occupant
geojson/detail.geojson IMDF detail features, currently empty detail
geojson/section.geojson Sections, currently empty section
geojson/geofence.geojson Geofences, currently empty geofence
geojson/kiosk.geojson Kiosks, currently empty kiosk
geojson/navigation_path.geojson Confirmed walkable route segments navigation extension
geojson/navigation_access.geojson Explicit fixture-to-path access projections navigation extension
geojson/navigation_stop.geojson Deduplicated exhibit viewing and route-start locations navigation extension
geojson/relationship.geojson Feature relationships, currently empty relationship
geojson/fixture.geojson Cabinets, drawer/island boxes, tables, cases, and flat floor-display footprints fixture
preview.geojson Stacked GeoJSON.io review file for the canonical map layers mixed

Mapped indoor gallery features reference one confirmed underground level:

41d0e8ca-d315-4b25-938c-7955db2daf2e

Testing With geojson.io

geojson.io is a beginner-friendly website for checking and previewing GeoJSON.

Use preview.geojson when you want the easiest visual review. It combines the main review layers in draw order so unit/level/footprint shapes load first and amenity points load last.

Import The Preview

  1. Go to geojson.io.
  2. Click Import, choose preview.geojson, and wait for the map to load near UBC in Vancouver.
  3. Look for red error messages in the main right-side JSON editor.
  4. Click existing features on the map to orient yourself before adding a new point.

GeoJSON.io import control for preview.geojson

Measure A Reference Distance

  1. Select an existing feature, or draw a temporary Line between two known reference points.
  2. With the feature selected, click the Measurements button in the top toolbar.
  3. For a line, the measurement dialog shows the bounding box, length, selectable units such as meters, and vertex count.
  4. Use meters for museum measurements unless another unit is clearer.
  5. Delete the temporary line before copying final GeoJSON if it was only used for measurement.

GeoJSON.io Measurements dialog

Add And Copy A Point

  1. Click the Point drawing tool in the top toolbar.
  2. Click the map where the new location should go.
  3. Select the new point.
  4. In the lower Feature Editor panel, click the GeoJSON tab. This lower panel edits only the selected feature.
  5. Hover over the lower GeoJSON snippet so its Copy button appears.
  6. Click Copy to copy only the selected point feature.

Paste Into The Issue

  1. Open a new Add or correct a map location issue.
  2. Fill in the name, confirmation method, reference points, GPS coordinates, photos, and notes.
  3. In Optional: pasted GeoJSON feature, paste the copied selected point feature between the fenced json lines.
  4. Confirm the pasted feature is a single Point feature and uses [longitude, latitude] coordinate order.

GitHub issue optional GeoJSON feature paste example

Before saving a change, confirm:

  • The map still loads.
  • The edited feature appears in the right place.
  • There are no JSON errors.
  • You did not accidentally remove the opening {, closing }, or commas between features.

Adding Locations

Many locations at the Beaty can be added to our maps. Consider visitor-facing points of interest, such as exhibits, fossil excavation viewing points, cabinet exhibit points, drawer exhibit points, kiosks, service points, or other things a visitor may search for or navigate to.

You do not need to know how to code to help add a location. The most important thing is to collect clear, accurate information so that the JSON entry can be created or reviewed correctly.

If you are submitting a new location, use the map-location issue template and select exactly one layer: exhibit, fixture, amenity, or opening. The template asks for the information a maintainer needs without requiring you to edit GeoJSON.

Issue-To-GeoJSON Review Flow

Open issues labeled map data or titled with the Location: prefix can be consumed by the Generate GeoJSON from Issues GitHub Actions workflow. The workflow runs when a matching issue is opened, edited, labeled, or reopened, and it can also be run manually or by its weekly scheduled backstop. Issue-triggered runs include the triggering issue directly and also batch any other open matching issues found by the GitHub CLI. The workflow also creates the map data and needs review labels if they are missing, then applies them to matching issues.

The workflow:

  1. Reads open map data issues.
  2. Reads the selected map layer and validates geometry appropriate to that layer.
  3. Updates geojson/exhibit.geojson, fixture.geojson, amenity.geojson, or opening.geojson.
  4. Rebuilds preview.geojson for GeoJSON.io review.
  5. Writes reports/issue-geojson-review.md.
  6. Opens or updates a pull request labeled needs review.

Generated features include source_issue_number, source_issue_title, and source_url. The pull request review is the approval gate: review the map changes in the PR, edit the generated GeoJSON if needed, and merge only after the candidate data is accepted. Geometry must fall within the configured UBC Vancouver bounding box, and the generated PR body includes Closes #... lines for converted issues. Validation rejects exhibits stored as amenities, unresolved exhibit-to-fixture or navigation references, duplicate issue records across layers, invalid level references, and stale previews.

The best way to figure out the location is to use multiple GPS readings. However, the GPS is not always great underground. Then, use confirmed points and measure from them. It's best if you can establish a reference point along a straight line.

Measuring from existing maps is a very helpful approach as well.

1. What is the visitor-facing name?

Use the name that a visitor, museum staff member, or exhibit label would recognize.

Good examples:

Gift Shop Cash Register
Visitor Information Kiosk

Avoid vague names such as:

Thing near wall
Display
Cabinet

If there is a label on the object, copy the label exactly. If there is no label, describe it clearly and consistently.

2. What kind of amenity is it?

Write down what the point represents.

Examples:

kiosk
service point
visitor information point
accessibility points
restroom

If you are not sure which category to use, write your best plain-language description. A maintainer can choose the final category.

3. Where should a visitor navigate to?

The amenity point should usually mark where a visitor should stand, look, or arrive — not necessarily the exact middle of the object.

4. How did you confirm the location?

Every new amenity should include how the location was confirmed. This helps reviewers know whether the point is reliable.

Use one of these methods where possible:

visually confirmed on site
measured on site
recorded with phone GPS
derived from existing wayfinding data
checked against a floor plan
confirmed by museum staff

Phone GPS can be useful, but indoor GPS is often inaccurate. If you use a phone, record the location while standing as close as possible to the amenity and include a note that it was collected indoors with a phone.

5. How can someone measure the location without editing JSON?

If you cannot confidently place the point in GeoJSON, collect enough information for someone else to place it.

Useful options:

  • Use your phone to record GPS coordinates while standing at the visitor viewing point.
  • Take a photo showing the amenity and nearby fixed objects, such as walls, doors, stairs, elevators, columns, or cabinets.
  • Measure with a tape measure from a confirmed spot already on the map.
  • Mark the point on a printed floor plan or screenshot.
  • Write a short description of the location using nearby landmarks.

Good measurement examples:

Standing point is 1.2 m in front of Cabinet 01, centered on the cabinet face.
Point is 0.8 m east of the southwest corner of Drawer Island 03.
Point is directly in front of the fossil excavation glass, aligned with the center of the viewing edge.
Phone GPS recorded while standing at the viewing point. Indoor GPS may be approximate.

If measuring from a confirmed spot, use a spot that is unlikely to move, such as:

  • a wall corner
  • a doorway
  • a column
  • a stair or elevator entrance
  • a cabinet or fixture already mapped in geojson/fixture.geojson

Avoid measuring from movable objects such as chairs, temporary signs, or garbage bins.

6. Is the amenity visible to visitors?

Record whether a normal visitor can see or access the amenity.

Examples:

visible to visitors
not visible to visitors
staff-only
temporarily hidden
behind glass
inside cabinet

7. Is it important for navigation?

Record whether visitors may reasonably search for this amenity or use it as a destination.

Examples:

yes, visitors may search for it
yes, it is a major exhibit point
no, it is only supporting information
unknown

8. Is it related to a fixture?

If the amenity belongs to a cabinet, drawer box, island, or other mapped object, write down the related fixture name or ID if you know it.

Examples:

related to Cabinet 01
related to Drawer Island 03
related fixture unknown

Do not invent a fixture ID. If you do not know it, leave a note.


Beginner-friendly checklist for a new amenity

Before submitting a new amenity, make sure you have recorded:

  • Name of the amenity
  • Type of amenity
  • Exact visitor standing/viewing point
  • How the location was confirmed
  • Whether it is visible to visitors
  • Whether it is useful for navigation
  • Related cabinet, drawer, island, or fixture, if known
  • Any uncertainty or notes for the reviewer

A maintainer can turn these notes into a correct entry in geojson/amenity.geojson.


If you are proposing the JSON directly

Copy an existing amenity entry that is similar to the one you want to add, paste it as a new feature, and then change only the values that describe the new amenity.

Be careful to:

  • Give the new feature a unique id.
  • Keep coordinates in this order: [longitude, latitude].
  • Use a point marker for the amenity location.
  • Keep the existing level_id unless the amenity is on a different floor.
  • Keep commas between features.
  • Test the full file in geojson.io before submitting.

If you are not sure what a field means, do not guess. Add a plain-language note instead, or ask a maintainer to review it.

Openings

Openings are places where a person can pass through a boundary, such as exterior entrances, doors, and internal thresholds between spaces. Follow the same process as Amenities, but record them as openings.

Submission Instructions

Submit your map edit as a GitHub Issue by clicking "Issues" and using the provided "Add or correct a map location" template.

Useful References

About

The Beaty Biodiversity Museum's indoor mapping files.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages