Skip to content
Hooney
한국어

Engines & modules · In use

maps

A map package that wraps the MapLibre GL library so React screens use maps like ordinary components, in three layers: setting up the map, reading it, and adding features.

3Layers: setting up the map, reading it, and adding features

Period
2026.04 ~ Present
Organization
Firstage
Role
Design and implementation (solo)
Place discovery on the Firstage homepage: clusters counting places over a satellite map of Seoul, a place list on the left, and a 'Search this area' button on top.

Core value

Screens with a map never handle the map library directly; they pick only what they need, such as place clusters or routes.

Outcomes

  • Powers maps in Journey, on the homepage, and in blog posts
  • Gathered map code that each screen wrote on its own into one package
  • Shows a loading view until the map is drawn, never an empty globe

Tech stack

  • MapLibre GL
  • React
  • TypeScript

Context

The map is the central Firstage screen for showing where photos were taken. As more screens gained a map, from photo maps and place screens in the Journey app to place exploration on the Firstage homepage, code that drove MapLibre instances directly spread across screens, each with its own branches. I gathered that code into one package so each screen picks only the map features it needs.

Decisions and implementation

  • A single MapView provider creates the map instance, and child components read it through hooks. Clustering, routes, markers, camera persistence, and other features are opt-in plugins, so a screen’s bundle leaves out what it does not use.
  • Marker diffing, coordinate keys, projection math, and cluster policy live in a React-free shared layer, and dependencies may only point from the map layer to the shared layer.
  • MapLibre is only the current renderer, so apps never create a MapLibre map object themselves. Camera, click, and GeoJSON layer access go through renderer-neutral hooks, so another renderer would only need to implement the same contract inside the package.
  • The map initializes only on the client and keeps its loading view until the first tiles actually render, so an empty globe never appears first. Server rendering does not break it.
  • There is no built-in data fetching. The map reports camera state, and each screen decides when to run a search and how to page through the results.

Current state

Photo maps and place screens in the Journey app, place exploration and course maps on the Firstage homepage, and maps inside blog posts use this package. Renderers other than MapLibre exist only as a contract and are not implemented yet.

The full route map on a Firstage course page, with a path joining the course's places in order over a satellite map of Busan.
The concert venue map in a Firstage social story, marking three venues on a satellite map of the Seoul area.
The globe map on the Firstage homepage: under a globe on a phone screen, photos are grouped by place in Jongno, Seoul.