This library is not production-ready yet. Developers should use it with caution and expect breaking changes.

The Story Behind Terrae

Why I built this library and what problems it solves

Challenge

Working with maps has been a challenge since my first experience with Leaflet and Vue.js back in 2019.

I had an interview with Loft Orbital, a French startup that deploys satellite infrastructure in low Earth orbit, where I was given a take-home project to build an Airbnb-like app.

The stack was restricted and they asked to use GraphQL, Leaflet, Vue, Docker, etc.

But what was challenging was the integration of Leaflet (no LLMs at that time), and due to the tiny community of Vue.js and my limited experience with maps, I could not finish the project on time.

Even though they gave me a chance to continue working on it, I couldn't finish the project on time. That's when I realized how broken the map development experience was.

At that time, I was implementing everything imperatively using the Leaflet API by calling functions and passing parameters to draw layers.

Everything was considered a layer.

On the other hand, implementing animated layers could take an entire day just to have a basic animation.

Years later, I had a technical interview with Credium, where I was assigned a take-home project to build a prototype for a solar system.

The challenge they had was to have a feature that allows users to select roof surfaces and panels individually. There were other features, but they were classic. The challenging one was the selection.

I was thinking at that time about using maps. But I could not make it with static map images. The API was returning a static image which already contained drawn roof surfaces and solar panels on top of the building, and making that interactive was impossible.

Then, after joining Credium and a year later, I started thinking about how I could make this solution feasible. I was spending time after work learning more about Mapbox, Three.js, and trying open-source tools and libraries.

I was looking for a shortcut.

Eventually, I managed to implement the solution to simulate roof surface and solar panel selection, but I did it in an imperative way using the Mapbox GL JS library, where also everything is a layer.

This took me a long time because I had to deep dive with Mapbox GL JS, understand how layers and sources work, manage refs and state for map instances, handle effects for cleanup, and wire it all together in Next.js.

As an engineer who is eager to solve problems, especially building tools for other engineers, I started thinking about a solution, whether it was worth working on and whether it would actually solve the problem.

My initial idea was to build on top of Google Maps, but I quickly realized it was too challenging and not opinionated enough for the kind of composable, declarative components I wanted to create. Mapbox GL JS proved to be the perfect fit.

It's flexible, powerful, and has the right level of opinion to build beautiful, composable components on top of it. But Mapbox itself has fundamental design decisions that make React integration awkward:

  • Everything is a layer. Mapbox treats markers, lines, polygons, and animations all as layers with sources, making simple tasks verbose and complex

  • Animations are imperative. Creating animated routes or moving markers requires manual frame-by-frame updates, timers, and state management

  • React libraries copy the same anatomy. Existing wrappers like react-map-gl mirror Mapbox's layer-source pattern, forcing you to think in Mapbox terms rather than React components

  • Plugin fragmentation. Need a geocoder? A draw tool? Export functionality? Each requires a separate plugin from a different maintainer, with inconsistent APIs, varying TypeScript support, and uncertain maintenance status. The same applies to MapLibre

Solution

Existing Mapbox implementations in React felt clunky and required too much boilerplate. So I built Terrae, a collection of beautiful, animated, composable map components that embrace declarative patterns, focus on the interactive parts of maps, and work seamlessly with React and shadcn/ui.

No more layers. Everything is a component.

What makes Terrae different:

  • Component-first anatomy. Instead of layers and sources, you work with intuitive components like MapMarker, MapLine, and MapPolygon

  • Declarative animations. Animated routes, pulsing markers, and camera follows are just props, not imperative loops. Write <MapLineAnimated /> instead of managing requestAnimationFrame

  • Idiomatic React. Compose components naturally with children, use familiar props, and let React handle the lifecycle

  • No Mapbox mental model. Forget layers, sources, and GeoJSON specs. Just use components that do what their names say

Inspiration

This project is inspired by MapCN, a project by Anmol Saini. Building on these foundations, I created Terrae to bring declarative map components to React with a focus on simplicity and composability.