-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
175 lines (156 loc) Β· 8.6 KB
/
index.html
File metadata and controls
175 lines (156 loc) Β· 8.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
ο»Ώ<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>π§ Brian Hungerman</title>
<meta name="description" content="Brian Hungerman: Software Engineer working in Graph Theory and Gamification. Portfolio, projects, hackathons, games.">
<meta name="author" content="Brian Hungerman">
<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:title" content="Brian Hungerman: Software Engineer">
<meta property="og:description" content="Portfolio showcasing work in Graph Theory, Gamification, Robotics & A.I. U.X. at Microsoft Applied Sciences.">
<meta property="og:image" content="https://mutilar.github.io/png/brian.png">
<meta property="og:url" content="https://mutilar.github.io/">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Brian Hungerman: Software Engineer">
<meta name="twitter:description" content="Portfolio showcasing work in Graph Theory, Gamification, Robotics & A.I. U.X. at Microsoft Applied Sciences.">
<meta name="twitter:image" content="https://mutilar.github.io/png/brian.png">
<meta name="twitter:site" content="@BrianHungerman">
<link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin>
<link rel="preconnect" href="https://img.youtube.com" crossorigin>
<link rel="dns-prefetch" href="https://cdnjs.cloudflare.com">
<link rel="dns-prefetch" href="https://img.youtube.com">
<link rel="shortcut icon" type="image/x-icon" href="png/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="png/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="png/favicon-16x16.png">
<link rel="icon" type="image/png" href="png/brian.png">
<link rel="apple-touch-icon" type="image/png" href="png/brian.png">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/v4-shims.min.css">
<link rel="stylesheet" href=".engine/css/STYLE.css">
<script>
// Restore theme before first paint to prevent FOUC
(function() {
if (localStorage.getItem('theme-mode') === 'light') {
document.documentElement.classList.add('light-mode');
}
})();
</script>
</head>
<body>
<noscript>
<div style="background:#1a1a1a;color:#fff;padding:48px 24px;text-align:center;font-family:system-ui,sans-serif;">
<h1>Brian Hungerman: Software Engineer</h1>
<p>This portfolio requires JavaScript to display interactive content.</p>
<p><a href="https://www.linkedin.com/in/brian-hungerman/" style="color:#00A4EF;">LinkedIn</a> Β· <a href="https://github.com/Mutilar" style="color:#00A4EF;">GitHub</a> Β· <a href="mailto:brianhungerman@gmail.com?subject=ππ»%20Hey%20π§%20Brian!" style="color:#00A4EF;"></a></p>
</div>
</noscript>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ProfilePage",
"mainEntity": {
"@type": "Person",
"name": "Brian Hungerman",
"jobTitle": "Senior Software Engineer",
"worksFor": { "@type": "Organization", "name": "Microsoft Applied Sciences" },
"url": "https://mutilar.github.io/",
"sameAs": [
"https://www.linkedin.com/in/brian-hungerman/",
"https://github.com/Mutilar",
"https://twitter.com/BrianHungerman"
]
}
}
</script>
<a href="#about" class="skip-to-content">Skip to content</a>
<!-- βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
DUAL PARALLAX BACKGROUNDS β two fixed canvas layers
Attention (bright/fast) sits deepest; Rest (dim/slow) on top.
The rest layer's opacity is controlled by JS so both can
blend or one can dominate depending on scroll position.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ -->
<div id="parallax-bg">
<canvas id="orbCanvas"></canvas>
<canvas id="glintCanvas"></canvas>
</div>
<!-- βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
NAVIGATION
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ -->
<nav class="glass-nav" id="mainNav">
<!-- Brand, theme toggle, and nav links injected by
BOOT.JS β THEME.JS β DATA.JS (from per-JSON nav entries).
Radio player injected by RADIO.JS (from settings.media). -->
</nav>
<!-- βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PAGE CONTENT β alternating windows & opaque bands
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ -->
<div id="page-content">
<!-- βββ Hero β rendered by DATA.JS from HERO.json βββ -->
<div id="hero"></div>
<!-- βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
SECTIONS β generated by DATA.JS from per-section JSON
header{} blocks. Each section JSON contributes an
opaque-band + parallax-window pair, sorted by index.
Includes: About, Marp, BitNaughts, MTG, Work, Education,
Projects, Hackathons, Games, Footer, Open Source.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ -->
<div id="sections"></div>
</div>
<!-- Modals are created on-the-fly by registerModal() in MODALS.JS -->
<!-- βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
SCRIPTS β settings-driven tier loader
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ -->
<script type="module">
import * as pdfjsLib from 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.7.76/pdf.min.mjs';
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.7.76/pdf.worker.min.mjs';
window.__pdfjsLib = pdfjsLib;
window.dispatchEvent(new Event('pdfjsReady'));
</script>
<script>
(function () {
/* ββ Tier-based script loader ββ */
function loadScript(src, optional) {
return new Promise(function (resolve, reject) {
var s = document.createElement('script');
s.src = src;
s.onload = resolve;
s.onerror = function () {
if (optional) { console.warn('[loader] optional ' + src + ' not loaded'); resolve(); }
else reject(new Error('Failed to load ' + src));
};
document.body.appendChild(s);
});
}
function loadScriptTiers(scripts, prefix) {
var tiers = {};
scripts.forEach(function (s) {
(tiers[s.order] = tiers[s.order] || []).push(s);
});
return Object.keys(tiers).sort(function (a, b) { return a - b; }).reduce(function (chain, tier) {
return chain.then(function () {
return Promise.all(tiers[tier].map(function (s) {
// If src already has a path separator, load directly (scripts_local)
var path = s.src.indexOf('/') !== -1 ? s.src : prefix + s.src;
return loadScript(path, s.optional);
}));
});
}, Promise.resolve());
}
/* 1. Fetch SETTINGS.json, then load scripts by tier */
var _settingsMetaPath = (document.querySelector('meta[name="settings-path"]') || {}).content || 'json/SETTINGS.json';
fetch(_settingsMetaPath + '?v=' + Date.now())
.then(function (r) { return r.ok ? r.json() : {}; })
.catch(function () { return {}; })
.then(function (settings) {
window.__SETTINGS = settings;
/* 2. Load engine scripts by tier from settings.scripts[] */
var scripts = (settings.scripts || []).concat(settings.scripts_local || []);
return loadScriptTiers(scripts, '.engine/js/');
}).catch(function (err) { console.error('[loader]', err); });
})();
</script>
</body>
</html>