npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mapcraft

v0.2.0

Published

Kick-starting development of web maps built around Mapbox GL JS.

Downloads

145

Readme

Index

Installation

Use as a node module:

npm install mapcraft --save

Or clone this repository, build a bundle, and add it to your html file.

git clone https://github.com/iding-ir/mapcraft.git
cd mapcraft
npm run build

To run the example:

npm start

Examples

Demo - Github

Demo - Github

Why Mapcraft?

Mapbox GL JS is a wonderful library, but starting to develop a single page app with it can be a slow task.

Would it not be great if you initialized your map in an instant so you could jump into your real code?

Take adding custom icons/images for example (official documents). It's not the prettiest of codes, and if you want to add multiple images it becomes even worse:

map.on("load", function() {
  map.loadImage("https://address/to/image/default.png", function(error, image) {
    if (error) throw error;

    map.addImage("default", image);

    map.loadImage("https://address/to/image/cat.png", function(error, image) {
      if (error) throw error;

      map.addImage("cat", image);

      map.loadImage("https://address/to/image/dog.png", function(error, image) {
        if (error) throw error;

        map.addImage("dog", image);

        map.addLayer({
          id: "points",
          type: "symbol",
          source: {
            type: "geojson",
            data: {
              type: "FeatureCollection",
              features: [{
                type: "Feature",
                geometry: {
                  type: "Point",
                  coordinates: [0, 0]
                }
              }]
            }
          },
          layout: {
            "icon-image": [
              "case", ["==", ["get", "icon"], "cat"],
              "cat", ["==", ["get", "gender"], "dog"],
              "dog",
              "default"
            ],
            "icon-size": 1
          }
        });
      });
    });
  });
});

Since Mapbox doesn't provide Javascript Promises, you will end up adding to your code indent for every custom image that you add.

There is a second option tho, creating Sprites, custom style files and hosting them which is an even bigger hassle.

But what if you could load custom icons like this when you initialized your map:

{
  default: "/path/to/default.png",
  cat: "/path/to/cat.png",
  dog: "/path/to/dog.png"
}

Or, if you could similarly add GeoJSON files like below, because loading and rendering GeoJSON files is not any easier.

{
  cities: "/path/to/cities.json",
  borders: "/path/to/borders.json",
  lakes: "/path/to/lakes.json"
}

Initialization

Minimal initialization:

import Mapcraft from "mapcraft";

const app = new Mapcraft({
  env: {
    mapbox: {
      token: "YOUR_MAPBOX_TOKEN"
    }
  },
  map: {
    container: "map",
    center: [5, 60],
    zoom: 5,
    pitch: 50,
    bearing: 0,
    hash: false
  },
  icons: {
    house: "./icon-house.png",
    apartment: "./icon-apartment.png",
    shared: "./icon-shared.png",
    dorm: "./icon-dorm.png"
  },
  geoJsons: {
    places: "./places.json"
  }
});

Initializing with all options:

import Mapcraft from "mapcraft";

const app = new Mapcraft({
  env: {
    mapbox: {
      token: ""
    }
  },
  map: {
    container: "map",
    center: [35, 35],
    zoom: 2,
    pitch: 0,
    bearing: 0,
    hash: true
  },
  controls: {
    fullscreen: false,
    geolocation: true,
    navigation: true
  },
  colors: {
    light: {
      primary: "#1976D2",
      secondary: "#8BC34A"
    },
    dark: {
      primary: "#455A64",
      secondary: "#FFA000"
    }
  },
  defaultMapColors: {
    light: {
      background: "#0D47A1",
      fill: "#EFEBE9",
      line: "#3E2723",
      text: "#3E2723"
    },
    dark: {
      background: "#101518",
      fill: "#263238",
      line: "#E1F5FE",
      text: "#E1F5FE"
    }
  },
  useBuiltIn: false,
  styles: {
    light: "mapbox://styles/mapbox/light-v10",
    dark: "mapbox://styles/mapbox/dark-v10"
  },
  defaultStyle: "light",
  icons: {
    default: "/mapcraft/images/icon-default.png"
  },
  defaultIcon: "default",
  geoJsons: {},
  layers: {
    polygon: {
      fill: true,
      line: true
    },
    polyline: {
      line: true,
      symbol: false
    },
    point: {
      symbol: true
    }
  },
  sourcePrefix: "",
  layersPrefixes: {
    polygon: {
      fill: "polygon-fill-",
      line: "polygon-line-"
    },
    polyline: {
      line: "polyline-line-",
      symbol: "polyline-symbol-"
    },
    point: {
      symbol: "point-symbol-"
    }
  }
});

Properties

Mapbox map object will be accessible with the 'map' property of your instance.

const app = new Mapcraft({...});

let center = app.map.getCenter(...);

Contents of the GeoJSON files will be accessible with the 'geoJsons' property of your instance.

const app = new Mapcraft({
  geoJsons: {
    places: "./places.json"
  }
});

console.log(app.geoJsons.places) // Will return the GeoJson object

Unlike Mapbox 'addSource' method, adding files like this provides access to GeoJSON objects. This is essential because methods like queryRenderedFeatures and querySourceFeatures do not quite do what their names suggest and you will soon find yourself using Javascript to filter the original GeoJSON data.

GeoJSON layers that are created will be accessible like this:

const app = new Mapcraft({
  geoJsons: {
    places: "./places.json"
  }
});

// Layer id = prefix + key
app.map.on("click", "point-symbol-places", event => {
  // Your awesome code here
});

Methods

Mapcraft.fitbounds

Fits the view port into the bounds of a GeoJSON.

let myGeoJson = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              31.3330078125,
              48.60385760823255
            ],
            [
              21.97265625,
              49.49667452747045
            ],
            [
              20.214843749999996,
              42.779275360241904
            ],
            [
              27.6416015625,
              41.64007838467894
            ],
            [
              31.3330078125,
              48.60385760823255
            ]
          ]
        ]
      }
    }
  ]
}

app.fitBounds({
  geoJson: myGeoJson
});

Built-in Map

Mapbox vector tiles are great, and Mapbox Style specification is amazing, but if for any reason you want to use a built-in map of the world instead of vector tiles, copy the 'mapcraft' directory in this repository to your project root and initialize Mapcraft like this:

const app = new Mapcraft({
  defaultMapColors: {
    light: {
      background: "#0D47A1",
      fill: "#EFEBE9",
      line: "#3E2723",
      text: "#3E2723"
    },
    dark: {
      background: "#101518",
      fill: "#263238",
      line: "#E1F5FE",
      text: "#E1F5FE"
    }
  },
  useBuiltIn: true,
  styles: {
    light: "/mapcraft/jsons/styles/light/style.json",
    dark: "/mapcraft/jsons/styles/dark/style.json",
  },
  defaultStyle: "light",
});