1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>MuniMusic â San Francisco in Concert</title> 7 <meta name="description" content="A generative music experience powered by San Francisco's Muni transit system in real time."> 8 <meta property="og:title" content="MuniMusic â San Francisco in Concert"> 9 <meta property="og:description" content="Every Muni vehicle is an instrument. The city is the score."> 10 <meta property="og:image" content="https://munimusic.com/og-image.png"> 11 <meta property="og:url" content="https://munimusic.com"> 12 <meta property="og:type" content="website"> 13 <meta property="og:site_name" content="MuniMusic"> 14 <meta name="twitter:card" content="summary_large_image"> 15 <meta name="twitter:title" content="MuniMusic â San Francisco in Concert"> 16 <meta name="twitter:description" content="Every Muni vehicle is an instrument. The city is the score."> 17 <meta name="twitter:image" content="https://munimusic.com/og-image.png"> 18 <link rel="canonical" href="https://munimusic.com/"> 19 20 <!-- Fonts: Satoshi from Fontshare --> 21 <link href="https://api.fontshare.com/v2/css?f[]=satoshi@300,400,500,600,700&display=swap" rel="stylesheet"> 22 23 <!-- MapLibre GL JS --> 24 <link href="https://unpkg.com/[email protected]/dist/maplibre-gl.css" rel="stylesheet" /> 25
25<script src="https://unpkg.com/[email protected]/dist/maplibre-gl.js"></script>
25 26 27 <link rel="stylesheet" href="./base.css?v=6"> 28 <link rel="stylesheet" href="./style.css?v=9"> 29 30 <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><circle cx='16' cy='16' r='16' fill='%23d41144'/><text x='16' y='22' text-anchor='middle' font-family='sans-serif' font-size='18' font-weight='bold' fill='white'>M</text></svg>"> 31
31<script defer src="https://analytics.aerialpredator.com/script.js" data-website-id="b4e09cfc-b54e-4664-9e7d-8367ce8c2abe"></script>
31 32</head> 33<body> 34 <div id="app"> 35 <!-- ===== SPLASH SCREEN â Split layout ===== --> 36 <div class="splash" id="splash"> 37 <!-- Left panel: logo + gradient --> 38 <div class="splash-left"> 39 <div class="splash-gradient-bg"></div> 40 <div class="splash-logo-wrap"> 41 <div class="splash-logo" id="splash-logo"></div> 42 </div> 43 <!-- Animated transit lines decoration --> 44 <div class="splash-transit-lines" id="splash-transit-lines"> 45 <svg viewBox="0 0 400 600" preserveAspectRatio="none" aria-hidden="true"> 46 <path class="transit-line tl-1" d="M -20,100 Q 100,120 200,80 T 420,100" stroke="var(--line-j)" /> 47 <path class="transit-line tl-2" d="M -20,200 Q 80,180 180,220 T 420,190" stroke="var(--line-k)" /> 48 <path class="transit-line tl-3" d="M -20,300 Q 120,320 200,280 T 420,310" stroke="var(--line-n)" /> 49 <path class="transit-line tl-4" d="M -20,400 Q 100,380 220,420 T 420,390" stroke="var(--line-m)" /> 50 <path class="transit-line tl-5" d="M -20,500 Q 140,520 240,480 T 420,510" stroke="var(--line-t)" /> 51 </svg> 52 </div> 53 </div> 54 55 <!-- Right panel: text content --> 56 <div class="splash-right"> 57 <div class="splash-content"> 58 <div class="splash-eyebrow">MuniMusic</div> 59 <h1 class="splash-headline">San Francisco<br>in Concert</h1> 60 <div class="splash-divider"></div> 61 <p class="splash-body">Beneath the fog, a city moves. Every Muni vehicle â bus, metro, cable car, streetcar â becomes an instrument in a generative lo-fi composition.</p> 62 <p class="splash-body splash-body--emphasis">Every moment is unique. No two listens are ever the same.</p> 63 <div class="splash-actions"> 64 <button class="splash-enter" id="enter-btn"> 65 <span>Listen</span> 66 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg> 67 </button> 68 <span class="splash-vehicle-hint" id="splash-hint"> 69 <span class="splash-pulse"></span> 70 <span id="splash-count">â</span> vehicles moving 71 </span> 72 </div> 73 </div> 74 </div> 75 </div> 76 77 <!-- ===== MAIN EXPERIENCE â Sidebar + Canvas ===== --> 78 <div class="experience" id="experience" style="display:none;"> 79 80 <!-- Left sidebar --> 81 <aside class="sidebar" id="sidebar"> 82 <div class="sidebar-header"> 83 <div class="sidebar-logo" id="sidebar-logo"></div> 84 <button class="sidebar-theme-btn" id="btn-theme" aria-label="Toggle theme" data-theme-toggle> 85 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg> 86 </button> 87 </div> 88 89 <!-- Status --> 90 <div class="sidebar-status"> 91 <span class="status-dot"></span> 92 <span id="vehicle-count-main">0</span> vehicles 93 <span class="status-mode" id="data-mode">simulation</span> 94 </div> 95 <div class="sidebar-countdown" id="poll-countdown" style="display:none"> 96 <span class="countdown-icon">â»</span> 97 Movement starts in <span id="countdown-secs">60</span>s 98 </div> 99 100 <!-- Line legend --> 101 <div class="sidebar-section"> 102 <div class="sidebar-label">Routes</div> 103 <div class="line-legend" id="line-legend"></div> 104 </div> 105 106 <!-- Now playing â status indicators, light up when each voice is active --> 107 <div class="sidebar-section"> 108 <div class="sidebar-label">
108Now Playing</div> 109 <div class="now-playing" id="now-playing" title="Indicators light up when each sound is active. Enable sound to hear the music."> 110 <!-- Built dynamically by app.js updateNowPlaying() --> 111 </div> 112 </div> 113 114 <!-- Controls --> 115 <div class="sidebar-controls"> 116 117 <div class="sound-group"> 118 <button class="ctrl-btn" id="btn-sound" aria-label="Toggle sound"> 119 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/></svg> 120 </button> 121 <input type="range" class="volume-slider" id="volume-slider" min="0" max="100" value="30" aria-label="Volume"> 122 </div> 123 <button class="ctrl-btn" id="btn-info" aria-label="About"> 124 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg> 125 </button> 126 <button class="ctrl-btn" id="btn-share" aria-label="Share"> 127 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="M8.59 13.51l6.83 3.98M15.41 6.51l-6.82 3.98"/></svg> 128 </button> 129 </div> 130 131 <!-- Mobile route toggle --> 132 <button class="mobile-route-toggle" id="mobile-route-toggle" aria-label="Show routes"> 133 Routes <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="6 9 12 15 18 9"/></svg> 134 </button> 135 136 <!-- Footer credit --> 137 <div class="sidebar-credit"> 138 a <a href="https://www.dollop.com/technology" target="_blank" rel="noopener">dollop technology</a> production 139 </div> 140 </aside> 141 142 <!-- Main canvas area --> 143 <main class="canvas-area"> 144 <div class="map-container" id="map-view"> 145 <div id="maplibre-map"></div> 146 </div> 147 148 <!-- Note activity strip --> 149 <div class="activity-strip" id="activity-strip"></div> 150 </main> 151 </div> 152 153 <!-- Route tooltip --> 154 <div class="route-tooltip" id="route-tooltip"> 155 <span class="route-color"></span> 156 <span class="route-name"></span> 157 </div> 158 159 <!-- INFO OVERLAY --> 160 <div class="info-overlay" id="info-overlay"> 161 <div class="info-content"> 162 <h2 class="info-title">About MuniMusic</h2> 163 <p>MuniMusic transforms San Francisco's Muni transit system into a generative composition.</p> 164 <p>Every vehicle â metro train, cable car, historic streetcar, and bus â plays a unique pair of tones based on its position and route. The J-Church blends warm electric piano with singing bowls. The N-Judah pairs bass pizzicato with marimba. Cable cars ring tubular bells and bamboo chimes.</p> 165 <p>A stop chime sounds when a train arrives at a station, giving each stop its own distinct tone.</p> 166 <p>Each colored marker is a vehicle moving in real time. Click a route badge to solo it.</p> 167 <button class="info-close-btn" id="close-info">Got it</button> 168 </div> 169 </div> 170 </div> 171 172 <!-- Share toast --> 173 <div class="share-toast" id="share-toast">Link copied to clipboard</div> 174 175 <noscript> 176 <div style="display:flex;align-items:center;justify-content:center;height:100vh;background:#1a0a14;color:#F5EFDF;font-family:sans-serif;text-align:center;padding:2rem;"> 177 <div> 178 <h1 style="color:#d41144;font-size:2rem;margin-bottom:1rem;">MuniMusic</h1> 179 <p>This experience requires JavaScript to run. Please enable it and reload.</p> 180 </div> 181 </div> 182 </noscript> 183 184
184<script src="./app.js?v=45"></script>
184 185</body> 186</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.