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 <meta name="referrer" content="strict-origin-when-cross-origin"> 7 <meta name="robots" content="index, follow"> 8 9 <!-- Security Headers --> 10 <meta http-equiv="X-Content-Type-Options" content="nosniff"> 11 <meta http-equiv="X-Frame-Options" content="DENY"> 12 <meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin"> 13 <meta http-equiv="Permissions-Policy" content="camera=(), microphone=(), geolocation=()"> 14 15 <title>DÎVID OREILLY â Official Archive</title> 16 <meta name="description" content="Explore a curated selection of animations, games, and interactive works from David OReilly."> 17 <meta name="author" content="David OReilly"> 18 <meta name="keywords" content="David OReilly, animation, games, Everything, Mountain, Please Say Something, digital art, interactive art, archive"> 19 20 <!-- Open Graph / Facebook --> 21 <meta property="og:type" content="website"> 22 <meta property="og:url" content="https://www.davidoreilly.com/"> 23 <meta property="og:title" content="DÎVID OREILLY â Official Archive"> 24 <meta property="og:description" content="Explore a curated selection of animations, games, and interactive works from David OReilly."> 25 <meta property="og:image" content="https://www.davidoreilly.com/assets/img/socialShareDOR.jpg"> 26 <meta property="og:image:alt" content="David OReilly at work."> 27 <meta property="og:image:width" content="1200"> 28 <meta property="og:image:height" content="630"> 29 <meta property="og:image:type" content="image/jpeg"> 30 <meta property="og:site_name" content="David OReilly"> 31 <meta property="og:locale" content="en_US"> 32 <meta property="og:updated_time" content="2024-01-01T00:00:00Z"> 33 34 <!-- Twitter --> 35 <meta name="twitter:card" content="summary_large_image"> 36 <meta name="twitter:url" content="https://www.davidoreilly.com/"> 37 <meta name="twitter:title" content="DÎVID OREILLY â Official Archive"> 38 <meta name="twitter:description" content="Explore a curated selection of animations, games, and interactive works from David OReilly."> 39 <meta name="twitter:image" content="https://www.davidoreilly.com/assets/img/socialShareDOR.jpg"> 40 <meta name="twitter:image:alt" content="David OReilly at work."> 41 <meta name="twitter:creator" content="@davidoreilly"> 42 43 <!-- Apple-specific meta tags for iMessage --> 44 <meta name="apple-mobile-web-app-capable" content="yes"> 45 <meta name="apple-mobile-web-app-status-bar-style" content="default"> 46 <meta name="apple-mobile-web-app-title" content="David OReilly"> 47 <meta name="apple-touch-fullscreen" content="yes"> 48 <meta name="format-detection" content="telephone=no"> 49 50 <link rel="icon" href="/assets/dorb-Dcuwjmpj.gif" type="image/gif"> 51 <link rel="canonical" href="https://www.davidoreilly.com/"> 52 53 <!-- Optimized font loading --> 54 <!-- Using system fonts for privacy and performance --> 55 <!-- No external font requests = faster loading + zero tracking --> 56 57 <!-- Preload critical CDN resources --> 58 <link rel="preload" href="https://cdn.plyr.io/3.8.4/plyr.css" as="style"> 59 <link rel="preload" href="https://cdn.plyr.io/3.8.4/plyr.js" as="script"> 60 61 <!-- Additional resource hints --> 62 <link rel="dns-prefetch" href="https://img.youtube.com"> 63 <link rel="dns-prefetch" href="https://cdn.jwplayer.com"> 64 <link rel="preload" href="/media-catalog.json" as="fetch" crossorigin> 65 <link rel="preload" href="/assets/rgb-BKuYZS-I.gif" as="image"> 66 67 <!-- CSS files --> 68 <link rel="stylesheet" href="https://cdn.plyr.io/3.8.4/plyr.css"> 69
69<script type="module" crossorigin src="/assets/main.js"></script>
69 70 <link rel="stylesheet" crossorigin href="/assets/index-BAHJEOFs.css"> 71</head> 72<body> 73 <canvas id="glCanvas"></canvas> 74 75 <!-- Header container for side-by-side layout --> 76 <div class="header-container"> 77 <!-- Header with colored name --> 78 <div id="header"> 79 <div id="site-title"> 80 <span class="D">D</span> 81 <span class="A1">Î</span> 82 <span class="V">V</span> 83 <span class="I">I</span> 84 <span class="D2">D</span> 85 <span class="O">O</span> 86 <span class="R">R</span> 87 <span class="E">E</span> 88 <span class="I2">I</span> 89 <span class="L">L</span> 90 <span class="L2">L</span> 91 <span class="Y">Y</span> 92 </div> 93 <div id="header-toggles"> 94 <span id="theme-toggle" style="cursor: pointer;" title="theme [t]"></span> 95 <span id="shuffle-toggle" style="cursor: pointer;" title="shuffle [r]"></span> 96 </div> 97 </div> 98 99 <div id="top-navigation"> 100 <a href="https://t.me/davidoreilly" target="_blank" rel="noopener noreferrer" aria-label="Contact David OReilly on Telegram">Telegram<span class="external-link-icon">â</span></a> 101 <a href="https://sub.davidoreilly.com/about" target="_blank" rel="noopener noreferrer" aria-label="Subscribe to David OReilly's newsletter">Newsletter<span class="external-link-icon">â</span></a> 102 <a href="#" id="infoLink" aria-label="View contact information and CV">Info</a> 103 </div> 104 </div> 105 <div id="site-tagline">worlds & simulations</div> 106 107 <!-- Gallery --> 108 <main id="gallery" role="main" aria-label="Portfolio gallery"> 109 <!-- Artifacts will be loaded here by JavaScript --> 110 </main> 111 112 <!-- Lightbox --> 113 <div id="lightbox" role="dialog" aria-modal="true" aria-hidden="true" aria-labelledby="lightbox-title"> 114 <div class="content" role="img" aria-live="polite"> 115 <!-- Lightbox content (image/video and caption) will be loaded here --> 116 </div> 117 <button class="lightbox-nav-base lightbox-prev" style="display: none;" aria-label="Previous item" title="previous [â]">V</button> 118 <button class="lightbox-nav-base lightbox-next" style="display: none;" aria-label="Next item" title="next [â]">V</button> 119 </div> 120 121 <!-- Data usage tracker configuration --> 122
122<script> 123 // Configure data usage tracker (optional) 124 window.dataUsageConfig = { 125 budget: 500 * 1024 * 1024, // 500MB 126 warningThreshold: 0.8, // Show warning at 80% 127 autoHoverThreshold: 0.5, // Auto-hover at 50% 128 // donateUrl: 'https://davidoreilly.itch.io/gif-archive' // Use default from data-usage-tracker.js 129 }; 130 </script>
130 131 132 <!-- ES module entry point for production builds --> 133
133<script defer src="https://cdn.plyr.io/3.8.4/plyr.js"></script>
133 134
134<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/4.2.0/model-viewer.min.js"></script>
134 135 136 <!-- Performance monitoring --> 137
137<script> 138 window.addEventListener('load', () => { 139 // Basic performance monitoring 140 if ('performance' in window) { 141 const perfData = performance.timing; 142 const loadTime = perfData.loadEventEnd - perfData.navigationStart; 143 const domReady = perfData.domContentLoadedEventEnd - perfData.navigationStart; 144 145 // Store performance data 146 const perfInfo = { 147 loadTime, 148 domReady, 149 timestamp: new Date().toISOString(), 150 url: window.location.href 151 }; 152 153 // Store locally for debugging 154 try { 155 let perfs = []; 156 try { 157 perfs = JSON.parse(localStorage.getItem('sitePerformance') || '[]'); 158 if (!Array.isArray(perfs)) perfs = []; 159 } catch (parseErr) { 160 perfs = []; 161 } 162 perfs.push(perfInfo); 163 if (perfs.length > 20) perfs.shift(); // Keep last 20 entries 164 localStorage.setItem('sitePerformance', JSON.stringify(perfs)); 165 } catch (e) { 166 // storage unavailable â skip persisting perf log 167 } 168 169 // Track slow loads 170 if (loadTime > 3000 && window.trackError) { 171 window.trackError(new Error(`Slow page load: ${loadTime}ms`), 'performance'); 172 } 173 } 174 }); 175 </script>
175 176 177 <!-- Umami Analytics (Privacy-friendly, GDPR compliant) --> 178
178<script defer src="https://cloud.umami.is/script.js" data-website-id="1bc419e0-2673-49d7-acba-259bf5fb2847"></script>
178 179 180 <!-- Sentry Error Monitoring --> 181
181<script 182 src="https://js-de.sentry-cdn.com/5847a42abbac9119ae1fb963c7a377b0.min.js" 183 crossorigin="anonymous" 184 ></script>
184 185
185<script> 186 // Guard against Sentry CDN being blocked (e.g. uBlock Origin blocks Sentry by default). 187 // If Sentry global never loaded, silently skip init rather than throw a ReferenceError. 188 if (typeof Sentry !== 'undefined' && Sentry.onLoad) { 189 Sentry.onLoad(function() { 190 Sentry.init({ 191 ignoreErrors: [ 192 "reading 'isPresenting'", 193 "reading 'supportsPresentation'", 194 "reading 'xr'", 195 /model-viewer/i, 196 ], 197 }); 198 }); 199 } 200 </script>
200 201</body> 202</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.