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="description" content=""> 7 <meta property="og:site_name" content="Erik Onarheim"> 8 <meta property="og:title" content="Erik Onarheim | Blog"> 9 <meta property="og:description" content="Hi, my name is Erik ð I'm a software developer in Minneapolis â I created a game engine for the web excaliburjs.com, and all things .NET and TypeScript/JavaScript are my specialty"> 10 <!-- 1200 x 630 --> 11 <meta property="og:image" content="https://erikonarheim.com/images/blocks2.png"> 12 <meta property="og:url" content="https://erikonarheim.com/"> 13 <meta property="og:type" content="website"> 14 15 <meta property="twitter:title" content="Erik Onarheim | Blog"> 16 <meta property="twitter:card" content="summary"> 17 <meta property="twitter:url" content="https://erikonarheim.com/"> 18 <meta property="twitter:image" content="https://erikonarheim.com/images/blocks2.png"> 19 <meta property="twitter:description" content="Hi, my name is Erik ð I'm a software developer in Minneapolis â I created a game engine for the web excaliburjs.com, and all things .NET and TypeScript/JavaScript are my specialty"> 20 <meta property="twitter:site" content="@ErikOnarheim"> 21 <meta property="twitter:creator" content="@ErikOnarheim"> 22 23 <link rel="canonical" href="https://erikonarheim.com/"> 24 <link rel="shortcut icon" href="/favicon.png" type="image/png"> 25 <link rel="icon" href="/favicon.png" type="image/png"> 26 <link href="https://fonts.googleapis.com/css2?family=Roboto&family=Source+Code+Pro:wght@500&display=swap" rel="stylesheet"> 27 <link href="https://unpkg.com/[email protected]/themes/prism-okaidia.css" rel="stylesheet"> 28 <title>Erik Onarheim | Blog</title> 29
29<script defer data-domain="erikonarheim.com" src="https://plausible.io/js/script.js"></script>
29 30 <style> 31 32 33a { 34 text-decoration: none; 35 color: orange; 36 37} 38nav { 39 padding: 10px; 40 background-color: #094472; 41} 42 43nav > ol { 44 list-style: none; 45 padding: 0; 46 display: flex; 47 flex-direction: column; 48 align-items: center; 49} 50nav li { 51 padding-bottom: 5px; 52} 53html, body { 54 height: 100%; 55} 56 57h1, h2, h3, h4, h5 { 58 font-family: 'Source Code Pro', monospace; 59} 60 61body { 62 margin: 0; 63 font-family: 'Roboto', sans-serif; 64 color: #ccc; 65 font-size: 16pt; 66 background-color: #176BAA; 67} 68 69code { 70 color:#a6e22e; 71} 72 73pre { 74 font-size: .8em !important; 75} 76 77aside { 78 margin-left: 20px; 79} 80 81 82img { 83 max-width: 100%; 84} 85 86img.full { 87 width: 100%; 88 margin: auto; 89} 90 91form.contact { 92 display: flex; 93 flex-direction: column; 94 width: 500px; 95} 96 97form.contact p { 98 margin: .5em; 99} 100 101form.contact label { 102 width: 100%; 103} 104form.contact input { 105 width: 100%; 106 min-height: 25px; 107 font-size: 1em; 108 padding: 5px; 109 margin-top: 3px; 110} 111form.contact textarea { 112 width: 100%; 113 min-height: 100px; 114 resize: vertical; 115 padding: 5px; 116 margin-top: 3px; 117} 118 119form.contact button { 120 border: none; 121 cursor: pointer; 122 text-decoration: none; 123 border-radius: 2px; 124 padding: 15px; 125 background-color: green; 126 color: #efefef; 127 font-size: 1em; 128} 129 130.hidden { 131 display: none; 132} 133 134.main { 135 margin: 10px; 136} 137 138.posts { 139 list-style-type: none; 140} 141 142p:has(img,iframe) { 143 max-width: 100%; 144 display: flex; 145} 146 147p:has(img,iframe) img,iframe { 148 max-width: 100%; 149 margin: auto; 150} 151 152.posts li { 153 padding-bottom: 10px; 154} 155 156.post-info { 157 display: flex; 158} 159 160.post-tag { 161 display: inline-block; 162 color: #fbe607; 163 padding: 4px 10px; 164 margin: 2px 4px 2px 5px; 165 font-size: 16px; 166 border-color: #978b02; 167 border-style: solid; 168 border-radius: 12px; 169 white-space: nowrap; 170 height: 20px; 171 /* display: inline-block; 172 background-color: #111; 173 border-radius: 12px; 174 border: solid; 175 border-color: black; 176 font-size: 16px; 177 padding: 4px 10px; 178 margin: 0 4px; 179 box-shadow: inset 0 2px 3px #fff5, 4px 4px 10px rgba(0, 0, 0, .5); 180 text-shadow: 2px 2px 4px rgba(255, 255, 255, .3); */ 181} 182.post-tag:hover { 183 /* box-shadow: inset -1px -2px 3px #fff5, 4px 4px 10px rgba(0, 0, 0, .5); */ 184} 185 186/* .post-tag:nth-of-type(1n) { 187 color: #00B2D4; 188} 189.post-tag:nth-of-type(2n) { 190 color: #fbe607; 191} 192.post-tag:nth-of-type(3n) { 193 color: #B2F432; 194} 195.post-tag:nth-of-type(4n) { 196 color: #FF4324; 197} */ 198 199.contact-success .wiggles { 200 display: flex; 201} 202.wiggles img { 203 width: 100px; 204} 205 206.posts .date { 207 margin: 0 20px; 208} 209 210.games { 211 display: flex; 212 flex-flow: wrap; 213} 214 215.game { 216 position: relative; 217 padding-right: 25px; 218 padding-top: 10px; 219 padding-bottom: 30px; 220 padding-left: 30px; 221 222 margin: 5px; 223 224 display: flex; 225 flex-direction: column; 226 align-items: center; 227 font-size: 16px; 228 229 width: 200px; 230 height: 300px; 231 color: #ccc; 232 border: 2px solid rgb(41, 41, 41); 233 background-color: rgb(58, 57, 57); 234 border-radius: 5px; 235} 236 237.game:before { 238 content: ''; 239 position: absolute; 240 right:-1px; 241 bottom:-1px; 242 border-top: 50px solid transparent; 243 border-right: 50px solid rgb(41, 41, 41); 244} 245 246.game:after { 247 content: ''; 248 position: absolute; 249 right: -2px; 250 bottom: -2px; 251 border-top: 50px solid transparent; 252 border-right: 50px solid #176BAA; 253} 254 255.game img { 256 width: 95%; 257 min-width: 200px; 258 height: 142px; 259 border: 10px solid rgb(41, 41, 41); 260 background-image: url(/images/loading.svg); 261 background-size: contain; 262 background-repeat: no-repeat; 263 background-position: center; 264} 265 266.game label { 267 font-weight: bold; 268 font-size: 18px; 269 white-space: nowrap; 270 margin-bottom: 5px; 271 z-index: 1; 272} 273 274.game .buttons { 275 display: flex; 276 width: 65%; 277 justify-content: space-between; 278} 279 280.game .decal { 281 position: absolute; 282 top: 0; 283 left: 0; 284 width: 20px; 285 height: 100%; 286 background: linear-gradient( 287 to bottom, 288 transparent, 289 transparent 50%, 290 rgb(41, 41, 41) 50%, 291 rgb(41, 41, 41) 292 ); 293 background-size: 100% 10px; 294} 295 296 297 298 299@media only screen and (min-width: 1000px) { 300 body { 301 font-size: 18pt; 302 } 303 304 .main { 305 display: flex; 306 } 307 308 .left { 309 flex: 1 1; 310 } 311 312 .content { 313 width: 820px; 314 /* margin: auto; */ 315 margin-bottom: 100px; 316 } 317 318 .right { 319 flex: 1 1; 320 } 321 322 footer { 323 position: fixed; 324 bottom: 0; 325 width: 100%; 326 height: 32px; 327 background-position: bottom; 328 background-image: url("/images/blocks.png"); 329 background-repeat: repeat-x; 330 } 331
332 @keyframes cloud-move-left { 333 from {left: -200px;} 334 to {left: -500px} 335 } 336 337 .cloud1 { 338 position: fixed; 339 top: 0; 340 left: -200px; 341 z-index: -99; 342 width: 400px; 343 height: 400px; 344 animation: cloud-move-left 4s 1s; 345 animation-fill-mode: forwards; 346 background-position: center; 347 background-size: contain; 348 background-image: url("/images/clouds.png"); 349 background-repeat: no-repeat; 350 } 351 352 @keyframes cloud-move-right { 353 from {right: -200px;} 354 to {right: -500px} 355 } 356 357 .cloud2 { 358 position: fixed; 359 bottom: 100px; 360 right: -200px; 361 z-index: -99; 362 width: 400px; 363 height: 400px; 364 animation: cloud-move-right 4s 1.5s; 365 animation-fill-mode: forwards; 366 background-position: center; 367 background-size: contain; 368 background-image: url("/images/clouds.png"); 369 background-repeat: no-repeat; 370 } 371 372 .block { 373 position: fixed; 374 bottom: 100px; 375 right: 100px; 376 z-index: -99; 377 width: 96px; 378 height: 32px; 379 background-size: contain; 380 background-image: url("/images/blocks2.png"); 381 background-repeat: repeat-x; 382 } 383 384 .pipe { 385 position: fixed; 386 bottom: 32px; 387 left: 64px; 388 z-index: -99; 389 width: 64px; 390 height: 64px; 391 background-size: contain; 392 background-image: url("/images/pipe.png"); 393 background-repeat: no-repeat; 394 } 395 396 @keyframes bot-walk { 397 0% { left: 72px; bottom: 32px; } 398 3% { left: 72px; bottom: 80px; } 399 5% { left: 125px; bottom: 80px; } 400 7% { left: 135px; bottom: 28px; } 401 100% { left: 100vw; bottom: 28px; } 402 } 403 404 .bot { 405 z-index: -100; 406 position: fixed; 407 transform: scaleX(-1); 408 background-image: url("/images/run.gif"); 409 background-size: cover; 410 width: 64px; 411 height: 64px; 412 animation: bot-walk 30s; 413 animation-iteration-count: infinite; 414 animation-timing-function: linear; 415 left: 80px; 416 bottom: 32px; 417 } 418} 419 420.profile { 421 color: transparent; 422 border-radius: 50%; 423 width: 5em; 424 height: 5em; 425} 426 427.profile-header { 428 display: flex; 429 align-items: center; 430 flex-direction: column; 431} 432 433.profile-right { 434 display: flex; 435 flex-direction: column; 436 align-items: center; 437} 438.profile-right > h1 { 439 padding-left: 20px; 440 margin-bottom: 0; 441 margin-top: 0; 442 white-space: nowrap; 443} 444 445.socials { 446 display: flex; 447 width: 100%; 448 justify-content: space-evenly; 449 padding-left: 25px; 450} 451 452.socials a { 453 background-color: #CCC; 454 /* border: 2px solid; */ 455 color: transparent; 456 /* padding: 10px; */ 457 width: 40px; 458 height: 40px; 459 border-radius: 50%; 460 display: block; 461} 462 463.socials img { 464 padding: 10px; 465 width: 20px; 466 height: 20px; 467} 468 469@media only screen and (min-width: 550px) { 470 nav > ol { 471 display: flex; 472 flex-direction: row; 473 list-style: none; 474 justify-content: center; 475 max-width: 900px; 476 margin: auto; 477 } 478 nav > ol > li { 479 flex: 1 0 auto; 480 padding-bottom: 0; 481 } 482 483 .profile-header { 484 display: flex; 485 flex-direction: row; 486 } 487 488} 489 490 </style> 491 </head> 492 <body> 493 <nav> 494 <ol> 495 <li><a href="/">Home</a></li><li><a href="/posts/">Posts</a></li><li><a href="/contact/">Contact</a></li><li><a href="/games/">Games</a></li><li><a href="/speaking/">Speaking</a></li><li><a href="/sponsor/">Sponsor Me</a></li></ol> 496</nav> 497 <div class="main"> 498 <div class="left"></div> 499 <main class="content" data-role="main"> 500 <h1></h1> 501 <div class="profile-header"> 502 <img class="profile" src="images/profile-squarecrop.jpg" /> 503 <div class="profile-right"> 504 <h1> Erik Onarheim</h1> 505 <div class="socials"><div class="social"> 506 <a rel="me" href="https://github.com/eonarheim"><img alt="GitHub" src="/images/social/github.svg" /></a> 507 </div><div class="social"> 508 <a rel="me" href="https://twitter.com/erikonarheim"><img alt="Twitter" src="/images/social/twitter.svg" /></a> 509 </div><div class="social"> 510 <a rel="me" href="https://www.threads.net/@erikonarheim"><img alt="Threads" src="/images/social/threads.svg" /></a> 511 </div><div class="social"> 512 <a rel="me" href="https://bsky.app/profile/erikonarheim.bsky.social"><img alt="Bluesky" src="/images/social/bluesky.svg" /></a> 513 </div><div class="social"> 514 <a rel="me" href="https://mastodon.social/@erikonarheim"><img alt="Mastodon" src="/images/social/mastodon.svg" /></a> 515 </div><div class="social"> 516 <a rel="me" href="https://www.youtube.com/channel/UCpfvwJIqmxG-3DD4QMofyxg"><img alt="YouTube" src="/images/social/youtube.svg" /></a> 517 </div><div class="social"> 518 <a rel="me" href="https://www.linkedin.com/in/erik-onarheim"><img alt="LinkedIn" src="/images/social/linkedin.svg" /></a> 519 </div><div class="social"> 520 <a rel="me" href="https://feeds.feedburner.com/erikonarheim"><img alt="RSS" src="/images/social/rss.svg" /></a> 521 </div></div> 522 </div> 523</div> 524<p>Hi, my name is Erik ð I'm a software developer in Minneapolis â</p> 525<p>Fullstack dev by day ð» maintainer of <a href="https://excaliburjs.com">Excalibur.js</a> by night âï¸</p> 526<p>    ð® <a href="https://igdatc.org/#board">IGDATC</a> Board Member<br> 527    âï¸ Cloud Focused<br> 528    ð¶ New Dad<br> 529    ð¹ï¸ Game Dev<br> 530    ð» Cat Lover<br> 531    ðââï¸ Distance Runner<br> 532    ð Math/Physics Nerd<br></p> 533 534 </main> 535 <div class="right"> 536 537 538 539<aside> 540 <h3>Recent Posts</h3> 541 <ul> 542 543 <li> 544 <a href="/posts/2024-the-best-worst-year/">2024 The Best Worst Year</a>
545 <span>Saturday, March 8th, 2025</span> 546 </li> 547 <li> 548 <a href="/posts/animating-with-coroutines/">Animating with Coroutines</a> 549 <span>Thursday, June 2nd, 2022</span> 550 </li> 551 <li> 552 <a href="/posts/handling-height-in-isometric/">Handling Height in Isometric Tile Maps</a> 553 <span>Wednesday, February 2nd, 2022</span> 554 </li></ul> 555</aside> 556 557 558 </div> 559 </div> 560 <div class="block"></div> 561 <div class="pipe"></div> 562 <div class="cloud1"></div> 563 <div class="cloud2"></div> 564 <div class="bot"></div> 565 <footer> 566 </footer> 567 568
568<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"b7ddfe06d9d94f758b81c3e3bf84a175","r":1,"spa":2}' crossorigin="anonymous"></script>
568 569</body> 570</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.