<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Nick Zuber on Medium]]></title>
        <description><![CDATA[Stories by Nick Zuber on Medium]]></description>
        <link>https://medium.com/@nickzuber?source=rss-2aa718162162------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*J7GnQvIUB0Gj1ffS7l4bxg.png</url>
            <title>Stories by Nick Zuber on Medium</title>
            <link>https://medium.com/@nickzuber?source=rss-2aa718162162------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 25 Jun 2026 03:15:03 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@nickzuber/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Procedurally Generating Indoor Pathways]]></title>
            <link>https://medium.com/@nickzuber/procedurally-generating-indoor-pathways-dbf7d7fe4ace?source=rss-2aa718162162------2</link>
            <guid isPermaLink="false">https://medium.com/p/dbf7d7fe4ace</guid>
            <category><![CDATA[procedural-generation]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[wayfinding]]></category>
            <category><![CDATA[algorithms]]></category>
            <category><![CDATA[mathematics]]></category>
            <dc:creator><![CDATA[Nick Zuber]]></dc:creator>
            <pubDate>Sun, 08 May 2022 20:30:34 GMT</pubDate>
            <atom:updated>2022-05-08T20:30:34.974Z</atom:updated>
            <content:encoded><![CDATA[<h4>Exploring a new technique for wayfinding that doesn’t involve drawing anything by hand.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jMH0hlax-UPw-aA3b9xO5A.png" /><figcaption>Image of a procedurally generated indoor pathway for a floor.</figcaption></figure><p>Wayfinding is a pretty cool problem because everyone is familiar with it. Whether you’re trying to find the nearest coffee shop, planning the commute to your office, or traveling across state lines, everybody wants to know the best way to get there.</p><p>The desire to know how to get between two places doesn’t only exist in the outside world though — sometimes you might want directions for how to get somewhere <em>inside</em> a building.</p><p>Let’s say it’s your first day at your new job at the big tech company Hooli. You have an important meeting in room 617B on the sixth floor. Getting to the sixth floor is easy because you obviously know where the elevators are, right? But finding room 617B is a bit more complicated than that because each floor in your fancy new office is the size of a small city. What are you supposed to do — run around, reading each room&#39;s name like somebody who isn’t already 5 minutes late?</p><p>A much better solution here would be to open some maps app on your phone that would tell you where room 617B is and exactly <em>how to get there</em>, or something to that effect.</p><p>There are a few things that make this a hard problem to solve:</p><ol><li>You probably don’t even have a map of your office on your phone in the first place (although, <a href="https://robinpowered.com/maps"><em>you could</em></a><em>)</em></li><li>Getting different pathways between rooms within an indoor space is traditionally a manual and tedious process that involves people literally drawing lines by hand.</li></ol><p>Finding the actual pathways for an indoor space is a surprisingly hard and abstract problem, especially when you compare it to finding pathways for an outdoor space.</p><p>Outdoor space pathways usually end up being just streets or roads, which is data that the map already has to begin with. For an indoor space, a pathway is more like <em>the absence</em> of the data we begin with since the pathways are the areas between all of the things that we know about (walls, chairs, tables, etc).</p><p>Because of this, most ways people solve this problem is by creating the “pathways” data <em>by hand</em>. In other words, someone will go in and draw invisible lines all over the place and use those as “roads”.</p><p>That’s lame because it doesn’t scale very well. Imagine having to draw pathways for hundreds or thousands of floors. Super lame. Since we don’t want to be lame, we can try to find a way to generate indoor pathways procedurally, so every floor can have pathways without us having to lift a finger.</p><h3>Wait, so what even is a “pathway”?</h3><p>If you think about it for too long, the concept of a “pathway” gets pretty blurry. So let’s take a step back — the problem we’re trying to solve is figuring out a way to get from point A to point B within an indoor space.</p><p>To help prevent us from getting distracted by the details, let’s imagine all the floors we’ll be looking at don’t have anything within them — just empty hallways.</p><p>So as far as we’re concerned, <em>a “pathway” is just a collection of contiguous line segments from some point A to some point B, such that no line segment intersects through any walls or entities on the floor</em>. That’s basically just a fancy way of saying that a pathway is a bunch of lines that are in-between walls.</p><p>Knowing where the walls are is the bare minimum requirement for even attempting to find any pathways, so let’s use this as our starting point — let’s assume that we already have all of the information about where walls are on a floor.</p><p>Great! So now that we know where all of the walls are in the form of a bunch of line segments, how can we figure out where all the pathways are? If only there was some kind of magical way of finding line segments in-between other line segments…</p><h3>Introducing the Voronoi Diagram</h3><p>Let’s take a break for a minute and talk shapes. In the world of mathematics, there is a special kind of diagram that helps partition geospatial data into groups based on their proximity to one another — it’s called a <a href="https://en.wikipedia.org/wiki/Voronoi_diagram"><strong>Voronoi diagram</strong></a>.</p><p>The idea is simple but can sound complicated — given a bunch of “source” points on a plane, divide that plane into different sections such that any arbitrary point within a section is closest to that section’s original source point more than any other section’s original source point.</p><p>Listen, I get it — it’s <em>kind of</em> hard to explain. The important thing to know is that these diagrams can be used to find which source point you’re closest to, wherever you are on the plane.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/220/0*beRf5Y9ihdtwwfLx.gif" /><figcaption>Demonstration of a Voronoi diagram being created, showing how each polygon contains all points that are closest to its source point compared to the other source points.</figcaption></figure><p>Now, I know what you’re thinking — that’s cool, but so what? How does that help us with finding indoor pathways?</p><p>Well, that’s the fun part. I noticed an interesting property that these Voronoi diagrams had. Since they’re designed to generate polygons around a point of origin, such that any point within the polygon is closest to its respective origin point than any other, that means there must <em>also</em> exist some points that are equally close to two or more different origin points — those points are actually the ones that form the lines which make up the generated polygons.</p><p>Do you know where I’m going with this yet? The line segments that make up each polygon within a Voronoi diagram are equidistant from some two origin points.</p><p>Sound familiar? This is incredibly close to the original problem we’re trying to solve with pathways! <strong>We are trying to figure out how to find lines between two walls, and this diagram will find us lines between two points.</strong></p><p>We now have a way of finding a line segment between two points, so if we just change up our input a little bit and convert those walls into many different points, we should be able to create a Voronoi diagram and “extract” the pathways we’re looking for from the generated polygons.</p><h3>Sculpting pathways from the marble of Voronoi</h3><p>Cool, so let’s put this idea to the test. We essentially want to generate a Voronoi diagram with the walls, and then extract the polylines that navigate through the hallways.</p><h4>Step 1: Generating the Voronoi diagram</h4><p>Since we need points to create a Voronoi diagram, we can just convert our wall line segments into points.</p><p>Instead of just using the start and end positions of the line as its points, we want to generate a bunch of points in between them as well. This is because we want the Voronoi polylines to <em>stay</em> within the hallways.</p><blockquote>Recall how the generated polylines are equidistant between any two source points. To ensure we get as many polylines as possible that exist in the hallways, we need more points on the wall line segment.</blockquote><p>Once we get all these points, all that’s left is to run it through any Voronoi algorithm you prefer. Since the resulting diagram is technically a bunch of polygons, we should convert them into line segments before we do anything with them. That part is easy — we just iterate through each point in a polygon and form a line segment using the next point in the order we see them.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WEX3LTUKBZ0QEvAAKnaNrQ.png" /><figcaption>Our indoor floor having its walls broken up into many points and then using those points to create a Voronoi diagram on top of it.</figcaption></figure><h4>Step 2: Simplify, simplify, simplify!</h4><p>Now that we have a bunch of line segments, we need to figure out a good way to simplify our data. We only care about pathways through the floor — we know they’re somewhere in all of these lines, so we need to help ourselves reveal them by removing the lines which will not help us.</p><p>Let’s start by figuring out which of these lines are totally useless. In our case here, a line is useless if it either:</p><ul><li>Is outside of our floor’s boundaries (the outer walls).</li><li>Goes through a wall.</li></ul><p>We can find any lines that fall outside of the floor’s boundaries by taking the <a href="https://en.wikipedia.org/wiki/Convex_hull">convex hull</a> of the outer walls, and simply pruning any line segments that either intersect with the hull or are outside of the hull.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1HPF0-yOaXj0rs0B2gWIcw.png" /><figcaption>Our indoor floor showing the line segments created from the Voronoi diagram. The convex hull is superimposed on the floor and all lines that fall outside are marked to be removed.</figcaption></figure><p>Similarly, we can find all of the lines that go through walls by comparing each line to our original wall dataset. If a line intersects with a wall, prune it!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nu-ll_IRZqp4vMW1PFJgRg.png" /><figcaption>Our indoor floor with all line segments which intersect with any walls being removed.</figcaption></figure><p>And… voilà! We’re left with a bunch of lines (a whole lot less than what we started with at least) that make up some kind of pathway through the entire floor!</p><h4>Step 3: Make it useful</h4><p>These lines might make sense to us visually, but not so much to a computer. In order for us to write a performant program for deriving pathways using these lines, we need to convert the data into something more helpful for the job — in our case, a weighted graph works perfectly.</p><p>For this graph, the vertices are the start and end points of our line segments, and the edges are just the lines themselves. The “weight” of each edge can just be the distance of the edges in pixels.</p><p>With the graph we just created, we can finally start wayfinding! Just pick two points on the floor, find the closest points on any of the edges to designate our true starting and ending positions, and then we can find the shortest path using any “<a href="https://en.wikipedia.org/wiki/Shortest_path_problem#Algorithms">shortest pathfinding</a>” graph algorithm of your choosing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6Dn7U-vwBBy-Lp6hhI1Ljg.png" /></figure><h4>Step 4: Finishing touches</h4><p>This works great and now we actually have a pathway between any two points on our floor, however, you’ve probably noticed that the generated path is a bit bumpy.</p><p>We can address this by using some <a href="https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm#Algorithm">polyline smoothing algorithm</a>, but we need to make sure we don’t smooth it out <em>too</em> much.</p><p>If the path gets too smooth, then it runs into the risk of smoothing itself through walls since the nature of smoothing a line is to “take shortcuts” between points.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/220/0*dxxTXGr23rAh9tfz.gif" /><figcaption>The general approach for most smoothing algorithms in action — taking shortcuts between points on a line to further simplify it.</figcaption></figure><p>After a bit of path smoothing, we’re left with the result — an indoor pathway that gets us between two places on a floor.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gAuF5zhT2iUG_vYyETmmtA.png" /></figure><h3>Moving forward</h3><p>While all of this works, it’s of course still possible to make many improvements.</p><ul><li>Extend this algorithm to account for things like desks, tables, and all other entities on the floor. We would just need to know where those things are and include them in our Voronoi dataset and things will work as expected!</li><li>We could extract the secret sauce from the Voronoi diagram generation and come up with a simpler algorithm that doesn’t waste our time generating as many “bad” lines or polygons.</li><li>Finding the convex hull of the floor is helpful but imperfect. We could instead just find the outer-most part of the entire wall dataset and use that as our bounds instead.</li><li>That path smoothing approach could be refined to always try and simplify a path as much as possible so long as it doesn’t collide with a wall or other entity on the map.</li></ul><p>The purpose of this exploration was to see how viable it was to procedurally generate pathways and if it was even possible. With that goal in mind, I think this was a huge success 🎉</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dbf7d7fe4ace" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why GitHub notifications make it hard to get things done & how to fix it.]]></title>
            <link>https://medium.com/@nickzuber/why-github-notifications-make-it-hard-to-get-things-done-how-to-fix-it-be7cea936063?source=rss-2aa718162162------2</link>
            <guid isPermaLink="false">https://medium.com/p/be7cea936063</guid>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[notifications]]></category>
            <category><![CDATA[github]]></category>
            <dc:creator><![CDATA[Nick Zuber]]></dc:creator>
            <pubDate>Sun, 10 Feb 2019 21:39:35 GMT</pubDate>
            <atom:updated>2019-02-10T21:39:35.300Z</atom:updated>
            <content:encoded><![CDATA[<h4>Making your notifications smarter, powerful, and meaningful.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HwRl1AsOJFDblMKXbuQhgQ.jpeg" /></figure><p>If you’re anything like me, GitHub plays a pretty big role in the day-to-day work life. It’s where I host most of my code —both personal and professional —and where I collaborate with my team and peers on a variety of different projects.</p><p>An awesome benefit from having all of your work in a centralized area is that you can get every update for the different projects you’re working on all in one spot. The downside is that GitHub’s updates in particular <em>kind of </em>suck —which is annoying because they have <em>so</em> much potential to be good.</p><p>I crunched the numbers (math minor™ btw) and out of the hundreds to thousands of notifications I get each month, I only really cared about 15% of them. Which, again, kind of sucks.</p><h3>Trying to use “The Platform” and why it doesn’t work</h3><p>While there are a few popular ways to manage GitHub notifications, all of them feel incomplete. When I get a notification, there are three things that I want to know:</p><ul><li><strong>Why am I getting this</strong> — When I get a notification, I want to know what it’s for. Did someone comment on an issue? Was I assigned something?</li><li><strong>Do I care about this</strong> — I don’t want notifications for issues and pull requests that I’m not directly participating on. If I’m not involved, I probably have more important things to focus on.</li><li><strong>How urgent is this</strong> — When confronted with more than one notification, I want to know which one I should click on first.</li></ul><p>So with this in mind, let’s explore the different ways people try to solve these problems today.</p><h3>Using the participating tab</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OKrA7sz_757Z2rXrSIEx3Q.jpeg" /></figure><p>Within GitHub’s notifications tab, there’s a sub-tab titled “participating” — this is where you’ll find all the notifications that GitHub thinks is relevant to you.</p><p>This is pretty great, and also happens to be how I used to manage my notifications for the past year or so — but even then, this isn’t <em>nearly</em> good enough.</p><p>While this checks off the second item on my list, it doesn’t address the other two. Sure, I can see all the notifications that I care about, but I still don’t know <em>why</em> I care any of them, nor do I know how important each of them are to me.</p><p>Imagine if I had two notifications: one for a coworker commenting on an issue I opened, and another for somebody @mention’ing me for the 17th time on a pull request that’s assigned to me, has been open for two weeks, and requests my review (extreme example, but you get the point).</p><p>Without the notification telling me <em>why</em> I’m getting it, there’s no way for me to know these things without having to open each and every one and investigating myself. When there are only two notifications, that’s probably not a big deal, but what if I had ten? Twenty? 62 million? While this isn’t always a problem, this isn’t something I <em>want</em> to have to worry about; I want my most important notifications front and center.</p><p>The problems here might be acceptable to ignore on a small scale, but start throwing in a bit more activity and this approach quickly falls apart.</p><h3>Using email (ugh)</h3><p>Email is a pain to work with as it is, so right out the gate I don’t like this approach — but let’s give it a shot.</p><p>So with email, you have the ability to filter things, which is nice. This means with enough effort, you can set up a motley crew of different filters to remove any notifications which aren’t relevant to you.</p><p>Another added benefit to emails is that they can provide you with some context on what the notification is — like what somebody commented or if a pull request was merged, which is super cool and helpful.</p><p>I like this, it even checks off the first item on my list, but it feels really clunky and requires a lot of set up. It also doesn’t <em>really </em>say how important each notification is. While this approach definitely has value, it’s not enough for what I want.</p><h3>Using third party apps</h3><p>So, if this is such a big problem, then <em>surely</em> somebody must have invented a solution already, right? I’ll even take an overzealous NPM package at this point.</p><p>Luckily, it turns out there <em>kind of</em> is a solution out there — there’s this pretty cool web-app called <a href="https://octobox.io/">Octobox</a> which aims to turn your GitHub notifications into something like Gmail.</p><p>This is really interesting and a great tool and ends up checking off the first two items on my list (after you set up enough filters), but it doesn’t address the third.</p><p>Octobox is great at organizing all your notifications with filters (like email) and briefly telling you what the notification is for, but it doesn’t tell you how important it is. It makes sense when you think about it — this app isn’t really opinionated, which is totally <em>fine</em>, but just not what I want.</p><p>Plus, you need to set up a lot of integrations in each repository you want to track notifications for, which is especially a pain when you’re involved in some private organizations.</p><p>Also it costs money for private repositories, and who likes to spend money?</p><p>So Octobox turns out to be a pretty solid solution, but <em>still</em> doesn’t do everything that I want.</p><h3>Nothing works, so let’s make our own thing — Arriving on Meteorite</h3><figure><a href="https://xkcd.com/927/"><img alt="" src="https://cdn-images-1.medium.com/max/500/1*9nMBMt-OugnruBr_M-WuEQ.png" /></a><figcaption>Standards — <a href="https://xkcd.com/927/">https://xkcd.com/927/</a></figcaption></figure><p>At this point, I’m getting impatient and starting to lose hope that something actually exists out there.</p><p>So to recap, when I get a GitHub notification, I want to know these three things:</p><ul><li><strong>Why am I getting this</strong> — When I get a notification, I want to know what it’s for. Did someone comment on an issue? Was I assigned something?</li><li><strong>Do I care about this</strong> — I don’t want notifications for issues and pull requests that I’m not directly participating on. If I’m not involved, I probably have more important things to focus on.</li><li><strong>How urgent is this</strong> — When confronted with more than one notification, I want to know which one I should click on first.</li></ul><p>So after checking out all of the alternatives, I decided to just make the dream web-app that checks off everything on the list myself: introducing <a href="https://github.com/nickzuber/meteorite">Meteorite — Smarter GitHub notifications</a>.</p><p>I figured it should be straightforward enough — have a strategy for fetching and syncing notifications in real-time, filter out the non-important ones (keep things like where you’re assigned, mentioned, review requested, etc.), keep track of the notification thread history, and compute an importance score based on its activity.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JiXJ-E9wPnt_7_KlUQzxzw.png" /></figure><p>Meteorite is just an alternative to managing your GitHub notifications. It’s geared towards helping surface all of the notifications that are relevant and most important to you.</p><p>In a nutshell, the primary things it’ll do for you are:</p><ul><li>Sort and score your notifications based on their importance, so we can <strong>surface the most critical updates to the top</strong> of your queue.</li><li>Provide you with quick context for <strong>why</strong> you’re receiving each notification.</li><li>Allow you to opt in for <strong>desktop notifications whenever you receive important updates</strong> to help notify you right away.</li><li>Helps call out pull requests or issues <strong>that require your attention</strong>, like old PRs that require your review or really active threads.</li><li>Protect you from useless spammy notifications that you don’t care about.</li><li>Let you focus in on specific types of notifications that matter to you, like when your review is requested for a pull request or you were assigned an issue.</li><li>Shows you statistics that help you understand how you interact with notifications on a daily basis.</li></ul><p>This project is also totally decentralized — any and all heuristic information used to score and rank your notifications is stored locally on <em>your own</em> computer. No databases, no nonsense.</p><h3>Well, does it actually work?</h3><p>Everybody works a little differently, but for me at least, this project have been a life saver. I’ve been using Meteorite for the past few months at my job and have been absolutely loving it. It makes it so much easier to track my work and reviews across a variety of different projects and keep me organized.</p><p>This project is completely free and open sourced on <a href="https://github.com/nickzuber/meteorite">GitHub</a> with no installing of any kind of apps required. Feel free to <a href="https://github.com/nickzuber/meteorite/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc">check it out, submit requests, and/or contribute</a> if that’s your jam.</p><p>This project has been super helpful for me and I hope others might find it useful too!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=be7cea936063" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>