<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Seongjin Kang</title>
    <description>The latest articles on DEV Community by Seongjin Kang (@seongjinkang).</description>
    <link>https://dev.to/seongjinkang</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4080765%2F058ffba3-4b54-4897-a201-2455f449404c.png</url>
      <title>DEV Community: Seongjin Kang</title>
      <link>https://dev.to/seongjinkang</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/seongjinkang"/>
    <language>en</language>
    <item>
      <title>I mapped how 241 anonymous users moved between rooms — a live "collective thought map"</title>
      <dc:creator>Seongjin Kang</dc:creator>
      <pubDate>Sun, 23 Aug 2026 15:48:50 +0000</pubDate>
      <link>https://dev.to/seongjinkang/i-mapped-how-241-anonymous-users-moved-between-rooms-a-live-collective-thought-map-56ld</link>
      <guid>https://dev.to/seongjinkang/i-mapped-how-241-anonymous-users-moved-between-rooms-a-live-collective-thought-map-56ld</guid>
      <description>&lt;p&gt;A few weeks ago I wrote about &lt;a href="https://dev.to/seongjinkang/i-built-a-forum-where-rooms-die-when-people-stop-talking-30mc"&gt;building a forum where rooms die when people stop talking&lt;/a&gt;. The other half of that idea: there are no profiles — the rooms you pass through draw a map that becomes your identity.&lt;/p&gt;

&lt;p&gt;So what does that look like for &lt;em&gt;everyone at once&lt;/em&gt;? I layered every room-to-room move real users made in the last 30 days into one map. It's live and zoomable: &lt;strong&gt;&lt;a href="https://noding.app/map?lang=en" rel="noopener noreferrer"&gt;https://noding.app/map?lang=en&lt;/a&gt;&lt;/strong&gt; (refreshes every 5 minutes).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz91vdo0z3kvtkt31qzwl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz91vdo0z3kvtkt31qzwl.png" alt="Collective thought map — 241 people, 111 rooms, 131 moves" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How it's built
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data&lt;/strong&gt;: a &lt;code&gt;Transition&lt;/code&gt; collection (from room → to room) aggregated by edge. Re-entering the same room, lingering, and leaving to the plaza don't count as paths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Excluded&lt;/strong&gt;: seeded persona accounts, staff accounts, bots, and flagged/hidden rooms. Personas are denormalized as &lt;code&gt;isSeed&lt;/code&gt; on each transition, so they drop out with one &lt;code&gt;$match&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rendering&lt;/strong&gt;: no libraries — a hand-rolled canvas force layout. Lesson learned: cap the repulsion force and the per-step velocity, or a couple of nodes get flung to infinity and your "fit to view" collapses the rest into a corner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progressive labels&lt;/strong&gt;: each room gets a zoom threshold by visit rank, so names fade in as you zoom (capped at 2.6×). Particles flow along edges in the direction of the move.&lt;/li&gt;
&lt;li&gt;One aggregation service feeds both the internal (authenticated) diagnostic endpoint and the public (trimmed, 5-min cached) one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it shows (after exclusions: 241 people · 111 rooms · 131 moves)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;People entered rooms &lt;strong&gt;669&lt;/strong&gt; times straight from the plaza, but moved room-to-room only &lt;strong&gt;131&lt;/strong&gt; times. Four visits out of five end in the first room. If "your path is your identity" is going to work, getting people to a &lt;em&gt;second&lt;/em&gt; room is the bottleneck — the map made that obvious.&lt;/li&gt;
&lt;li&gt;The hub is &lt;code&gt;프로그래밍&lt;/code&gt; (programming) — the first stop for a wave of visitors from a Korean tech news site — with the thickest flow going on to &lt;code&gt;llm&lt;/code&gt; → &lt;code&gt;LLM의 한계&lt;/code&gt; ("limits of LLMs").&lt;/li&gt;
&lt;li&gt;Only &lt;strong&gt;6 of 126 edges&lt;/strong&gt; were walked in the same direction by 2+ people. Everything else is a path one person took. "Meeting people who walked the same path" is still a hypothesis.&lt;/li&gt;
&lt;li&gt;Korean and English rooms barely mix (5 crossings).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;The map now lives on the landing page, and each person's own map is shown under &lt;em&gt;My&lt;/em&gt;. I also started surfacing "people who passed through X went on to Y next" from the collective data as a first, very thin "next room" forecast. Whether that sharpens as the map grows is the next thing to measure.&lt;/p&gt;

&lt;p&gt;If you've built graph visualizations for small-but-growing datasets, I'd love to hear what you'd do differently.&lt;/p&gt;

</description>
      <category>datavisualization</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>community</category>
    </item>
    <item>
      <title>I built a forum where rooms die when people stop talking</title>
      <dc:creator>Seongjin Kang</dc:creator>
      <pubDate>Mon, 17 Aug 2026 02:32:27 +0000</pubDate>
      <link>https://dev.to/seongjinkang/i-built-a-forum-where-rooms-die-when-people-stop-talking-30mc</link>
      <guid>https://dev.to/seongjinkang/i-built-a-forum-where-rooms-die-when-people-stop-talking-30mc</guid>
      <description>&lt;p&gt;I got tired of two things about online communities.&lt;/p&gt;

&lt;p&gt;The first is that they don't die well. A subreddit or a Discord channel that was alive for a week keeps existing for years, and the emptiness is louder than silence — you open it, see the last post is from 2023, and leave. The second is that everything you say is pinned to a permanent profile. Even on "anonymous" apps, you accumulate a history, and the history becomes a reason not to say the true thing.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Noding&lt;/strong&gt;: an anonymous forum where any word becomes a room, and rooms decay when people stop talking.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two rules
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A word is a room.&lt;/strong&gt; You type "late night thoughts" or "career anxiety" or "NBA" — if a room exists, you're in it; if not, it exists now. No creation form, no moderator to petition. The search box &lt;em&gt;is&lt;/em&gt; the create button.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rooms decay.&lt;/strong&gt; Every room has an activity score. It gets bumped by visits and posts, and it decays with a 24-hour half-life when nothing happens. &lt;code&gt;active → warning → dormant → gone from the plaza&lt;/code&gt;. If someone opens a dormant room again, it comes back with its history intact — the room only &lt;em&gt;disappears from view&lt;/em&gt;, it doesn't get deleted. So the plaza always shows what's alive right now, and nothing has to be pruned by hand.&lt;/p&gt;

&lt;p&gt;The identity part fell out of these two rules. If there are no profiles, what tells people apart? I ended up using the one thing that's already there: &lt;strong&gt;the path&lt;/strong&gt;. The rooms you pass through, and the order you pass through them, draw a small graph. That graph is rendered as a mark next to your posts. Tap someone's mark and you see the rooms you've &lt;em&gt;both&lt;/em&gt; been in — and nothing else. Their rooms you haven't visited stay blurred. It's the only social feature in the app, and it's asymmetric on purpose: it reveals overlap, never the other person's full history.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it's built
&lt;/h2&gt;

&lt;p&gt;Nothing exotic. TypeScript, Express, Socket.IO, MongoDB. React Native (Expo) for the iOS app, and the same codebase exported to web so it works in a browser without installing anything.&lt;/p&gt;

&lt;p&gt;A few pieces that turned out to matter more than I expected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The decay scheduler.&lt;/strong&gt; A cron every 15 minutes recomputes &lt;code&gt;nodeActivity&lt;/code&gt; for every room and moves rooms across lifecycle stages. The half-life is a constant; tuning it is the single most important product decision in the app, and it's one number.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Path as data.&lt;/strong&gt; Every move between rooms is logged as a weighted edge (&lt;code&gt;from → to&lt;/code&gt;, with dwell time). The user's identity mark is literally a rendering of that edge list. It also gives me a "people who walked a similar path" signal for recommendations, without ever asking anyone what they like.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Room similarity.&lt;/strong&gt; Room titles are embedded and stored in Pinecone, so "late night thoughts" and "3am thoughts" know they're neighbors. This is what makes the search-box-as-create-button not fragment into a thousand near-duplicate rooms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Moderation before publish.&lt;/strong&gt; Three layers on every post before anyone sees it: a pattern list, fuzzy matching against it, then an LLM pass. Anonymous &lt;em&gt;and&lt;/em&gt; unmoderated is a bad combination; anonymous and moderated is fine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No account before consent.&lt;/strong&gt; A small thing that bit me: the web app used to open a socket (and create a user) as soon as it booted, before the person had agreed to anything. Every crawler that rendered a shared link created a ghost user. Now nothing exists until someone taps "agree." Consent first, account second.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What happened when real people came
&lt;/h2&gt;

&lt;p&gt;It's been running in Korea for a few months. The rooms people make there are mostly what I hoped for: venting about work, reactions to whatever happened today, "anyone else up at 2am."&lt;/p&gt;

&lt;p&gt;Two numbers I keep coming back to. First: people who visit &lt;strong&gt;six or more rooms&lt;/strong&gt; in their first session come back at a completely different rate than people who visit fewer. Depth on day one is almost the whole story. Second: the best users I've gotten so far didn't come from launches — they came from search. Someone typed a worry into Google, landed in a room, made their own room, and wrote the thing they couldn't say elsewhere.&lt;/p&gt;

&lt;p&gt;I opened the English side of Noding this week. It's quiet — a handful of rooms, a few dozen posts — but alive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The question I actually want answered
&lt;/h2&gt;

&lt;p&gt;Does "rooms that die" feel right to you, or unsettling? And does path-as-identity read as privacy, or as &lt;em&gt;nothing to hold onto&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;If you want to poke at it, it runs in the browser with no signup: &lt;a href="https://noding.app/en?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=story" rel="noopener noreferrer"&gt;noding.app/en&lt;/a&gt;. I'm the only person building it, so I'll read everything.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>showdev</category>
      <category>sideprojects</category>
      <category>node</category>
    </item>
  </channel>
</rss>
