An open API service indexing awesome lists of open source software.

https://github.com/jcubic/ascii-globe

Zero dependencies isomorphic ASCII-Art globe renderer in JavaScript
https://github.com/jcubic/ascii-globe

3d animation ascii ascii-art ascii-art-generator cartography globe

Last synced: about 1 month ago
JSON representation

Zero dependencies isomorphic ASCII-Art globe renderer in JavaScript

Awesome Lists containing this project

README

          

# ![ASCII-Globe](https://github.com/jcubic/ascii-globe/blob/master/.github/logo.svg?raw=true)

[![npm](https://img.shields.io/badge/npm-0.4.2-yellow.svg)](https://www.npmjs.com/package/ascii-globe)
[![github repo](https://img.shields.io/badge/github-repo-orange?logo=github)](https://github.com/jcubic/ascii-globe)
![NPM Downloads](https://img.shields.io/npm/dm/ascii-globe)
[![jsDelivr hits (npm)](https://img.shields.io/jsdelivr/npm/hm/ascii-globe)](https://www.jsdelivr.com/package/npm/ascii-globe)
[![LICENSE MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jcubic/ascii-globe/blob/master/LICENSE)

Zero dependencies isomorphic ASCII-Art globe renderer in JavaScript.

See [Live Demo](https://codepen.io/jcubic/full/EaNaRVp)

## Installation

### npm

```bash
npm install ascii-globe
```

### CDN

```html

import Globe from 'https://esm.run/ascii-globe';

```

## Usage

### ES Module (Node.js / Vite / bundlers)

```javascript
import Globe from 'ascii-globe';

const globe = new Globe({ size: 1.4 });
console.log(globe.render(90));
```

### CommonJS (Node.js)

```javascript
const Globe = require('ascii-globe');

const globe = new Globe({ size: 1.4 });
console.log(globe.render(90));
```

### Browser (script tag)

```html

var globe = new Globe({ size: 1 });
document.getElementById('output').textContent = globe.render(0);

```

### Browser (ES Module)

```html

import Globe from 'https://esm.run/ascii-globe';

const globe = new Globe({ size: 1 });
document.getElementById('output').textContent = globe.render(0);

```

## 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`). |
| `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`/`pin` characters. This lets you wrap output in HTML tags, ANSI codes, or any other markup.

| Type value | Meaning |
|------------|------------|
| `0` | Background |
| `1` | Water |
| `2` | Land |
| `3+` | Pin (index `type - 3` in the `pins` array) |

Example — HTML colored output:

```javascript
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 `${text}`;
}
});

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:

```javascript
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:

```html

var globe = new Globe({ map: Globe.maps['death-star'], land: '#', water: ' ' });
document.getElementById('output').textContent = globe.render(0);

```

You can also generate your own map data from any equirectangular projection image
(see [Generating custom map data](#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.

```javascript
globe.render(90); // horizontal rotation only
globe.render([90, 30]); // horizontal + vertical tilt
```

## CLI

```bash
npx ascii-globe --rotation 200
npx ascii-globe --animate
```

Or install globally:

```bash
npm install -g ascii-globe
globe --rotation 200
globe --animate
```

```
ASCII Globe v0.4.2 - Isomorphic ASCII globe renderer

Usage: globe <--rotation | --animate> [options]

Options:
--rotation Rotation angle (single number or h,v pair)
--animate Animate the globe in the terminal
--size Globe size multiplier (default: 1.4)
--map Path to a map data file (generated by extract-texture)
--land Character for land (default: #)
--water Character for water (default: -)
--background Character for background (default: " ")
--margin Characters around the globe (default: 0)
--margin-block Vertical margin (overrides --margin)
--margin-inline Horizontal margin (overrides --margin)
--pin Character for location pins (default: @)
--pin-size Size of pin markers (default: 1)
--pins Pin locations as lat,long pairs separated by ;
--tilt Axial tilt in degrees (default: 0)
--speed 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):

```bash
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 custom map:

```bash
globe --rotation 40,20 --map ./my-map.js --land '#' --water ' '
```

## Examples

### Node.js terminal animation

```javascript
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:

```bash
npm run example:node
```

### Browser animation

```html



Pause

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();

```

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:

```bash
npx tsx scripts/extract-texture.ts --output
```

Options:

| Flag | Description |
|----------------|----------------------------------------------------------|
| `--output ` | Output file path (default: `src/maps/.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:

```javascript
import Globe from 'ascii-globe';
import myMap from './my-map.ts';

const globe = new Globe({ map: myMap });
```

Or used with the CLI:

```bash
globe --rotation 90 --map ./my-map.ts
```

## Building from source

```bash
npm install
npm run extract # generate src/maps/ from globe.png and death-star.png
npm run build # compile TypeScript to dist/
```

## Acknowledgments

World map texture by Ebrahim; [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0); source [Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Equirectangular_projection_world_map_without_borders.svg).

## License

Copyright (c) 2025 [Jakub T. Jankiewicz](https://jakub.jankiewicz.org/)

Released under the MIT License. See [LICENSE](https://github.com/jcubic/ascii-globe/blob/master/LICENSE) for details.