skip to content
GIS for Design Practices

This tutorial will help you publish a web map using the style you created in the last exercise, along with Maplibre, Github, and Github Pages.

Maplibre is a free and open-source fork of Mapbox GL JS, which is a JavaScript library for creating interactive web maps. Maplibre is a powerful tool that allows you to create custom web maps with a wide range of features, such as custom styles, vector tiles, and interactivity. Github Pages is a free service offered by Github that allows you to host static websites for free. You can publish your map to the web using Github Pages, allowing you to share your work with others. You can also host your map using services like cloudflare, render, netlify, or vercel, but this tutorial will focus on Github Pages.

Both of the templates below describe each of their maps in a YAML file rather than in JavaScript, using a library called maplibre-yaml. You will write the map you want — its basemap, its starting view, and the layers drawn on it — as a list of settings, and the library builds the MapLibre map from it.

Deliverables

  • Link to your github repository, containing the code for your web map.
  • A link to your published web map.

Data

  • None (you provide your own style and data).

Choosing a template

There are two templates to choose from. They produce the same map, and they describe it with the same kind of YAML file; what differs is the website built around the map. Pick one and work through that section only.

Plain HTML is the one to start with if you have no web development experience, and you know your app/page will not grow in complexity. The site is a folder of .html files, and there is nothing to install and no build step: you edit the HTML and the YAML files, and the folder is published exactly as it is. MapLibre itself is loaded from the web each time a page opens, which keeps the project small but means your published site depends on that service staying up. You will also need to run a small web server on your own computer to preview the site, because browsers will not load the map files from a page you open by double-clicking it. Software like VSCode make it easy to run these servers.

Astro is a popular web framework for building content-forward static sites. It’s beauty is it builds the site from source files before publishing it. Pages are written in Markdown rather than HTML, images are resized for you, and a mistake in a map file stops the build with the file and line number instead of publishing a broken map. It requires a bit more setup and configuration, but it provides a more robust and maintainable solution for building portfolio or project sites. There are additional steps to get up and running, but it is a powerful tool for creating modern web experiences that scale beyond a single page. The course website is an Astro site written almost entirely in Markdown.

The YAML (map configuration file) you write is the same in both, with one difference worth knowing before you start: in the plain HTML template paths never begin with a /, and in the Astro template they always do. Each section below is written for its own template, so follow the one you picked and do not mix the two. Switching later is not that hard, so feel free to try one and the other if you get curious.

Exercise (plain HTML)

Getting started

  • Navigate to the course webmap template repository and click the “Use this template” button, then choose “Create a new repository”. This will create a copy of the repository in your Github account that you can edit.

  • Give your new repository a name of your own. This name becomes part of your website’s address, so pick something you would not mind reading in a url: g4dp-atlas rather than html-maplibre-template-1. Set the repository to Public — Github Pages will not publish a private repository on a free account. Keep the other default settings.

use this template
  • Now that you have your own working copy of the repository, use the online Github interface or the Github Desktop application to clone the repository to your local machine. This will create a copy of the repository on your computer that you can edit using a text editor. See here for instructions on how to clone a repository.

  • Open the repository in the text editor you downloaded last week. There is no project to configure and nothing to install: the folder you are looking at is the website. Four pages sit at the top of it — index.html, inline-maps.html, full-page-map.html and scrollytelling.html — alongside the folders they draw from.

  • Three of those folders matter most for this exercise. maps holds one YAML file per map on the site. data holds the GeoJSON layers drawn on those maps. css/site.css holds the styling for the site as a whole. Your map style will go in the top folder, next to index.html.

  • When VS Code offers you the recommended extensions for this folder, accept them. YAML gives you autocomplete and error underlines inside the map files, and Live Server is what you will use to preview the site.

Naming your site

Github Pages will publish your site at https://<your-username>.github.io/<your-repo>/, where <your-repo> is the name you chose previously. You do not have to write that address anywhere: every path in this template is relative, so the same files work both on your computer and on the published site.

What you should change is the site’s name. It reads Project Website in the header of all four .html files, as well as in each page’s <title> and <meta name="description"> near the top of the file. Change it in each one. Note that the header is copied into every page rather than shared between them, so if you add a page of your own later, you will need to add its link to the other pages by hand.

Adding your map style file

Drag and drop your style.json file into the top folder of the repository, next to index.html.

html template file tree

Keep your own files in the folders at the top of the repository — maps, data, img — and keep your pages next to index.html. Paths in this template are written relative to the page, and they only line up if the files sit where the template expects them.

Adding your map style to the map

For this initial example, we will create a full page map, with sample layers, to demonstrate the process of adding a map style to a web map and loading layers.

First, we need to obtain an API key from Protomaps to be able to use their tile server. Go to Protomaps and sign up for an account. Once you have an account, you can generate an API key by clicking on the “Add API Key” button. Give your key a name (e.g. g4dp-api-key) and leave the other settings as default. Copy the API key to your clipboard. The key will be a 16-digit alphanumeric string.

Note: Your map style may be based on another provider besides Protomaps. If you are using a different tile server, you will need to obtain an API key from that provider and follow their instructions for adding the key to your map style. Look at the base url in your style.json file to determine which tile server you are using. If, for example, you are using a MapTiler-based stlye, go to https://cloud.maptiler.com/maps/ instead to create an API key.

generate api key

Open your style.json file. Toward the top of the JSON object, you will see a sources object with a protomaps source. Add your newly generated API key after key=, replacing the testing key generated by Maputnik:

add your api key

Now open maps/full-page.yaml. This is the file that describes the full page map. A YAML file is a human-readable data serialization format that is commonly used for configuration files. Each map file has two parts that concern us here: a config block holding the map’s basemap and starting view, and a layers list holding the data drawn on top of it.

The template ships with a keyless sample basemap. Replace that URL with the path to your own style file:

type: map
id: full-page
config:
mapStyle: "style.json"
center: [-73.97228, 40.74921]
zoom: 13.81

Take note of each of these keys:

  • type and id identify the file to the library. Leave type: map alone; id is a short name of your choosing.
  • mapStyle is your basemap. style.json is the file you just dragged in, found next to the page that shows the map. The path must exactly match where the file is relative to the page that shows the map. You can also give a full https:// url here to use someone else’s style.
  • center is the initial center of the map, written as [longitude, latitude]. Note the order: longitude first. This is the reverse of what Maputnik showed you.
  • zoom is the initial zoom level of the map.

Recall the address bar in Maputnik from the last tutorial, which read something like #13.81/40.74921/-73.97228. That is zoom, then latitude, then longitude. To use it here, keep the zoom as it is and swap the last two numbers around into center.

You can also add interactive: false under config to make a map that does not pan or zoom, which is useful for a locator map. It is true by default.

The page that shows the map

Open full-page-map.html in VSCode. This is an ordinary HTML page, which you can edit in any text editor. The part of the file that draws the map reads:

<ml-map src="maps/full-page.yaml" class="full-page-map">
<div slot="top-left" class="map-note">
<strong>Central Park</strong><br />
Squirrel sightings and Manhattan's bike lanes.
</div>
</ml-map>
ml-map element

<ml-map> is not one of the standard HTML elements. It is defined by the block at the top of the page, inside <head>, which loads MapLibre and maplibre-yaml from the web:

<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@6/dist/maplibre-gl.css" />
<link rel="stylesheet" href="css/site.css" />
<script type="importmap">
{ "imports": { "maplibre-gl": "https://unpkg.com/maplibre-gl@6/dist/maplibre-gl.mjs" } }
</script>
<script type="module" src="https://unpkg.com/@maplibre-yaml/[email protected]/register.js"></script>

If you make a page of your own later on, copy that whole block into its <head>, or the maps on your page will not appear.

Note that the map’s center and zoom are not set in the page. Everything about the map itself lives in the YAML file, and the page only says which file to draw and how big to draw it. The element takes a small number of attributes:

  • src is the map file to draw. This is the only required attribute.
  • class and style are CSS applied to the map container. full-page-map is defined in css/site.css and makes the map fill the window below the site header. Any other map needs a height of its own, either from a CSS class or written in place as style="height: 60vh;" — without one the element has no height by default and the map is invisible.
  • A child element with slot="top-left" (or top-right, bottom-left, bottom-right) sits in that corner of the map, as the note in the example does.

The <body> of this page also carries class="bleed", which removes the page padding and the footer so that one map can fill the window.

Previewing your site locally

In VS Code, open the project folder, install the recommended Live Server extension, then click Go Live in the bar at the bottom of the window. Your browser opens at http://127.0.0.1:5500/, and the page reloads every time you save a file.

go live

Follow the “Full page map” link from the site’s home page, or go straight to http://127.0.0.1:5500/full-page-map.html.

If this is too confusing or you encounter issues, do not despair: you can bypass local previews and publish directly to your website. The tradeoff is that you will not be able to see changes in real-time, but you can still make changes to your files, commit them to your online repository, and see the results by refreshing the page. Be aware that a mistake in a map file will stop your site from being published rather than publish a broken map, so if a change of yours does not appear, read the log in the Actions tab (described below) — it reports the same file and line number you would have seen locally. Your published site stays as it was until a check succeeds.

Adding layers to your map

Return to maps/full-page.yaml and look at the layers list below config. This is where the data drawn on top of your basemap is described. In general, the layers adhere to the Mapbox layer specification, with information on layer source, type, and style properties.

layers:
- id: buildings
type: fill
label: Buildings
visible: false
legend: false
source:
type: vector
url: "https://tiles.openfreemap.org/planet"
source-layer: building
minzoom: 13
paint:
fill-color: "#b2182b"
fill-opacity: 0.35
- id: bike-lanes
label: Bike lanes
visible: true
type: line
source:
type: geojson
url: "data/manhattan-bike-lanes.geojson"
paint:
line-color: "#2166ac"
line-width: 2
legend: { label: Bike lanes, color: "#2166ac", shape: line }

Each layer has the following properties:

  • id: a unique identifier for the layer
  • label: the name of the layer that will be displayed in the layer switcher. A layer with a label gets a checkbox; leave it out and the layer is always on.
  • visible: whether the layer is visible by default. Set visible: false to start a layer switched off.
  • type: the type of layer. This can be fill, line, circle, symbol, or raster.
  • source: where the data comes from. For a GeoJSON file this is type: geojson and a url. Write the url as the path from the top of the repository, with no leading / — so the file data/my-file.geojson is url: "data/my-file.geojson" — or give a remote url as shown in the other sample layers in other map YAML files.
  • paint: the style properties for the layer. This is where you can customize the appearance of the layer, such as the color, opacity, and width of the lines. See the Mapbox style specification for more information on the available style properties.
  • legend: an optional entry for this layer in the legend, with a label, a color and a shape of line, circle or square.

You can add data of different formats, but GeoJSON is a good place to start for vector data.

Note that the key words and indentation are important in YAML files. If you are unfamiliar with YAML, you can read more about it here. The first line of each map file is a comment that gives your text editor autocomplete and error underlines for these keys, so leave it in place.

The file holds a few other blocks that we will not use in this tutorial: controls and legend near the top, which position MapLibre’s zoom buttons and the legend box, and classify and interactive on two of the sample layers, which color features by one of their attributes and show a popup when a feature is clicked. Feel free to experiment with them.

Publishing your map

Once you are happy with your map, you can publish it to the web using Github Pages. This is a free service offered by Github that allows you to host static websites for free. You can publish your map by following these steps:

  1. Enable Github Pages for your repository. In the Github web interface, navigate to the “Settings” tab of your repository. From the left side menu select “Pages.” Select the option to enable Github Pages for your repository. Then from the Source drop down menu select “GitHub Actions”. You have now enabled Github Pages functionality for your repository and can proceed to publish your map.
activate github pages
  1. Commit your changes to your repository. You can do this using the Github Desktop application by selecting the files you want to commit, entering a commit message, and clicking the “Commit” button. Then, click the “Push origin” button to push your changes to your online repository.
  2. In the Github web interface, navigate to the “Actions” tab of your repository. You should see a workflow listed in the left hand menu called Validate and deploy to GitHub Pages — click on this workflow to see a list of individual actions that have been run through this workflow. You will see an action running that matches the commit message you just made. It has two parts: validate checks every map file, and deploy publishes your site if the check passed. There is no build step here — the folder is published as it is.
  3. If you’re curious, you can click on either the validate or deploy nodes to see the steps that are being taken behind the scenes. The url you see in the deploy node is the address where your website is published. Your full page map is at full-page-map.html under that address.

Two things are worth knowing if a push does not show up on the site. The checker is stricter on Github than on your own computer: a problem that only prints a warning locally will fail the validate job, so read its log rather than assuming the file is fine. And if you pushed before you enabled Github Pages in step 1, the first run will have failed at the deploy step; do step 1, then open the failed run and click Re-run all jobs.

As you make changes to your files in the coming days and weeks, you will replicate this process and continue to build on these template files. For the sake of the tutorial, we have added sample layers to demonstrate how you can add layers to your map.

This exercise takes you through the simplest example, the full-page map, but take a look at the other pages types in the template- you can create scrollytelling maps, or embed maps and other content inline with text. Some of the more robust content creation and management is better suited for Astro, described below.

Exercise (Astro)

Getting started

  • Navigate to the course webmap template repository and click the “Use this template” button, then choose “Create a new repository”. This will create a copy of the repository in your Github account that you can edit.

  • Give your new repository a name of your own. This name becomes part of your website’s address, so pick something you would not mind reading in a url: g4dp-atlas rather than astro-maplibre-template-1. Set the repository to Public — Github Pages will not publish a private repository on a free account. Keep the other default settings.

use this template
  • Now that you have your own working copy of the repository, use the online Github interface or the Github Desktop application to clone the repository to your local machine. This will create a copy of the repository on your computer that you can edit using a text editor. See here for instructions on how to clone a repository.

  • Open the repository in VSCode. You will see a wide range of files and folders, which adhere to the structure of a typical Astro project. Astro is a static site generator that allows you to build websites using modern web technologies like React and Vue, but outputs static HTML, CSS, and JavaScript files. This makes it well-suited for web mapping, as it allows you to create interactive web maps without the need for a server or database. On top of that, most of the content that your users will see can be authored in Markdown, which makes Astro an ideal choice for portfolios, blogs, documentation, etc. This tutorial only scratches the surface of what Astro can do, but it is a powerful tool that you may want to explore further in the future.

  • Two folders matter most for this exercise. public holds static files that are served exactly as they are, including your map style and your data. src/maps holds one YAML file per map on the site.

Naming your site

Github Pages will publish your site at https://<your-username>.github.io/<your-repo>/, where <your-repo> is the name you just chose. The project needs to know that address before the rest of this tutorial will line up, so set it now.

In your text editor, open the astro.config.mjs file in the root directory of your project. You’ll see a variable called defineConfig, with a site and a base variable. Update site to match your Github username, and base to match your repository name:

site: "https://<your-username>.github.io",
base: "/<your-repo>",
define config

In the image above, replace design-practices with your username and astro-maplibre-template with your repository name. Note the leading / on base and that there is no trailing one. base must match the repository name exactly, including capitalization.

This is the only place that name is written: every link, map, data file and image on the site picks it up from here. If you rename the repository on Github later, change base to match.

Adding your map style file

Open the /public folder in the file tree. The public folder is where you will store any static assets that you want to include in your website, such as images, fonts, and map styles, as well as geojson layers (more on that later). Drag and drop your style.json file into this folder.

file tree

You can either right click on public to open the folder location, or find it in your file tree.

Adding your map style to the map

For this initial example, we will create a full page map, with sample layers, to demonstrate the process of adding a map style to a web map and loading layers.

First, we need to obtain an API key from Protomaps to be able to use their tile server. Go to Protomaps and sign up for an account. Once you have an account, you can generate an API key by clicking on the “Add API Key” button. Give your key a name (e.g. g4dp-api-key) and leave the other settings as default. Copy the API key to your clipboard. The key will be a 16-digit alphanumeric string.

Note: Your map style may be based on another provider besides Protomaps. If you are using a different tile server, you will need to obtain an API key from that provider and follow their instructions for adding the key to your map style. Look at the base url in your style.json file to determine which tile server you are using. If, for example, you are using a MapTiler-based stlye, go to https://cloud.maptiler.com/maps/ instead to create an API key.

generate api key

Open your style.json file. Toward the top of the JSON object, you will see a sources object with a protomaps source. Add your newly generated API key after key=, replacing the testing key generated by Maputnik:

add your api key

Now open src/maps/full-page.yaml. This is the file that describes the full page map. A YAML file is a human-readable data serialization format that is commonly used for configuration files. Each map file has two parts that concern us here: a config block holding the map’s basemap and starting view, and a layers list holding the data drawn on top of it.

The template ships with a keyless sample basemap. Replace that URL with the path to your own style file:

type: map
id: full-page
config:
mapStyle: "/style.json"
center: [-73.97228, 40.74921]
zoom: 13.81

Take note of each of these keys:

  • type and id identify the file to the library. Leave type: map alone; id is a short name of your choosing.
  • mapStyle is your basemap. The leading / means “from the public folder,” so /style.json is the file you just dragged in. You can also give a full https:// url here to use a published web style.
  • center is the initial center of the map, written as [longitude, latitude]. Note the order: longitude first. This is the reverse of what Maputnik showed you.
  • zoom is the initial zoom level of the map.

Recall the address bar in Maputnik from the last tutorial, which read something like #13.81/40.74921/-73.97228. That is zoom, then latitude, then longitude. To use it here, keep the zoom as it is and swap the last two numbers around into center.

You can also add interactive: false under config to make a map that does not pan or zoom, which is useful for a locator map. It is true by default.

The page that shows the map

Open src/pages/full_page_map.mdx. This file is written in MDX, which is a markdown syntax that allows you to embed components. This is a powerful feature of Astro, as it allows you to write markdown files that contain interactive elements, such as maps, charts, and other visualizations. The part of the file that draws the map reads:

import { FullPageMap, loadMapConfig } from "@maplibre-yaml/astro";
export const map = await loadMapConfig("./src/maps/full-page.yaml");
<FullPageMap config={map} />
full page map component

If you are familiar with HTML programming, you may recognize the structure of the <FullPageMap> component as similar to an HTML element. Two things are happening here. loadMapConfig reads the YAML file you just edited, and it does so while the site is being built: if you make a mistake in the file, the build stops and tells you the file, the line and the column, rather than publishing a broken map. <FullPageMap> then draws that map so that it fills the window below the site header, with zoom and reset buttons.

Note that the map’s center and zoom are not set here. Everything about the map itself lives in the YAML file, and the page only says which file to draw and how big to draw it. The component takes a small number of arguments:

  • config is the map to draw, as loaded above. This is the only required argument.
  • id is the ID of the HTML element that the map will be rendered in. One is generated for you if you leave it out.
  • class and style are CSS applied to the map container. You can change these to customize the appearance of the map container, and can add further css properties in styles/global.css.
  • showControls adds the zoom and reset buttons, and is true by default.
  • showLegend adds a legend box, and is false by default.

Optional: install Astro to be able to run and test your map locally

Install NPM (Node Package Manager)

If you have not already done so, you will need to install Node.js and npm to be able to run and test your map locally. You can download the installer from the Node.js website. Follow the instructions to install Node.js and npm on your computer. This template needs Node.js version 22.23.4 or later; running node --version in a terminal will tell you which version you have. Essentially, this will allow you to run JavaScript code on your computer, and will allow you to install the necessary dependencies for your project.

Install Astro

If you have not already done so, you will need to install Astro to be able to run and test your map locally. Open a terminal window and navigate to the root directory of your project. Run the following command to install the necessary dependencies:

Terminal window
cd path/to/your/project
npm install

In the above example, cd is a command that stands for “change directory”, and path/to/your/project is the path to the root directory of your project. (It will look something like /Users/marioag/Documents/GitHub/gis-for-design-practices/). You will need to replace this with the actual path to your project. You can copy and paste the path from the address bar of your file explorer, or right-click on the project folder and select “Copy path”.

npm install is a command that tells npm to install the dependencies for your project. This will install the necessary dependencies for your project, including Astro. You can see the full list of packages that will be installed in the package.json file. Once the installation is complete, you can run the following command to start the development server:

Terminal window
npm run dev

npm run dev tells npm to run the dev script in the package.json file. You can see what subcommands it runs, as well as what other commands are available in the package.json file.

This will start the development server, which will watch for changes to your files and automatically update the browser. You can open a web browser and navigate to http://localhost:4321/<your-repo>/full_page_map to see your map, using the repository name you set as base above. You can make changes to your files and see the changes reflected in the browser in real-time.

One other command is worth knowing about. npm run validate checks your map files for mistakes without building the whole site, and is much faster:

Terminal window
npm run validate

A mistake in a map file reads like this, naming the file, the problem and where to find it:

✗ src/maps/full-page.yaml
error Unknown key "cenetr" — did you mean "center"? ("center" is required here.)
at line 7, column 3

Adding layers to your map

Return to src/maps/full-page.yaml and look at the layers list below config. This is where the data drawn on top of your basemap is described. In general, the layers adhere to the Mapbox layer specification, with information on layer source, type, and style properties.

layers:
- id: bike-lanes
label: Bike lanes
visible: true
type: line
source:
type: geojson
url: "/data/manhattan-bike-lanes.geojson"
paint:
line-color: "#2166ac"
line-width: 2
legend: { label: Bike lanes, color: "#2166ac", shape: line }

Each layer has the following properties:

  • id: a unique identifier for the layer
  • label: the name of the layer that will be displayed in the layer switcher. A layer with a label gets a checkbox; leave it out and the layer is always on.
  • visible: whether the layer is visible by default. Set visible: false to start a layer switched off.
  • type: the type of layer. This can be fill, line, circle, symbol, or raster.
  • source: where the data comes from. For a GeoJSON file this is type: geojson and a url. The url should be a path to a GeoJSON file in the public folder, written without public — so public/data/my-file.geojson is /data/my-file.geojson — or a remote url as shown in the other sample layers.
  • paint: the style properties for the layer. This is where you can customize the appearance of the layer, such as the color, opacity, and width of the lines. See the Mapbox style specification for more information on the available style properties.
  • legend: an optional entry for this layer in the legend, with a label, a color and a shape of line, circle or square.

To add your own data, export it as GeoJSON from QGIS, drop the file into public/data, and add a layer pointing at it.

Note that the key words and indentation are important in YAML files. If you are unfamiliar with YAML, you can read more about it here. The first line of each map file is a comment that gives your text editor autocomplete and error underlines for these keys, so leave it in place; in VS Code, accept the recommended YAML extension when it offers.

Two of the sample layers show features we will not use in this exercise. The squirrel layer has a classify block, which colors features by one of their attributes, and an interactive block, which shows a popup when a feature is clicked.

Publishing your map

Once you are happy with your map, you can publish it to the web using Github Pages. This is a free service offered by Github that allows you to host static websites for free. You can publish your map by following these steps:

  1. Enable Github Pages for your repository. In the Github web interface, navigate to the “Settings” tab of your repository. From the left side menu select “Pages.” Select the option to enable Github Pages for your repository. Then from the Source drop down menu select “GitHub Actions”. You have now enabled Github Pages functionality for your repository and can proceed to configure and then publish you map.
activate github pages
  1. Check that site and base in astro.config.mjs are set to your username and your repository name, as described in Naming your site above. This is the most common reason a published site comes up blank or without its maps.
  2. Commit your changes to your repository. You can do this using the Github Desktop application by selecting the files you want to commit, entering a commit message, and clicking the “Commit” button. Then, click the “Push origin” button to push your changes to your online repository.
  3. In the Github web interface, navigate to the “Actions” tab of your repository. You should see a workflow listed in the left hand menu called Deploy to GitHub Pages — click on this workflow to see a list of individual actions that have been run through this workflow. You will see an action running that matches the commit message you just made (in this example, “update config”). This action will build your website and deploy it to Github Pages.
build steps
  1. If you’re curious, you can click on either the build or deploy nodes to see the steps that are being taken behind the scenes to compile your website and deploy it to Github Pages. This will give you a sense of the process that is happening when you run npm run *** commands (in this case, npm run build). Finally, the url you see in the deploy node is the url where your website will be published. You can click on this link to see your website live on the web.

As you make changes to your files in the coming days and weeks, you will replicate this process and continue to build on these template files. For the sake of the tutorial, we have added sample layers to demonstrate how you can add layers to your map.

Wrapping up

Please submit the following to Canvas:

  • Link to your github repository, containing the code for your web map.
  • A link to your published web map. If you used the plain HTML template this will be https://<your-username>.github.io/<your-repo>/full-page-map.html; if you used the Astro template it will be https://<your-username>.github.io/<your-repo>/full_page_map. In both cases <your-username> is your Github username and <your-repo> is the name you gave your repository.