{"id":13659872,"url":"https://github.com/hreikin/interactive-campaign-map","last_synced_at":"2025-04-10T02:04:18.109Z","repository":{"id":82389588,"uuid":"135803195","full_name":"hreikin/interactive-campaign-map","owner":"hreikin","description":"Interactive campaign map for use in tabletop wargaming, RPG's, etc.","archived":false,"fork":false,"pushed_at":"2021-10-20T19:10:14.000Z","size":15274,"stargazers_count":21,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-24T03:43:38.247Z","etag":null,"topics":["campaign-maps","interactive-maps","leaflet-map","rpg-maps","tabletop-gaming","tabletop-maps"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hreikin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-06-02T09:06:14.000Z","updated_at":"2024-08-28T22:47:15.000Z","dependencies_parsed_at":"2023-06-15T11:30:14.134Z","dependency_job_id":null,"html_url":"https://github.com/hreikin/interactive-campaign-map","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hreikin%2Finteractive-campaign-map","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hreikin%2Finteractive-campaign-map/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hreikin%2Finteractive-campaign-map/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hreikin%2Finteractive-campaign-map/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hreikin","download_url":"https://codeload.github.com/hreikin/interactive-campaign-map/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248142945,"owners_count":21054671,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["campaign-maps","interactive-maps","leaflet-map","rpg-maps","tabletop-gaming","tabletop-maps"],"created_at":"2024-08-02T05:01:13.165Z","updated_at":"2025-04-10T02:04:18.072Z","avatar_url":"https://github.com/hreikin.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Interactive Campaign Map\nThe Interactive Campaign Map is designed to let campaign arbitrators and GM's create an interactive map for use in their tabletop or roleplaying games.\n\nOnce you have cloned this repository, to run the demo map simply open the file named 'interactive-campaign-map.html' in a web browser. You should be greeted by the default map which shows the starting points of the demo campaigns players. The map works just like a normal map you would find on the likes of google with zooming and panning responding to input from a touch screen device or mouse like normal. \n\nYou can click on the player icons to bring up popups and a layers filter is available in the top right corner. All marker icons can be customised to represent whatever you need but in this simple demo we only have 2, one for the players and one for battles. If you open up the layers control in the top right corner you can choose which map to show and there is also a filter for you to choose which markers you want to display on the map. These markers can all be clicked and include a popup which can be used to include whatever information you see fit.\n\nThe interactive campaign map repository contains a few files and folders which i will outline below.\n\n- **docs :** Contains documentation on using the Interactive Campaign Map.\n- **images :** Contains files used for custom markers, player icons, etc.\n- **interactive-campaign-map-stage-01 :** Contains map tiles for stage 01 of the demo campaign.\n- **interactive-campaign-map-stage-02 :** Contains map tiles for stage 02 of the demo campaign.\n- **interactive-campaign-map-start :** Contains map tiles for the beginning of the demo campaign.\n- **js :** Contains the Javascript files required for the Interactive Campaign Map and L.tileLayer.zoomify.\n- **L.tileLayer.zoomify-LICENSE.md :** The license for the L.tileLayer.zoomify.js file.\n- **LICENSE.md :** The license for the Interactive Campaign Map.\n- **README.md :** The README file of the repository which includes basic information to guide you through the process of creating an interactive campaign map.\n- **interactive-campaign-map.html :** HTML file used to display the interactive campaign map demo.\n\n## Requirements\n- [Leaflet](https://leafletjs.com/) 1.3.1 (Or later).\n- L.tileLayer.zoomify (Included). Originally taken from the [Leaflet.Zoomify](http://github.com/cmulders/Leaflet.Zoomify/) repository.\n- Zoomify tile source. Zoomify Free is available from [here](http://www.zoomify.com/free.htm).\n\n## Demo\nA fullscreen demo is available to view [here](https://hreikin.co.uk/interactive-campaign-map/interactive-campaign-map.html).\n\n## Basic Usage\nA detailed guide is available to view [here](https://www.hreikin.co.uk/2018/06/07/user-guide-how-to-create-an-interactive-campaign-map-with-leafletjs/). Full documentation is available in the ```docs``` folder of this repository.\n\nCreate the map and set a flat projection, as we are projecting an image. Then create the Zoomify tile layer.\n```js\n//Creates the map, tells it to display in the element with id of 'mapid' and sets a flat projection, as we are projecting an image. \nvar map = L.map('mapid', { \n    crs: L.CRS.Simple, //Set a flat CRS (Coordinate Reference System) projection as we are projecting an image.\n});\n\n//Change the URL to reflect where you are hosting your map tiles. Width and Height of original image MUST be defined.\nvar layer = L.tileLayer.zoomify('./interactive-campaign-map-start/{g}/{z}-{x}-{y}.jpg', {\n    width: 8318,    // MUST be defined.\n    height: 3640,   // MUST be defined.\n}).addTo(map);\n\n//Setting the view to our layer bounds, set by our Zoomify plugin.\nmap.fitBounds(layer.getBounds());\n```\n\nDeclare which icons to use for the Player and Battle markers.\n```js\n// Create the icon used for the player markers. May be changed to any image you wish.\nvar playerIcon = L.icon({\n    iconUrl: 'images/players.png',  // Location of file to be used as icon.\n    iconSize: [38, 38],             // Size of icon on map.\n});\n\n// Create the icon used for the battle markers. May be changed to any image you wish.\nvar battleIcon = L.icon({\n    iconUrl: 'images/battles.png',  // Location of file to be used as icon.\n    iconSize: [50, 50],             // Size of icon on map.\n});\n```\n\nDeclare the popup content for any Player or Battle popups.\n```js\n// Create the player popup content. You can change these to include player bios, army lists, etc for each individual player. Accepts HTML content such as images and links.\nvar redPlayerPopup = 'Player information can go here, it could include details such as army/gang/faction and a link to their list or roster. The icon can be set to any image, it could be either a profile picture of the player or a recognisable army/gang/faction mark.';\nvar turquoisePlayerPopup = 'Player information can go here, it could include details such as army/gang/faction and a link to their list or roster. The icon can be set to any image, it could be either a profile picture of the player or a recognisable army/gang/faction mark.';\nvar lightgreenPlayerPopup = 'Player information can go here, it could include details such as army/gang/faction and a link to their list or roster. The icon can be set to any image, it could be either a profile picture of the player or a recognisable army/gang/faction mark.';\nvar yellowPlayerPopup = 'Player information can go here, it could include details such as army/gang/faction and a link to their list or roster. The icon can be set to any image, it could be either a profile picture of the player or a recognisable army/gang/faction mark.';\nvar bluePlayerPopup = 'Player information can go here, it could include details such as army/gang/faction and a link to their list or roster. The icon can be set to any image, it could be either a profile picture of the player or a recognisable army/gang/faction mark.';\nvar orangePlayerPopup = 'Player information can go here, it could include details such as army/gang/faction and a link to their list or roster. The icon can be set to any image, it could be either a profile picture of the player or a recognisable army/gang/faction mark.';\nvar purplePlayerPopup = 'Player information can go here, it could include details such as army/gang/faction and a link to their list or roster. The icon can be set to any image, it could be either a profile picture of the player or a recognisable army/gang/faction mark.';\nvar greenPlayerPopup = 'Player information can go here, it could include details such as army/gang/faction and a link to their list or roster. The icon can be set to any image, it could be either a profile picture of the player or a recognisable army/gang/faction mark.';\nvar darkBluePlayerPopup = 'Player information can go here, it could include details such as army/gang/faction and a link to their list or roster. The icon can be set to any image, it could be either a profile picture of the player or a recognisable army/gang/faction mark.';\nvar lightBluePlayerPopup = 'Player information can go here, it could include details such as army/gang/faction and a link to their list or roster. The icon can be set to any image, it could be either a profile picture of the player or a recognisable army/gang/faction mark.';\n\n// Stage 01 battles popup content. You can change these to include results, etc for each battle that occurred this stage. Accepts HTML content such as images and links.\nvar redPlayerStage01Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar redPlayerStage01Battle02Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar lightGreenPlayerStage01Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar yellowPlayerStage01Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar yellowPlayerStage01Battle02Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar bluePlayerStage01Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar orangePlayerStage01Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar purplePlayerStage01Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar purplePlayerStage01Battle02Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar greenPlayerStage01Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar darkBluePlayerStage01Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar lightBluePlayerStage01Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar turquoisePlayerStage01Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar turquoisePlayerStage01Battle02Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\n\n// Stage 02 battles popup content. You can change these to include results, etc for each battle that occurred this stage. Accepts HTML content such as images and links.\nvar redPlayerStage02Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar lightGreenPlayerStage02Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar yellowPlayerStage02Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar bluePlayerStage02Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar orangePlayerStage02Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar purplePlayerStage02Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar greenPlayerStage02Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar darkBluePlayerStage02Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar lightBluePlayerStage02Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar lightBluePlayerStage02Battle02Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\nvar turquoisePlayerStage02Battle01Popup = 'Battle information and results can go here with a link to any results/league tables. The icon can be set to any image.';\n```\n\nCreate the Player markers and set the latitude and longitude values and then pass any options for custom icon and custom popup values. Then create a group of Player markers to be added to the layer control and add the player markers group to the map.\n```js\n// Creates the player markers, sets the latitude and longitude. Passes options for custom icon and custom popup values.\nvar redPlayer = L.marker([-10.0, 10.0], {icon: playerIcon}).bindPopup(redPlayerPopup);\nvar lightGreenPlayer = L.marker([-21.0, 33.0], {icon: playerIcon}).bindPopup(lightgreenPlayerPopup);\nvar yellowPlayer = L.marker([-25.0, 61.0], {icon: playerIcon}).bindPopup(yellowPlayerPopup);\nvar bluePlayer = L.marker([-16.0, 85.0], {icon: playerIcon}).bindPopup(bluePlayerPopup);\nvar orangePlayer = L.marker([-14.0, 116.0], {icon: playerIcon}).bindPopup(orangePlayerPopup);\nvar purplePlayer = L.marker([-32.0, 122.0], {icon: playerIcon}).bindPopup(purplePlayerPopup);\nvar greenPlayer = L.marker([-43.0, 97.0], {icon: playerIcon}).bindPopup(greenPlayerPopup);\nvar darkBluePlayer = L.marker([-44.0, 73.0], {icon: playerIcon}).bindPopup(darkBluePlayerPopup);\nvar lightBluePlayer = L.marker([-48.0, 49.0], {icon: playerIcon}).bindPopup(lightBluePlayerPopup);\nvar turquoisePlayer = L.marker([-45.0, 16.0], {icon: playerIcon}).bindPopup(turquoisePlayerPopup);\n\n// Creates a group of player markers to be added to layer control later. Adds player markers to map.\nvar players = L.layerGroup([redPlayer, lightGreenPlayer, yellowPlayer, bluePlayer, orangePlayer, purplePlayer, greenPlayer, darkBluePlayer, lightBluePlayer, turquoisePlayer]).addTo(map);\n```\n\nCreate the Battle markers for each stage and set the latitude and longitude values and then pass any options for custom icon and custom popup values. Then create a group of Battle markers for each stage to be added to the layer control.\n```js\n// Creates the stage 01 battle markers, sets the latitude and longitude. Passes options for custom icon and custom popup values.\nvar redPlayerStage01Battle01 = L.marker([-3.5, 5.0], {icon: battleIcon}).bindPopup(redPlayerStage01Battle01Popup);\nvar redPlayerStage01Battle02 = L.marker([-4.0, 15.0], {icon: battleIcon}).bindPopup(redPlayerStage01Battle02Popup);\nvar lightGreenPlayerStage01Battle01 = L.marker([-13.0, 30.0], {icon: battleIcon}).bindPopup(lightGreenPlayerStage01Battle01Popup);\nvar yellowPlayerStage01Battle01 = L.marker([-13.0, 65.0], {icon: battleIcon}).bindPopup(yellowPlayerStage01Battle01Popup);\nvar yellowPlayerStage01Battle02 = L.marker([-25.0, 68.0], {icon: battleIcon}).bindPopup(yellowPlayerStage01Battle02Popup);\nvar bluePlayerStage01Battle01 = L.marker([-17.0, 95.0], {icon: battleIcon}).bindPopup(bluePlayerStage01Battle01Popup);\nvar orangePlayerStage01Battle01 = L.marker([-4.0, 111.0], {icon: battleIcon}).bindPopup(orangePlayerStage01Battle01Popup);\nvar purplePlayerStage01Battle01 = L.marker([-23.0, 127.0], {icon: battleIcon}).bindPopup(purplePlayerStage01Battle01Popup);\nvar purplePlayerStage01Battle02 = L.marker([-14.0, 125.0], {icon: battleIcon}).bindPopup(purplePlayerStage01Battle02Popup);\nvar greenPlayerStage01Battle01 = L.marker([-42.0, 108.0], {icon: battleIcon}).bindPopup(greenPlayerStage01Battle01Popup);\nvar darkBluePlayerStage01Battle01 = L.marker([-37.0, 74.0], {icon: battleIcon}).bindPopup(darkBluePlayerStage01Battle01Popup);\nvar lightBluePlayerStage01Battle01 = L.marker([-54.0, 50.0], {icon: battleIcon}).bindPopup(lightBluePlayerStage01Battle01Popup);\nvar turquoisePlayerStage01Battle01 = L.marker([-43.0, 27.0], {icon: battleIcon}).bindPopup(turquoisePlayerStage01Battle01Popup);\nvar turquoisePlayerStage01Battle02 = L.marker([-44.0, 37.0], {icon: battleIcon}).bindPopup(turquoisePlayerStage01Battle02Popup);\n\n// Creates a group of stage 01 battle markers to be added to layer control later.\nvar battlesStage01 = L.layerGroup([redPlayerStage01Battle01, redPlayerStage01Battle02, lightGreenPlayerStage01Battle01, yellowPlayerStage01Battle01, yellowPlayerStage01Battle02, bluePlayerStage01Battle01, orangePlayerStage01Battle01, purplePlayerStage01Battle01, purplePlayerStage01Battle02, greenPlayerStage01Battle01, darkBluePlayerStage01Battle01, lightBluePlayerStage01Battle01, turquoisePlayerStage01Battle01, turquoisePlayerStage01Battle02]);\n\n// Creates the stage 02 battle markers, sets the latitude and longitude. Passes options for custom icon and custom popup values.\nvar redPlayerStage02Battle01 = L.marker([-4.0, 28.0], {icon: battleIcon}).bindPopup(redPlayerStage02Battle01Popup);\nvar lightGreenPlayerStage02Battle01 = L.marker([-30.0, 36.0], {icon: battleIcon}).bindPopup(lightGreenPlayerStage02Battle01Popup);\nvar yellowPlayerStage02Battle01 = L.marker([-14.0, 58.0], {icon: battleIcon}).bindPopup(yellowPlayerStage02Battle01Popup);\nvar bluePlayerStage02Battle01 = L.marker([-23.0, 87.0], {icon: battleIcon}).bindPopup(bluePlayerStage02Battle01Popup);\nvar orangePlayerStage02Battle01 = L.marker([-4.0, 119.0], {icon: battleIcon}).bindPopup(orangePlayerStage02Battle01Popup);\nvar purplePlayerStage02Battle01 = L.marker([-42.0, 122.0], {icon: battleIcon}).bindPopup(purplePlayerStage02Battle01Popup);\nvar greenPlayerStage02Battle01 = L.marker([-30.0, 107.0], {icon: battleIcon}).bindPopup(greenPlayerStage02Battle01Popup);\nvar darkBluePlayerStage02Battle01 = L.marker([-37.0, 66.0], {icon: battleIcon}).bindPopup(darkBluePlayerStage02Battle01Popup);\nvar lightBluePlayerStage02Battle01 = L.marker([-53.0, 63.0], {icon: battleIcon}).bindPopup(lightBluePlayerStage02Battle01Popup);\nvar lightBluePlayerStage02Battle02 = L.marker([-40.0, 37.0], {icon: battleIcon}).bindPopup(lightBluePlayerStage02Battle02Popup);\nvar turquoisePlayerStage02Battle01 = L.marker([-41.0, 48.0], {icon: battleIcon}).bindPopup(turquoisePlayerStage02Battle01Popup);\n\n// Creates a group of stage 02 battle markers to be added to layer control later.\nvar battlesStage02 = L.layerGroup([redPlayerStage02Battle01, lightGreenPlayerStage02Battle01, yellowPlayerStage02Battle01, bluePlayerStage02Battle01, orangePlayerStage02Battle01, purplePlayerStage02Battle01, greenPlayerStage02Battle01, darkBluePlayerStage02Battle01, lightBluePlayerStage02Battle01, lightBluePlayerStage02Battle02, turquoisePlayerStage02Battle01]);\n```\n\nCreate the switchable map layers and add them to the map. Width and Height of original image MUST be defined.\n```js\n//Creates the switchable map layers. Change the URL to reflect where you are hosting your map tiles. Width and Height of original image MUST be defined.\nvar start = L.tileLayer.zoomify('./interactive-campaign-map-start/{g}/{z}-{x}-{y}.jpg', {\n    width: 8318,                                                                                        // MUST be defined.\n    height: 3640,                                                                                       // MUST be defined.\n    tolerance: 0.9, \n    layers: [stage01, stage02, players, battlesStage01, battlesStage02],                                //Layers to include in layers control, initial map should NOT be included as it will be added automatically.\n    attribution: 'Map by \u003ca href=\"https://hreikin.co.uk\" target=\"_blank\" alt=\"hreikin\"\u003e@hreikin\u003c/a\u003e'    // Attribution which appears in the bottom left corner, change this value to whatever you like.\n    }).addTo(map),\n\n    stage01 = L.tileLayer.zoomify('./interactive-campaign-map-stage-01/{g}/{z}-{x}-{y}.jpg', {\n    width: 8318,                                                                                        // MUST be defined.\n    height: 3640,                                                                                       // MUST be defined.\n    tolerance: 0.9, \n    layers: [stage01, stage02, players, battlesStage01, battlesStage02],                                //Layers to include in layers control, initial map should NOT be included as it will be added automatically.\n    attribution: 'Map by \u003ca href=\"https://hreikin.co.uk\" target=\"_blank\" alt=\"hreikin\"\u003e@hreikin\u003c/a\u003e'    // Attribution which appears in the bottom left corner, change this value to whatever you like.\n    }),\n\n    stage02 = L.tileLayer.zoomify('./interactive-campaign-map-stage-02/{g}/{z}-{x}-{y}.jpg', {\n    width: 8318,                                                                                        // MUST be defined.\n    height: 3640,                                                                                       // MUST be defined.\n    tolerance: 0.9, \n    layers: [stage01, stage02, players, battlesStage01, battlesStage02],                                //Layers to include in layers control, initial map should NOT be included as it will be added automatically.\n    attribution: 'Map by \u003ca href=\"https://hreikin.co.uk\" target=\"_blank\" alt=\"hreikin\"\u003e@hreikin\u003c/a\u003e'    // Attribution which appears in the bottom left corner, change this value to whatever you like.\n    });\n```\n\nCreate the baseMaps and overlayMaps layers and passes which map layers to include in the layers control. Then create the layers control and add it to the map.\n```js\n// Creates baseMaps layer and passes which maps to include in the layers control.\nvar baseMaps = {\n    \"Campaign Start\": start,        // The value within quotation marks is the name of the switchable control as it appears on the map. The second value is the layer name.\n    \"Campaign Stage 01\": stage01,   // The value within quotation marks is the name of the switchable control as it appears on the map. The second value is the layer name.\n    \"Campaign Stage 02\": stage02    // The value within quotation marks is the name of the switchable control as it appears on the map. The second value is the layer name.\n};\n\n// Creates overlayMaps layer and passes which marker groups to include in the layers control.\nvar overlayMaps = {\n    \"Players\": players,                 // The value within quotation marks is the name of the switchable control as it appears on the map. The second value is the group name.\n    \"Stage 1 Battles\": battlesStage01,  // The value within quotation marks is the name of the switchable control as it appears on the map. The second value is the group name.\n    \"Stage 2 Battles\": battlesStage02   // The value within quotation marks is the name of the switchable control as it appears on the map. The second value is the group name.\n    };\n\n// Creates a switchable layers control from baseMaps and overlayMaps and adds them to map.\nL.control.layers(baseMaps, overlayMaps).addTo(map);\n```\n\n## License\nThis software is released under the [MIT licence](http://www.opensource.org/licenses/mit-license.php).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhreikin%2Finteractive-campaign-map","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhreikin%2Finteractive-campaign-map","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhreikin%2Finteractive-campaign-map/lists"}