orchestrions.html
October 18, 2025 ยท View on GitHub
Historic Orchestrions Around the World
A collection of rare and remarkable mechanical orchestras
<div id="loading" class="loading">Loading orchestrions...</div>
<div id="error" style="display: none;"></div>
<div id="orchestrions" class="locations-container"></div>
<footer>
<p>Data compiled from museum archives and historical records</p>
</footer>
</div>
<script>
async function loadOrchestrions() {
try {
const response = await fetch('https://gist.githubusercontent.com/simonw/2a0b26633802149a44e15cf1cd396f86/raw/836dde6b9b9452ac797d98b403872034f7536c9d/orchestrions.json');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
displayOrchestrions(data);
} catch (error) {
document.getElementById('loading').style.display = 'none';
const errorDiv = document.getElementById('error');
errorDiv.style.display = 'block';
errorDiv.className = 'error';
errorDiv.textContent = `Error loading data: ${error.message}`;
}
}
function displayOrchestrions(orchestrions) {
document.getElementById('loading').style.display = 'none';
// Group orchestrions by venue
const grouped = {};
orchestrions.forEach(orch => {
const key = `${orch.venue}|${orch.city}|${orch.country}|${orch.latitude}|${orch.longitude}`;
if (!grouped[key]) {
grouped[key] = {
venue: orch.venue,
city: orch.city,
country: orch.country,
latitude: orch.latitude,
longitude: orch.longitude,
orchestrions: []
};
}
grouped[key].orchestrions.push(orch);
});
const locations = Object.values(grouped);
// Display statistics
const countries = new Set(orchestrions.map(o => o.country));
const statsHtml = `
<div class="stat"><strong>${orchestrions.length}</strong> Orchestrions</div>
<div class="stat"><strong>${locations.length}</strong> Locations</div>
<div class="stat"><strong>${countries.size}</strong> Countries</div>
`;
document.getElementById('stats').innerHTML = statsHtml;
// Display locations and orchestrions
const container = document.getElementById('orchestrions');
container.innerHTML = locations.map(location => {
const googleMapsUrl = `https://www.google.com/maps?q=${location.latitude},${location.longitude}`;
const count = location.orchestrions.length;
return `
<div class="location-group">
<div class="location-header">
<div class="venue-name">
${escapeHtml(location.venue)}
${count > 1 ? `<span class="orchestrion-count">${count} orchestrions</span>` : ''}
</div>
<div class="location">
<span class="location-icon">๐</span>
<span>${escapeHtml(location.city)}, ${escapeHtml(location.country)}</span>
</div>
<a href="${googleMapsUrl}" target="_blank" rel="noopener" class="map-link">
View on Google Maps โ
</a>
</div>
<div class="orchestrions-list">
${location.orchestrions.map((orch, idx) => `
<div class="card">
${count > 1 ? `
<div class="card-header">
<div class="orchestrion-title">Orchestrion ${idx + 1}</div>
</div>
` : ''}
${orch.description ? `
<div class="section">
<div class="section-title">Description</div>
<div class="section-content">${formatText(orch.description)}</div>
</div>
` : ''}
${orch.history ? `
<div class="section">
<div class="section-title">History</div>
<div class="section-content">${formatText(orch.history)}</div>
</div>
` : ''}
${orch.notes ? `
<div class="section">
<div class="section-title">Notes</div>
<div class="section-content">${formatText(orch.notes)}</div>
</div>
` : ''}
</div>
`).join('')}
</div>
</div>
`;
}).join('');
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function formatText(text) {
// Convert markdown-style links [text](url) to HTML links
return escapeHtml(text).replace(
/\[([^\]]+)\]\(([^)]+)\)/g,
'<a href="\$2" target="_blank" rel="noopener">\$1</a>'
);
}
// Load data when page loads
loadOrchestrions();
</script>