Skip to content

Instantly share code, notes, and snippets.

@JohnLBevan
Last active June 28, 2026 16:57
Show Gist options
  • Select an option

  • Save JohnLBevan/8607af4d89b085ee1281b3b6a0e52dbe to your computer and use it in GitHub Desktop.

Select an option

Save JohnLBevan/8607af4d89b085ee1281b3b6a0e52dbe to your computer and use it in GitHub Desktop.
Tom Scott Leylines modernised by Gemini
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Modern Ley Line Locator</title>
<!-- Leaflet CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<style>
body { margin: 0; padding: 0; font-family: sans-serif; }
#map { height: 100vh; width: 100vw; }
#ui {
position: absolute;
top: 10px; left: 50px;
z-index: 1000;
background: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
max-width: 300px;
}
button { padding: 8px 12px; cursor: pointer; margin-top: 10px; width: 100%;}
#status { margin-top: 10px; font-size: 0.9em; color: #555; }
</style>
</head>
<body>
<div id="ui">
<h3>Ley Line Locator</h3>
<p>Click anywhere on the map to set your "house", then click the button below to find ancient sites and intersecting ley lines.</p>
<button id="findLinesBtn" disabled>Find Ley Lines</button>
<div id="status">Waiting for location...</div>
</div>
<div id="map"></div>
<!-- Leaflet JS -->
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
const map = L.map('map').setView([51.505, -0.09], 11); // Default to London
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
let userMarker = null;
let siteMarkers = L.layerGroup().addTo(map);
let leyLines = L.layerGroup().addTo(map);
// Handle map clicks to set the target location
map.on('click', function(e) {
if (!userMarker) {
userMarker = L.marker(e.latlng, { icon: L.icon({
iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png',
iconSize: [25, 41], iconAnchor: [12, 41]
})}).addTo(map);
} else {
userMarker.setLatLng(e.latlng);
}
document.getElementById('findLinesBtn').disabled = false;
document.getElementById('status').innerText = "Location set. Ready to search.";
});
document.getElementById('findLinesBtn').addEventListener('click', async () => {
if (!userMarker) return;
const lat = userMarker.getLatLng().lat;
const lng = userMarker.getLatLng().lng;
document.getElementById('status').innerText = "Querying OpenStreetMap for ancient sites...";
siteMarkers.clearLayers();
leyLines.clearLayers();
// Overpass API query: Find historic monuments, archaeological sites, or ruins within 10km
const query = `
[out:json];
(
node["historic"="monument"](around:10000, ${lat}, ${lng});
node["historic"="archaeological_site"](around:10000, ${lat}, ${lng});
node["historic"="ruins"](around:10000, ${lat}, ${lng});
);
out body;
`;
try {
const response = await fetch('https://overpass-api.de/api/interpreter', {
method: 'POST',
body: query
});
const data = await response.json();
const sites = data.elements;
document.getElementById('status').innerText = `Found ${sites.length} sites. Calculating lines...`;
// Plot the sites
sites.forEach(site => {
L.circleMarker([site.lat, site.lon], { radius: 4, color: 'blue' })
.bindPopup(site.tags.name || "Unnamed ancient site")
.addTo(siteMarkers);
});
// Find lines that cross near the user's marker
let lineCount = 0;
const threshold = 0.001; // Roughly 100 meters in decimal degrees
for (let i = 0; i < sites.length; i++) {
for (let j = i + 1; j < sites.length; j++) {
const dist = distanceToLine(
lat, lng,
sites[i].lat, sites[i].lon,
sites[j].lat, sites[j].lon
);
if (dist < threshold) {
L.polyline([
[sites[i].lat, sites[i].lon],
[sites[j].lat, sites[j].lon]
], { color: 'purple', weight: 2, opacity: 0.5 }).addTo(leyLines);
lineCount++;
}
}
}
document.getElementById('status').innerText = `Drew ${lineCount} ley lines intersecting your location!`;
} catch (error) {
document.getElementById('status').innerText = "Error fetching data.";
console.error(error);
}
});
// Calculate perpendicular distance from point (x0, y0) to line passing through (x1, y1) and (x2, y2)
function distanceToLine(x0, y0, x1, y1, x2, y2) {
const numerator = Math.abs((x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1));
const denominator = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
return denominator === 0 ? 0 : numerator / denominator;
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Static Ley Line Locator</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<style>
body { margin: 0; padding: 0; font-family: sans-serif; }
#map { height: 100vh; width: 100vw; }
#ui {
position: absolute;
top: 10px; left: 50px;
z-index: 1000;
background: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
max-width: 320px;
}
button { padding: 10px; cursor: pointer; margin-top: 10px; width: 100%; font-weight: bold; }
#status { margin-top: 10px; font-size: 0.9em; color: #333; }
</style>
</head>
<body>
<div id="ui">
<h3>Static Ley Line Locator</h3>
<p>Click the map to place your target, then calculate the mystical alignments!</p>
<button id="findLinesBtn" disabled>Calculate Ley Lines</button>
<div id="status">Waiting for location...</div>
</div>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
// Center on the UK
const map = L.map('map').setView([52.5, -1.5], 7);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
let userMarker = null;
let siteMarkers = L.layerGroup().addTo(map);
let leyLines = L.layerGroup().addTo(map);
// 1. A static list of famous UK sites
const staticSites = [
{ name: "Stonehenge", lat: 51.1788, lng: -1.8262 },
{ name: "Avebury Stone Circle", lat: 51.4286, lng: -1.8542 },
{ name: "Glastonbury Tor", lat: 51.1449, lng: -2.6985 },
{ name: "Castlerigg Stone Circle", lat: 54.6028, lng: -3.0984 },
{ name: "Bryn Celli Ddu", lat: 53.2075, lng: -4.2355 },
{ name: "Callanish Stones", lat: 58.1979, lng: -6.7452 },
{ name: "Maeshowe", lat: 58.9967, lng: -3.1882 }
];
// 2. Simulate a massive database to make the math joke work
// (Generates 500 "Minor Barrows/Stones" across the UK bounding box)
for (let i = 0; i < 500; i++) {
staticSites.push({
name: `Unrecorded Earthwork #${i+1}`,
// UK approximate bounding box coordinates
lat: 50 + Math.random() * 9,
lng: -7 + Math.random() * 9
});
}
// Plot all sites on load
staticSites.forEach(site => {
L.circleMarker([site.lat, site.lng], { radius: 3, color: 'blue', opacity: 0.5 })
.bindPopup(site.name)
.addTo(siteMarkers);
});
// Handle map clicks
map.on('click', function(e) {
if (!userMarker) {
userMarker = L.marker(e.latlng, { icon: L.icon({
iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png',
iconSize: [25, 41], iconAnchor: [12, 41]
})}).addTo(map);
} else {
userMarker.setLatLng(e.latlng);
}
document.getElementById('findLinesBtn').disabled = false;
document.getElementById('status').innerText = "Location set. Ready to calculate.";
});
// Calculate lines on button click
document.getElementById('findLinesBtn').addEventListener('click', () => {
if (!userMarker) return;
const targetLat = userMarker.getLatLng().lat;
const targetLng = userMarker.getLatLng().lng;
document.getElementById('status').innerText = `Calculating lines between ${staticSites.length} sites...`;
leyLines.clearLayers();
setTimeout(() => {
let lineCount = 0;
// Threshold is roughly 2km in decimal degrees to account for the mock data spread
const threshold = 0.02;
// Combinatorics: check every site against every other site
for (let i = 0; i < staticSites.length; i++) {
for (let j = i + 1; j < staticSites.length; j++) {
const dist = distanceToLine(
targetLat, targetLng,
staticSites[i].lat, staticSites[i].lng,
staticSites[j].lat, staticSites[j].lng
);
if (dist < threshold) {
L.polyline([
[staticSites[i].lat, staticSites[i].lng],
[staticSites[j].lat, staticSites[j].lng]
], { color: 'purple', weight: 1, opacity: 0.3 }).addTo(leyLines);
lineCount++;
}
}
}
document.getElementById('status').innerText = `Mathematical inevitability complete! Drew ${lineCount} ley lines intersecting your location.`;
}, 50); // Small timeout to allow UI to update before heavy math blocks the main thread
});
// Mathematical perpendicular distance formula
function distanceToLine(x0, y0, x1, y1, x2, y2) {
const numerator = Math.abs((x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1));
const denominator = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
return denominator === 0 ? 0 : numerator / denominator;
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment