<?xml version="1.0" encoding="UTF-8" ?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>bl.elg.gg</title><link>https://bl.elg.gg/</link><description>bl.elg.gg</description><language>en-us</language><atom:link rel="self" href="https://bl.elg.gg/rss" type="application/rss+xml" /><item><title>Looking Good</title><link>https://bl.elg.gg/looking-good</link><description>Looking Good</description><pubDate>Sat, 28 Mar 2026 00:00:00 GMT</pubDate><guid>https://bl.elg.gg/looking-good</guid><content:encoded><![CDATA[<p>I’m not exceptionally skilled at first-person shooters, but I’m very particular about making sure that my look sensitivity in first-person games is what I’m used to, even in a non-competitive context. That is to say, it should feel the same between games. To me, this seems like something easy to solve, but every game I’ve ever played, no matter the budget, does the same thing - they give you a slider with an arbitrary unit on it.</p>
<h1 id="preface"><a href="#preface">Preface</a></h1>
<p>Mouse sensitivity is measured in DPI: dots per inch, where a “dot” refers to the smallest unit of raw sensor movement. If your OS leaves the sensitivity alone, then DPI effectively means pixels per inch.</p>
<p>If you want the most precision possible, you should not adjust your mouse sensitivity in your OS settings - you should configure it in the mouse software. If you agree with me or you don’t care, feel free to <a href="#the-problem">skip</a> the rest of this section:</p>
<h3>Mouse software</h3>
<p>When you adjust your mouse sensitivity in the mouse software, you’re adjusting the sensitivity of the sensor. So if you increase it by 25%, then the mouse will report 1 dot at 80% of the distance of the previous sensitivity (1 / 1.25 = 0.8). All is well and good here.
<div class="callout info-callout"><span class="callout-icon info-callout-icon"></span><span>Tangent: Because your mouse reports movement at smaller distances at higher DPI, You can technically get more precise look sensitivity in games by going with a high mouse software sensitivity and low in-game look sensitivity (since look sensitivity only changes the amount of camera rotation per dot), but the benefit is probably not worth the uncomfortably high cursor speed in menus.</span></div>
</p>
<h3>OS Sensitivity</h3>
<p>In contrast, if you set your OS sensitivity to 125%, your OS tries to fake this increase: If the mouse reports 4 dots in one poll, it’s adjusted to 5. If the mouse reports 8, it’s adjusted to 10. This works fine for these nicely divisible values; however, for numbers that don’t end up as a whole integer, the OS uses subpixel precision by storing the remainder in an internal accumulator. For simplicity, let’s use a scenario where the mouse is moving at a steady pace of 1 dot per poll at 125% OS sensitivity:</p>
<table><thead><tr><th>poll #</th><th>Pointer movement</th><th>Accumulator after movement</th></tr></thead><tbody>
<tr><td>1</td><td>1</td><td>0.25</td></tr>
<tr><td>2</td><td>1</td><td>0.50</td></tr>
<tr><td>3</td><td>1</td><td>0.75</td></tr>
<tr><td>4</td><td><strong>2</strong></td><td>0.00</td></tr>
<tr><td>5</td><td>1</td><td>0.25</td></tr>
<tr><td>6</td><td>1</td><td>0.50</td></tr>
</tbody></table>
<p>And so on.
Note that there are separate accumulators for the X and Y axis, but for this example, let’s assume the mouse is moving only along 1 axis.</p>
<p>In the first poll, the mouse reports 1 dot, which gets converted to 1.25 pixels, so the cursor moves 1 pixel and the remaining 0.25 is stored in the accumulator. This process repeats, storing an additional 0.25 in the accumulator until poll #4, where adding the 1.25 movement to 0.75 leads to a movement of 2 pixels. So every 4th poll, the mouse moves 2 pixels instead of one, adding jitter to our steady 1 dot per poll speed.</p>
<p>You can test this yourself, if you’ve got the hand and eyes for it. Set your OS mouse sensitivity to some value a little over 1x and then move the mouse along an axis, pixel by pixel. You’ll notice that at some point, it will jump 2 pixels instead of 1. If you move the mouse back, it jumps 2 pixels again, but only 1 pixel in the area immediately around it.</p>
<p>The precision loss is mostly negligible at values close to 1:1 and gets worse the higher the OS sensitivity is set. For example, if your OS sensitivity is 3x the mouse sensitivity, the cursor can move no less than 3 pixels at a time.</p>
<p>This is why it’s common for competitive players to recommend modifying mouse sensitivity only in mouse software and leaving OS sensitivity at 1:1 (as well as disabling acceleration, or “Enhance pointer precision” on Windows, but that’s a different story).</p>
<p>Granted, you don’t lose much precision when the OS is trying to <strong>lower</strong> the mouse sensitivity rather than raise it, but the point is: For the rest of this post we’ll assume a 1:1 OS sensitivity (or otherwise Raw Input being enabled in the game).</p>
<h1 id="the-problem"><a href="#the-problem">The problem</a></h1>
<p>The naive approach to achieve consistent look sensitivity between first-person games is aiming for the same degrees of rotation per dot. You might measure how much your mouse needs to travel to turn 360 degrees, and you might notice that despite this, it still doesn’t feel the same between games. This is due to a difference in FOV between games.</p>
<p>I created <a href="https://nginx.elg.gg/fpst">a tool</a> in Unity many years ago to test and transfer look sensitivities to other games. The page has a pretty good explanation:</p>
<blockquote>
<p>Though this tool has the option to measure the amount that one’s mouse travels in a 360 degree turn, it can also measure the distance to look from one edge of the player’s field of view to the other (from an object on one edge of the screen to an object on the other). Consistent sensitivity using this reference is typically preferred over consistency in degrees because your reticle travels the same amount relative to objects around it.</p>
<p>For example, if you’re looking down the scope of a sniper rifle, you would not want to turn the same amount of degrees per dot that you would when looking around normally. You would want the visible world to move across the screen by the same amount. Measuring the distance your mouse travels when looking across your field of view creates this perceived consistency in all FOVs, so you do not need to maintain consistent FOV between games.</p>
</blockquote>
<p>To be fair, matching sensitivities in terms of degrees of rotation is fine so long as the FOV is consistent between games. Another factor is the window size but I’ll assume most people play in full screen.</p>
<p>Anyway, the tool was more of a learning project for me - you really just need a piece of paper.</p>
<h1 id="the-solution"><a href="#the-solution">The Solution</a></h1>
<p>On my desk there’s an old envelope with 2 markings on it a couple inches apart. The distance between these markings is the distance my mouse should travel to look from one side of my FOV to the other. So whenever I start a new first-person game, I do the following:</p>
<ol>
<li>Align 2 objects exactly at both edges of my screen</li>
<li>Look at the object to the left, with my crosshair aligned vertically at the horizon</li>
<li>Pause the game</li>
<li>Put that paper under my mouse with the right side of the mouse aligned with the first marking</li>
<li>Unpause the game and move my mouse to the right until I’m looking at the object to the right</li>
<li>See where the mouse landed. If the right side of the mouse is to the left of the marking, decrease the game’s look sensitivity. If it’s to the right of it, increase it. Then start again from step 2 until the mouse ends up aligned with the second marking.</li>
</ol>
<p><div class="callout info-callout"><span class="callout-icon info-callout-icon"></span><span>Note: Mouse acceleration should be off to get consistent results.</span></div>
</p>
<p>The markings I initially drew with the same process, but instead of the crosshair, I moved my desktop cursor from one side of the screen to the other. I wanted my look sensitivity to feel like my pointer speed. Another benefit of this method is that it even ensures consistent look sensitivity between mice from different brands of which the software may report different speeds as the same DPI value, since you’re basing it on physical mouse travel distance.</p>
<p>Ideally, developers would use something like “Dots per FOV°” as the unit. If we measure look sensitivity in dots to turn the camera by the amount of degrees that your horizontal FOV takes up, then we have just one number that we have to remember. Want to look around at about the same speed as your pointer? Set it to your horizontal resolution (again, assuming full screen and a 1:1 OS sensitivity). The only caveat is that higher numbers would be slower, which might be counterintuitive but I guess you could just use the reciprocal or something.</p>
<p>Realistically though no game developer is going to start doing this so if you want consistent look sensitivity, just use the paper method.</p>
<p>Thanks for reading.</p>
]]></content:encoded></item><item><title>Airplane Mode</title><link>https://bl.elg.gg/airplane-mode</link><description>Airplane Mode</description><pubDate>Mon, 30 Jun 2025 00:00:00 GMT</pubDate><guid>https://bl.elg.gg/airplane-mode</guid><content:encoded><![CDATA[<p>I’ve always been reluctant to post content to the internet. I’ve made an effort in the past to delete old posts and accounts when I got old enough to hate them. Even things like open source software that I create I’m often afraid to promote on the basis of it not being perfect and immune to scrutiny. I’ve come to find, though, that perfection is impossible and no one actually sees your stuff anyway - but if many do, then maybe you’re already doing something right.</p>
<h1 id="context"><a href="#context">Context</a></h1>
<p>My first software job was on-site web development at a sports supplement company. Protein powder, bodybuilding, stuff I’m not really into. The development team at the time was just the team lead and 2 cousins, Chris and Ricky. Cool guys. In fact, you’re probably one of them, as they’re likely the only people who will ever read this post.</p>
<p>I worked there for a little over 2 years until Ricky suggested I look into Rust while he was researching blockchain technologies during a crypto boom around 2021 because of course, Rust is used to write smart contacts on Solana. I was never really into blockchain, and Ricky’s interest was also short-lived, but he saw the potential in Rust for general use so I looked into using it as a backend language with <a href="https://rocket.rs/">Rocket</a> and similar.</p>
<p>I left that company to pursue this (they also left shortly after; such is life). I eventually started taking some Rust contracts, and Chris and Ricky and I remained friends. Ricky recently started <a href="https://www.rickykissoon.com/">his site</a> &amp; <a href="https://www.rickykissoon.com/blogs/">blog</a> and gave us a challenge:</p>
<p><img src="/static/assets/airplane_mode/lets_all_blog.png" alt="“Let’s all blog”" /></p>
<h1 id="the-blog"><a href="#the-blog">The blog</a></h1>
<p>There’s already <a href="https://www.getzola.org/">Zola</a> which I’m sure is great for blogs, but we could go lighter. Plus, Zola uses <a href="https://docs.rs/pulldown-cmark/latest/pulldown_cmark/">pulldown_cmark</a> to do all the heavy lifting of converting markdown to HTML, so after I implement that:</p>
<pre><code class="language-rust">fn markdown_to_html(markdown_input: &amp;str) -&gt; String {
    let parser = Parser::new_ext(markdown_input, Options::all());
    let mut html_output = String::new();
    html::push_html(&amp;mut html_output, parser);
    html_output
}
</code></pre>
<p>There’s not much else to build to warrant using Zola. This was the hard part and pulldown_cmark did the work for me.</p>
<p><div class="callout update-callout"><span class="callout-icon update-callout-icon"></span><span>I later updated this function to also add anchor links to <code>h1</code> headers and to support this update callout box, so it looks different now.</span></div>
</p>
<p><div class="callout info-callout"><span class="callout-icon info-callout-icon"></span><span>There’s also this “info” version.</span></div>
</p>
<p>The site isn’t much. You can see the source <a href="https://github.com/Elgenzay/bl.elg.gg">here</a>. On launch, it reads the blog post files and persists it in memory (Rocket’s managed state). I figured this is better than reading the files on each GET, and it’s not like this blog will ever have enough posts for memory to be an issue. It’s simple enough that I think a database would be overkill. Maybe if I add comments, but frankly, I don’t want these pages to be soiled by user-generated content. When I add a post, I can update the managed state by visiting this <a href="/reload">reload endpoint</a> which only runs if it’s been more than 10 seconds since the previous reload request.</p>
<p>The frontend uses Tera via <a href="https://api.rocket.rs/master/rocket_dyn_templates/">rocket_dyn_templates</a>. No frontend frameworks beyond that. The CSS logo at the top I created with <a href="https://pixelartcss.com/">pixelartcss.com</a>, and the background animation JS (visible only on wider screens) I initially wrote for <a href="https://elg.gg">elg.gg</a>.</p>
<p>Posts are stored in the <code>static/posts</code> directory as markdown, with toml front matter at the beginning:</p>
<pre><code>+++
title = "Airplane Mode"
date = "2025-06-30"
+++
Content goes here
</code></pre>
<p>The slug used in the URL is determined by the file name. This post is being sourced from <a href="/static/posts/airplane_mode">this file</a>.</p>
<p>I also added an <a href="/rss">RSS feed</a>. I don’t personally use an RSS reader but it passes the <a href="https://validator.w3.org/feed/check.cgi?url=https%3A%2F%2Fbl.elg.gg%2Frss">W3C validator</a> so it should be good.</p>
<h1 id="the-future"><a href="#the-future">The future</a></h1>
<p>I don’t know if I’ll be able to commit to posting here at any reasonable frequency. The future of independent online blogging looks bleak, what with microblogging platforms and the exponential growth of LLMs muddying things up. You can’t tell if someone actually wrote what they posted anymore, and I got this far in life without feeling the need to post long-form content.</p>
<p>The majority of this post (minus the “The blog” section) was drafted during a flight to PAX East (hence the post title), during which I had no internet so maybe I’ll write again if I find myself in a similar situation. I didn’t have this blog site built at the time of writing so it took a month before I got around to building the site, revising this post, and publishing it. Maybe the existence of this site will be a motivator to continue writing. You’ll know I’ve ran out of topics when I post a dissertation comparing the GameCube port of Sonic Adventure 2 to the Dreamcast version.</p>
<p>Thanks for reading.</p>
]]></content:encoded></item></channel></rss>