Open-source project
hasanharman/isomiddleearth avatar
hasanharman/isomiddleearth

isomiddleearth: an isometric Middle-earth map builder in the browser

An isometric world‑builder set in Tolkien’s Middle‑earth, where you create and shape your own landscapes inspired by its iconic lands and lore.

836 stars71 forksTypeScriptLicense varies

At a glance

What is it?
This Next.js app lets you paint an isometric map of Tolkien's Middle-earth tile by tile across seven realms, export it as a PNG or as JSON, and browse community maps. It is a small, well-scoped front-end project, and the JSON format it uses for sharing is the interesting part for anyone extending it.
Who is it for?
Adopt isomiddleearth if you want a browser-based isometric map editor with a documented JSON format you can extend, or if you want to contribute tiles and characters to an existing community catalogue.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 172 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A tile grid with seven realms and a hover preview

The project is an isometric Middle-earth builder for crafting maps across multiple realms, tile by tile. The core interaction is familiar: an isometric canvas shows a grid, hovering previews the tile under the cursor, and clicking or dragging paints. Right-click clears a tile, with character overlays clearing before the terrain underneath. The grid size is adjustable from 3x3 to 20x20, which is a small decision with a large effect on what a map can contain. Seven realms are available, shire, gondor, mordor, lothlorien, rohan, moria and rivendell, plus a mixed mode that lets a single map span several of them. That mixed mode is the feature that turns this from a single-theme editor into something more useful, since a map can place a shire tile next to a gondor tile without switching tools. Assets are grouped into six categories, Terrain, Water and Bridges, Trees and Vegetation, Dwellings, Buildings and Decorations, with separate picker tabs for Buildings and Characters, and the character set currently holds 8 Hobbit sprites.

The asset layout is a plain convention, not a database

Understanding how assets are addressed tells you most of what you need to know to extend the project. Tiles live at public/tiles/<realm>/r<row>-c<col>.png, so a tile is addressed by its realm and its grid coordinates, and characters live at public/characters/<character-realm>/<character-id>.png. The sprite canvas size is 130x230 and the isometric tile footprint on the canvas is 128x64. New coordinates can be added with any non-negative row and col, and at runtime the code falls back to r0-c0 if a specific tile image is missing. That fallback is worth understanding before you add content. A missing image does not error, it renders the first tile, so a typo in a filename produces a wrong-looking map rather than a broken one, and you would have to look closely to notice. The collections are stored the same way, as files under collections/maps, with a JSON schema at collections/schema/map.schema.json, an API endpoint at GET /api/collections/:id, and documentation in collections/README.md. This is a static-file approach that fits a Next.js deployment and does not need a database, but it also means content changes are a pull request.

The JSON format is the contract worth studying

The toolbar can export and import a map as JSON, and the documented shape is small enough to read in full:

json
  "createdAt": "2026-02-24T00:00:00.000Z",
  "location": "mixed",
  "gridSize": 7,
  "map": [
    [[0, 0, "shire"], [2, 4, "gondor"]],
    [[1, 6, "mordor"], [3, 2, "rivendell"]]
  ]
}

The rules are stated plainly. A tile is either [row, col] or [row, col, realm], so a map inherits the realm of the editor it was made in unless a tile overrides it. Row and col are non-negative integers and gridSize must be between 3 and 20. There is a schemaVersion field, which is the right way to evolve a format. There is also an explicit limitation: the current JSON import and export is tile-map based and character overlays are not part of the format yet. That is a real gap for anyone who builds a map around Hobbit sprites and then tries to share it, and it is documented rather than hidden. The format also carries id, name, an author object with a name and a GitHub username, and a createdAt timestamp, which are exactly the fields a community catalogue needs.

A community browser with deep links and a validation script

Maps can be shared through the collections browser at /collections, which lists community maps with pagination, and a specific map can be opened directly with a query parameter, /?collection=<map-id>. Because the collections are files in the repository and the endpoint is a Next.js route, a deep link works without any server-side lookup table. The editor also keeps state locally through Zustand, persisted to localStorage, so a work in progress survives a page reload without a server round trip. There is a dedicated validation script for the collection files:

bash
pnpm validate:collections

which is wired into package.json as validate:collections and runs node scripts/validate-collections.mjs. A schema file exists for the maps, so the validation script presumably checks the collection files against it, and this is the piece that keeps a file-based catalogue honest as people contribute. The trade-off is that publishing a collection means opening a pull request against the repository, which is slower than a form post but gives every map a review and a history.

Running it takes a clone and pnpm dev

The prerequisites are Node.js 18 or newer and pnpm 9 or newer, and the setup is three commands:

bash
git clone https://github.com/hasanharman/isomiddleearth.git
cd isomiddleearth
pnpm install
pnpm dev

The dev script runs next dev, and the app is then on http://localhost:3000. The other scripts in package.json are build with next build, start with next start, lint with eslint, and validate:collections. There is a live deployment at isomiddleearth.com, and the demo image in the README is the fastest way to see what the output looks like before you install anything. The workflow for using it is short: pick a realm or Mixed from the top location selector, choose an asset tab in the bottom bar, click or drag to paint, right-click to clear, and then use the toolbar for undo, grid resize, PNG export and JSON import and export. Undo is bound to Cmd or Ctrl with Z, and PNG export is done through the html-to-image library.

A Next.js 16 front end with Zustand and Radix

The tech stack is stated in the README and confirmed by the dependency list in package.json. Next.js 16.1.6 with React 19.2.3 and TypeScript 5, Zustand 5.0.11 for state, Tailwind CSS 4 for styling, and Radix UI with shadcn components, with a components.json file at the root and a components/ directory holding the generated pieces. There is a components.json, an eslint.config.mjs, a postcss.config.mjs, a next.config.ts, a tsconfig.json, an app/ directory for routes, a lib/ directory, a public/ directory for the asset tree, and an output/ directory. The dependency set is small and mostly conventional for a Next.js app: lucide-react for icons, the hugeicons packages, sonner for toasts, next-themes for theming, clsx and tailwind-merge for class handling, and class-variance-authority. The Vercel analytics and speed-insights packages are also there, which tells you the deployed instance is on Vercel. The package is private and versioned 0.1.0, with pnpm 10.17.0 pinned as the package manager, and both a pnpm-lock.yaml and a package-lock.json in the repository.

No licence file, and a last push in May

Two things to sort out before you build on this. First, licensing. The project is derived from Tolkien's Middle-earth, and the repository contains no licence file at all: the top-level entries are the .github directory, .gitignore, README.md, the app, collections, components, config files, lib, output, the lock files, package.json, public, scripts and tsconfig.json, with no LICENSE entry among them. The README badge for the licence points at the GitHub licence endpoint, which would render as unknown for a repository without one. That is a genuine question for a project built on a copyrighted setting and on art assets of unclear provenance, and it is not something to resolve by assumption. Second, maintenance. The repository is not archived and the last push was on 2026-05-08, with no GitHub releases at all. So the project is a working snapshot rather than a versioned release line, and the version in package.json is 0.1.0 with no tags to pin against.

Editorial conclusion

Adopt isomiddleearth if you want a browser-based isometric map editor with a documented JSON format you can extend, or if you want to contribute tiles and characters to an existing community catalogue. Do not adopt it expecting a game engine or a 3D tool, since it renders a fixed isometric tile grid on a canvas, and do not assume the collection infrastructure is production ready, since collections are read from the filesystem under collections/maps and validated by a script rather than served from a database. Before you commit, check the asset paths under public/tiles and public/characters, because a missing tile image silently falls back to r0-c0, and confirm the licensing position of the art yourself, since the repository contains no licence file.

Frequently asked questions

What is isomiddleearth?

It is an isometric Middle-earth map builder for crafting maps across multiple realms, tile by tile. It is a TypeScript Next.js app with seven realms plus a mixed mode, adjustable grid sizes from 3x3 to 20x20, character overlays, PNG export and JSON import and export.

How do I run isomiddleearth locally?

You need Node.js 18 or newer and pnpm 9 or newer. Clone the repository, then run pnpm install and pnpm dev, which starts next dev, and open http://localhost:3000.

What format does the isomiddleearth JSON export use?

A tile is [row, col] or [row, col, realm], with non-negative integers for the coordinates, a gridSize between 3 and 20, and a schemaVersion field. The current format is tile-map based, so character overlays are not included in JSON import and export yet.

How do I add new tiles or characters to isomiddleearth?

Tiles are read from public/tiles/<realm>/r<row>-c<col>.png and characters from public/characters/<character-realm>/<character-id>.png. You can add new coordinates with any non-negative row and col, and the runtime falls back to r0-c0 if a specific tile image is missing.

Official sources

  1. hasanharman/isomiddleearth on GitHub
  2. Issues
  3. Project website
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/hasanharman-isomiddleearth.svg)](https://hysenlabs.com/projects/hasanharman-isomiddleearth)

Was this useful?