diff --git a/map/README.md b/map/README.md
new file mode 100644
index 0000000..0edc7cd
--- /dev/null
+++ b/map/README.md
@@ -0,0 +1,26 @@
+# 404 Camp Not Found Map
+
+Interactive map for navigating the 404 Camp Not Found event. Find facilities, activities, camping spots, and amenities across the campgrounds.
+
+## Features
+
+- **Interactive facilities map** with OpenStreetMap tiles
+- **Location markers** for key areas (kitchen, workshops, camping, beach)
+- **Activity schedules** with meal times and events
+- **Facility information** including amenities and descriptions
+- **Marker clustering** for better map navigation
+
+## Stack
+
+- **Leaflet** - Interactive map library
+- **OpenStreetMap** - Map tiles and geographic data
+- **GeoJSON** - Location data format
+- **Marker Clustering** - Enhanced map navigation
+
+## Usage
+
+```sh
+python -m http.server 8000
+```
+
+Open your browser and navigate to `http://localhost:8000` to view the map.
\ No newline at end of file
diff --git a/map/index.html b/map/index.html
new file mode 100644
index 0000000..e310001
--- /dev/null
+++ b/map/index.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+ 404 Camp Not Found Map
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/map/locations.geojson b/map/locations.geojson
new file mode 100644
index 0000000..b46e67f
--- /dev/null
+++ b/map/locations.geojson
@@ -0,0 +1,269 @@
+{
+ "type": "FeatureCollection",
+ "features": [
+ {
+ "type": "Feature",
+ "id": "main-entrance",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.98482, 54.657344]
+ },
+ "properties": {
+ "name": "Main Entrance",
+ "icons": ["đĒ"],
+ "description": "Primary entry point with information desk and lost & found",
+ "activities": ["đĒ Entry Gate", "âšī¸ Information", "đĻ Lost & Found"]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "parking-main",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.984841, 54.661329]
+ },
+ "properties": {
+ "name": "Parking Area",
+ "icons": ["đ
ŋī¸"],
+ "description": "Central parking zone for camp visitors",
+ "activities": ["đ
ŋī¸ Car Parking", "đ Central Parking Zone"]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "base-camp",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.985192, 54.661103]
+ },
+ "properties": {
+ "name": "Base Camp",
+ "icons": ["đŊ", "âģī¸", "đ§", "đ"],
+ "description": "Central facility hub with essential amenities",
+ "activities": ["đŊ Toilets", "âģī¸ Recycling", "đ§ Hot Water", "đ Charging Station"]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "kitchen-area",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.9861, 54.6613]
+ },
+ "properties": {
+ "name": "Kitchen",
+ "icons": ["đŊī¸", "đŗ", "â", "đŋ"],
+ "description": "Main food service area with scheduled meal times",
+ "activities": [
+ "đŗ Breakfast 07:-09:30",
+ "â Coffee 07:-11:",
+ "đĨĒ Lunch 12:-14:30",
+ "đŋ Popcorn 15:-17:",
+ "đŊī¸ Dinner 18:-20:30"
+ ],
+
+ "marker-color": "#ea580c",
+ "marker-size": "large"
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "talks",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.9858, 54.6611]
+ },
+ "properties": {
+ "name": "Talks",
+ "icons": ["đĸ"],
+ "description": "Learning area for hands-on workshops and presentations",
+ "activities": ["đĸ Talks"]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "workshop-zone",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.9857, 54.6614]
+ },
+ "properties": {
+ "name": "Workshop",
+ "icons": ["đ¨"],
+ "description": "Learning area for hands-on workshops and presentations",
+ "activities": ["đ¨ Workshops"]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "campfire-circle",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.986815, 54.660984]
+ },
+ "properties": {
+ "name": "Campfire",
+ "icons": ["đĨ", "đē"],
+ "description": "Social area for evening fires and refreshments",
+ "activities": ["đĨ Evening Fires", "đē Beer Area 20:-23:"]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "lieptelis-grove",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.9869683, 54.6613]
+ },
+ "properties": {
+ "name": "Lieptelis Grove",
+ "icons": ["đŗ", "đ§"],
+ "description": "Peaceful area around the historic Lieptelis tree",
+ "activities": ["đŗ Historic Tree", "đ§ Quiet Space"]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "beach-main",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.98656, 54.6613]
+ },
+ "properties": {
+ "name": "Beach",
+ "icons": ["đī¸", "đ"],
+ "description": "Primary beach access point for swimming and water activities",
+ "activities": ["đ Swimming", "đī¸ Beach Access"]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "sunset-peninsula",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.983742, 54.661853]
+ },
+ "properties": {
+ "name": "Sunset Peninsula",
+ "icons": ["đ
", "đ¸"],
+ "description": "Scenic peninsula perfect for sunset photography",
+ "activities": ["đ
Sunset Views", "đ¸ Photo Spot"]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "camping-site-2",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.983811, 54.661425]
+ },
+ "properties": {
+ "name": "Camp 2",
+ "icons": ["âē", "đ"],
+ "description": "Designated camping area for overnight stays",
+ "activities": ["âē Camping Spot", "đ Night Area"]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "camping-site-3",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.983731, 54.661232]
+ },
+ "properties": {
+ "name": "Camp 3",
+ "icons": ["âē", "đī¸"],
+ "description": "Peaceful camping area away from main activities",
+ "activities": ["âē Camping Spot", "đī¸ Quiet Zone"]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "south-beach",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.987159, 54.660553]
+ },
+ "properties": {
+ "name": "South Beach",
+ "icons": ["đī¸", "đ"],
+ "description": "Secondary beach area for water activities",
+ "activities": ["đī¸ Beach Access", "đ Water Activities"],
+
+ "marker-color": "#0ea5e9",
+ "marker-size": "medium"
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "high-mountain",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.985989, 54.660596]
+ },
+ "properties": {
+ "name": "High Mountain",
+ "icons": ["â°ī¸", "đ¸"],
+ "description": "Elevated viewpoint offering panoramic views of the area",
+ "activities": ["â°ī¸ Viewpoint", "đ¸ Scenic Spot"]
+ }
+ },
+
+
+ {
+ "type": "Feature",
+ "id": "trash-bin-3",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.987, 54.6608]
+ },
+ "properties": {
+ "name": "Trash Bin",
+ "icons": ["đī¸"],
+ "activities": []
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "trash-bin-4",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.9842, 54.661]
+ },
+ "properties": {
+ "name": "Trash Bin",
+ "icons": ["đī¸"],
+ "activities": []
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "restroom",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.9856, 54.6612]
+ },
+ "properties": {
+ "name": "Restroom",
+ "icons": ["đģ"],
+ "description": "",
+ "activities": []
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "restroom",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [24.986, 54.6609]
+ },
+ "properties": {
+ "name": "Restroom",
+ "icons": ["đģ"],
+ "description": "",
+ "activities": []
+ }
+ }
+ ]
+}
diff --git a/map/script.js b/map/script.js
new file mode 100644
index 0000000..f421836
--- /dev/null
+++ b/map/script.js
@@ -0,0 +1,108 @@
+const MAP_CONFIG = {
+ center: [54.661103, 24.986192],
+ zoom: 18,
+ maxZoom: 18,
+ minZoom: 16,
+};
+
+const ICON_CONFIG = {
+ iconOnly: {
+ size: [25, 25],
+ anchor: [12, 12],
+ fontSize: 16,
+ },
+};
+
+const map = L.map("map", MAP_CONFIG);
+
+const createIcon = (properties) => {
+ const { name, icons } = properties;
+
+ // For trashbins, display icon only
+ if ((name && name.toLowerCase().includes("trash")) || name.toLowerCase().includes("restroom")) {
+ const iconString = icons && icons.length > 0 ? icons[0] : "đī¸";
+ return L.divIcon({
+ html: `${iconString}
`,
+ iconSize: ICON_CONFIG.iconOnly.size,
+ iconAnchor: ICON_CONFIG.iconOnly.anchor,
+ className: "icon-only-marker",
+ });
+ }
+
+ // Shorten long names (Base Camp fits, but longer names get truncated)
+ const iconString = icons && icons.length > 0 ? icons.join("") : "";
+ const displayText = iconString ? `${name}\n${iconString}` : name;
+
+ return L.divIcon({
+ className: "custom-div-icon",
+ html: `${displayText}
`,
+ iconSize: [null, null],
+ iconAnchor: [0, 0],
+ });
+};
+
+const createPopupContent = (properties) => {
+ if (!properties?.name) {
+ return null;
+ }
+
+ const { name, icons, activities } = properties;
+ let content = `${name} `;
+
+ // Add icons section if available
+ if (icons && icons.length > 0) {
+ const iconsHtml = icons.map((icon) => ``).join("");
+ content += ``;
+ }
+
+ // Add activities if available
+ if (activities && activities.length > 0) {
+ const activitiesHtml = activities.map((activity) => `${activity} `).join("");
+ content += ``;
+ }
+
+ return content;
+};
+
+const onEachFeature = (feature, layer) => {
+ const popupContent = createPopupContent(feature.properties);
+ if (popupContent) {
+ layer.bindPopup(popupContent);
+ }
+};
+
+const pointToLayer = (feature, latlng) => {
+ const icon = createIcon(feature.properties);
+ return L.marker(latlng, { icon });
+};
+
+document.addEventListener("DOMContentLoaded", () => {
+ L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
+ attribution: 'Š OpenStreetMap contributors',
+ }).addTo(map);
+
+ const markers = L.markerClusterGroup({
+ maxClusterRadius: 50,
+ disableClusteringAtZoom: 18,
+ });
+
+ fetch("locations.geojson")
+ .then((response) => response.json())
+ .then((data) => {
+ const geoJsonLayer = L.geoJSON(data, {
+ onEachFeature: onEachFeature,
+ pointToLayer: pointToLayer,
+ });
+
+ markers.addLayer(geoJsonLayer);
+ map.addLayer(markers);
+ })
+ .catch((error) => {
+ console.error("Error loading location data:", error);
+ alert(
+ "Could not load location data. Please serve this page from a web server (e.g., python3 -m http.server 8000)"
+ );
+ });
+
+ L.control.scale().addTo(map);
+});
diff --git a/map/styles.css b/map/styles.css
new file mode 100644
index 0000000..8cfc766
--- /dev/null
+++ b/map/styles.css
@@ -0,0 +1,46 @@
+body {
+ margin: 0;
+ padding: 0;
+}
+
+#map {
+ width: 100%;
+ height: 100vh;
+}
+
+/* Custom marker styles */
+.custom-marker {
+ background: rgba(255, 255, 255, 0.95);
+ border: 2px solid #2e86ab;
+ border-radius: 15px;
+ padding: 2px 4px;
+ font-size: 1em;
+ color: #2e86ab;
+ text-align: center;
+ white-space: pre-line;
+ min-width: max-content;
+}
+
+/* Popup styles */
+.popup-icons {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin: 10px 0;
+ justify-content: flex-start;
+}
+
+.popup-icon {
+ font-size: 24px;
+ display: inline-block;
+ padding: 4px;
+ background: rgba(46, 134, 171, 0.1);
+ border-radius: 8px;
+ border: 1px solid rgba(46, 134, 171, 0.2);
+}
+
+.popup-activities {
+ margin-top: 10px;
+ font-size: 14px;
+ line-height: 1.4;
+}
\ No newline at end of file