ascii-globe
v0.5.0
Published
Isomorphic ASCII globe renderer
Maintainers
Readme
Zero dependencies isomorphic ASCII-Art globe renderer in JavaScript.
See Live Demo
Installation
npm
npm install ascii-globeCDN
<!-- IIFE (global variable) -->
<script src="https://cdn.jsdelivr.net/npm/ascii-globe"></script>
<!-- ES Module -->
<script type="module">
import Globe from 'https://esm.run/ascii-globe';
</script>Usage
ES Module (Node.js / Vite / bundlers)
import Globe from 'ascii-globe';
const globe = new Globe({ size: 1.4 });
console.log(globe.render(90));CommonJS (Node.js)
const Globe = require('ascii-globe');
const globe = new Globe({ size: 1.4 });
console.log(globe.render(90));Browser (script tag)
<pre id="output"></pre>
<script src="https://cdn.jsdelivr.net/npm/ascii-globe"></script>
<script>
var globe = new Globe({ size: 1 });
document.getElementById('output').textContent = globe.render(0);
</script>Browser (ES Module)
<pre id="output"></pre>
<script type="module">
import Globe from 'https://esm.run/ascii-globe';
const globe = new Globe({ size: 1 });
document.getElementById('output').textContent = globe.render(0);
</script>API
new Globe(options?)
Creates a new globe instance.
| Option | Type | Default | Description |
|----------------|----------|---------|-----------------------------------------------------|
| size | number | 1.4 | Scale factor. 1 produces a 120x60 character grid. |
| map | string | — | Base64-encoded map data. Defaults to the built-in Earth map. |
| land | string | '#' | Character used to render land masses. |
| water | string | '-' | Character used to render water/ocean. |
| background | string | ' ' | Character used for the area outside the globe disk. |
| margin | number | 0 | Number of characters around the globe disk. |
| marginBlock | number | 0 | Vertical margin (overrides margin). |
| marginInline | number | 0 | Horizontal margin (overrides margin). |
| padding | number | 0 | Thickness (in characters) of a circular gap between the globe and the border. |
| border | string | '#' | Character used to draw the circular border/glow ring in the default (non-format) renderer. Only has an effect when borderWidth is set. |
| borderWidth | number | 0 | Thickness (in characters) of the border ring. This is what turns the ring on — border alone does nothing. |
| pin | string | '@' | Default character for location pins. Can include ANSI escape codes. |
| pinSize | number | 1 | Default size multiplier for pin markers. |
| pins | Pin[] | [] | Array of pin locations. |
| tilt | number | 0 | Axial tilt in degrees (Earth's tilt is 23.5°). |
| speed | number | 0.7 | Rotation speed in degrees per frame. |
| format | function | — | Callback (type, length) => string for custom output (see below). |
Pin object
| Property | Type | Required | Description |
|----------|----------|----------|--------------------------------------------------------------------|
| lat | number | yes | Latitude in degrees (-90 to 90). |
| long | number | yes | Longitude in degrees (-180 to 180). |
| char | string | no | Override character for this pin. Can include ANSI escape codes. |
| size | number | no | Size multiplier for this pin (overrides pinSize). |
format(type, length)
When provided, render() calls this function for each run of consecutive cells of the same type instead of using the land/water/background/border/pin characters. This lets you wrap output in HTML tags, ANSI codes, or any other markup.
Cells are numbered outward-in: background is always 0, the border ring and padding ring (when enabled) take the next slots in that order, then water, land, and pins. The border ring is enabled by borderWidth > 0 — the border character is only used by the default (non-format) renderer, so with format you don't need to set it at all. Padding is enabled by padding > 0.
| borderWidth > 0 | padding > 0 | Type values |
|--------------------|----------------|-----------------------------------------------------------|
| no | no | 0 Background, 1 Water, 2 Land, 3+ Pin |
| yes | no | 0 Background, 1 Border, 2 Water, 3 Land, 4+ Pin |
| no | yes | 0 Background, 1 Padding, 2 Water, 3 Land, 4+ Pin |
| yes | yes | 0 Background, 1 Border, 2 Padding, 3 Water, 4 Land, 5+ Pin |
For the pin case, the index into the pins array is type - pinsStartType, where pinsStartType is the last number in the row above (e.g. 3 in the first row, 5 in the last).
Example — a colored glow using format, without setting a border character:
const globe = new Globe({
size: 1,
padding: 1,
borderWidth: 1,
format(type, length) {
const chars = [' ', '*', ' ', '-', '#'];
const colors = ['', 'cyan', '', '', ''];
const text = chars[type].repeat(length);
if (!colors[type]) return text;
return `<span style="color:${colors[type]}">${text}</span>`;
}
});Example — HTML colored output:
const globe = new Globe({
size: 1,
pins: [{ lat: 52.23, long: 21.01 }],
format(type, length) {
const chars = [' ', ' ', '#', '@'];
const colors = ['', '', 'green', 'red'];
const text = chars[type].repeat(length);
if (!colors[type]) return text;
return `<span style="color:${colors[type]}">${text}</span>`;
}
});
pre.innerHTML = globe.render(250);Custom maps
The library ships with an Earth map by default, but you can use a different map by passing
the map option. The package includes a built-in Death Star map:
import Globe from 'ascii-globe';
import deathStar from 'ascii-globe/maps/death-star';
const globe = new Globe({ map: deathStar, land: '#', water: ' ' });
console.log(globe.render(0));With a script tag (no modules), load the map as a separate script. The load order doesn't matter:
<pre id="output"></pre>
<script src="https://cdn.jsdelivr.net/npm/ascii-globe"></script>
<script src="https://cdn.jsdelivr.net/npm/ascii-globe/dist/maps/death-star.global.js"></script>
<script>
var globe = new Globe({ map: Globe.maps['death-star'], land: '#', water: ' ' });
document.getElementById('output').textContent = globe.render(0);
</script>You can also generate your own map data from any equirectangular projection image (see Generating custom map data below).
globe.render(rotation)
Returns a string with the ASCII globe rendered at the given rotation.
rotation— a single number (horizontal angle in degrees) or a[horizontal, vertical]pair. Values wrap around automatically.
globe.render(90); // horizontal rotation only
globe.render([90, 30]); // horizontal + vertical tiltCLI
npx ascii-globe --rotation 200
npx ascii-globe --animateOr install globally:
npm install -g ascii-globe
globe --rotation 200
globe --animateASCII Globe v0.4.2 - Isomorphic ASCII globe renderer
Usage: globe <--rotation <degrees> | --animate> [options]
Options:
--rotation <degrees> Rotation angle (single number or h,v pair)
--animate Animate the globe in the terminal
--size <number> Globe size multiplier (default: 1.4)
--map <file> Path to a map data file (generated by extract-texture)
--land <char> Character for land (default: #)
--water <char> Character for water (default: -)
--background <char> Character for background (default: " ")
--margin <number> Characters around the globe (default: 0)
--margin-block <n> Vertical margin (overrides --margin)
--margin-inline <n> Horizontal margin (overrides --margin)
--padding <number> Circular gap between the globe and the border (default: 0)
--border <char> Character for a circular border/glow around the globe (default: #)
--border-width <n> Thickness of the border ring; turns it on (default: 0, or 1 if --border is set)
--pin <char> Character for location pins (default: @)
--pin-size <number> Size of pin markers (default: 1)
--pins <coords> Pin locations as lat,long pairs separated by ;
--tilt <degrees> Axial tilt in degrees (default: 0)
--speed <number> Rotation speed in degrees per frame (default: 0.7)
--help Show this help message
-v, --version Show version number
Either --rotation or --animate is required.Example with pins (Warsaw and New York):
globe --rotation 250 --pins '52.23,21.01;40.71,-74.01'
globe --rotation 250 --pin '\x1b[31m@\x1b[m' --pins '52.23,21.01'Example with a circular glow around the globe (1 character of padding, # border):
globe --rotation 0 --padding 1 --border '#'Example with a custom map:
globe --rotation 40,20 --map ./my-map.js --land '#' --water ' 'Examples
Node.js terminal animation
import Globe from 'ascii-globe';
const globe = new Globe({ size: 1, land: '#', water: ' ', tilt: 23.5 });
let rotation = 0;
process.stdout.write('\x1B[?25l'); // hide cursor
setInterval(() => {
process.stdout.write('\x1B[2J\x1B[H'); // clear + home
process.stdout.write(globe.render(rotation));
rotation = (rotation + globe.speed) % 360;
}, 1000 / 30);Run the included example:
npm run example:nodeBrowser animation
<pre id="globe"></pre>
<button id="toggle">Pause</button>
<input id="rotation" type="number" min="0" max="360" step="0.1" value="0" disabled>
<script src="https://cdn.jsdelivr.net/npm/ascii-globe"></script>
<script>
var globe = new Globe({ size: 1, land: '#', water: ' ' });
var pre = document.getElementById('globe');
var playing = true;
var rotation = 0;
function loop() {
pre.textContent = globe.render(rotation);
if (playing) {
rotation = (rotation + 0.7) % 360;
requestAnimationFrame(loop);
}
}
document.getElementById('toggle').addEventListener('click', function() {
playing = !playing;
if (playing) loop();
});
loop();
</script>Open examples/browser/index.html via a local server to run the included browser demo.
Generating custom map data
You can generate map data from any equirectangular projection image (2:1 aspect ratio PNG). The extract script is included in the repository:
npx tsx scripts/extract-texture.ts <image.png> --output <output.ts>Options:
| Flag | Description |
|----------------|----------------------------------------------------------|
| --output <path> | Output file path (default: src/maps/<name>.ts) |
| --grayscale | Use brightness instead of Earth-specific color detection |
| --alpha | Use the alpha channel as the mask (opaque = land) |
| --invert | Invert the mask (swap land and water) |
The default mode classifies pixels using Earth-specific color heuristics (blue → water,
dark → land). Use --grayscale or --alpha for non-Earth images.
The output file can be imported and passed to the map option:
import Globe from 'ascii-globe';
import myMap from './my-map.ts';
const globe = new Globe({ map: myMap });Or used with the CLI:
globe --rotation 90 --map ./my-map.tsBuilding from source
npm install
npm run extract # generate src/maps/ from globe.png and death-star.png
npm run build # compile TypeScript to dist/License
Copyright (c) 2026 Jakub T. Jankiewicz
Released under the MIT License. See LICENSE for details.
