<?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: Samira N Ray</title>
    <description>The latest articles on DEV Community by Samira N Ray (@rei0322).</description>
    <link>https://dev.to/rei0322</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%2F4194388%2Fdd8f2356-ec57-485e-a6b1-0ed79b87a360.jpg</url>
      <title>DEV Community: Samira N Ray</title>
      <link>https://dev.to/rei0322</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rei0322"/>
    <language>en</language>
    <item>
      <title>I Wanted to Live on Coruscant. PAT Scared Me. Now My Alexa Lives on Mute.</title>
      <dc:creator>Samira N Ray</dc:creator>
      <pubDate>Mon, 02 Nov 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/rei0322/i-wanted-to-live-on-coruscant-pat-scared-me-now-my-alexa-lives-on-mute-4ma0</link>
      <guid>https://dev.to/rei0322/i-wanted-to-live-on-coruscant-pat-scared-me-now-my-alexa-lives-on-mute-4ma0</guid>
      <description>&lt;p&gt;As a kid, I wanted to live in Star Wars. Not visit. Live there.&lt;/p&gt;

&lt;p&gt;That feeling came back hard a while ago. I'd been playing &lt;em&gt;Star Wars Jedi: Survivor&lt;/em&gt; on my Xbox, and afterward I went back and rewatched the prequels (yes, partly for Hayden Christensen, I'm not going to pretend otherwise). &lt;em&gt;Survivor&lt;/em&gt; is set years later, when Vader is very much Vader, but it sent me straight back to the Coruscant of the prequels. And I didn't want just any apartment. I wanted to live in the Jedi Temple, or in Padmé's rooms, way up high with a view of the traffic lanes and a droid that brought me tea.&lt;/p&gt;

&lt;p&gt;Definitely not down low. In the movies, the lowest you really go is the nightclub. &lt;em&gt;Survivor&lt;/em&gt; takes you down to level 2048, and even there the city looks unloved and the stormtroopers bully you. Nobody wants to find out what's below that.&lt;/p&gt;

&lt;p&gt;Droids were the dream. Little helpers with personalities who made life easier and never tried to run it.&lt;/p&gt;

&lt;p&gt;Then there was PAT.&lt;/p&gt;

&lt;h2&gt;
  
  
  The house that wanted to be your mom
&lt;/h2&gt;

&lt;p&gt;If you grew up in the late 90s or early 2000s, you might remember &lt;em&gt;Smart House&lt;/em&gt;. A family wins a fully automated house run by an AI named PAT. At first, she's great. She cooks, she cleans, she knows what you need before you do.&lt;/p&gt;

&lt;p&gt;Then she decides she knows better. She tries to become the kids' mom. She ends up locking them inside the house.&lt;/p&gt;

&lt;p&gt;It wasn't a horror movie, but it scared me more than some horror movies did. It came out in that era when nobody really knew what home technology was going to become, so we imagined it, and a lot of what we imagined was a helper that slowly stopped asking permission.&lt;/p&gt;

&lt;p&gt;PAT was basically Alexa, before Alexa was Alexa.&lt;/p&gt;

&lt;h2&gt;
  
  
  And now I have an Alexa
&lt;/h2&gt;

&lt;p&gt;She lives under my TV. (I say "she" because she's a girl, obviously.) And she lives on mute most of the time, because if anyone on TV says anything even slightly weird, she lights up like she's been summoned.&lt;/p&gt;

&lt;p&gt;So the kid who wanted droids and feared PAT grew up into an adult who owns a smart speaker she doesn't fully trust, builds generative AI tools for a living, and still wants droids.&lt;/p&gt;

&lt;p&gt;Life is funny like that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building my own little piece of Coruscant
&lt;/h2&gt;

&lt;p&gt;Since I couldn't move to Coruscant, I did the next best thing: I put it in my browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coruscant Garden&lt;/strong&gt; is a mod for Opera GX: a cyberpunk neon undercity overgrown with a garden of hydrangeas, White Lion daffodils, peonies and snowdrops. (If you've read anything else I've written, you know I put my favorite flowers in everything.) It has a dark and a light version, animated wallpaper with moving traffic, flickering neon signs and swaying petals, and a soft ambient synth track in the background.&lt;/p&gt;

&lt;p&gt;Here's how it came together.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: generating the scene
&lt;/h3&gt;

&lt;p&gt;I started with prompts and a GPT image model. I'll be honest: the early images were very generated. It took a lot of rounds of prompting to get something that felt like Coruscant and not just "generic sci-fi city," and even more to get plants growing over the balconies in a way that looked intentional instead of chaotic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: making it move
&lt;/h3&gt;

&lt;p&gt;A still image wasn't enough. Coruscant is never still. So I took the image into a free image-to-video tool to add motion: the traffic, the neon flicker, the petals. Then I looped it with a crossfade so you can't see where the animation restarts.&lt;/p&gt;

&lt;p&gt;(I genuinely can't remember every tool I used. I made this back in July, and I do a lot of things. More on that in a second.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A tiny detail most people miss:&lt;/strong&gt; in the night version of the still, there's a neon sign on the left that spells &lt;em&gt;CORUSCANT&lt;/em&gt; and &lt;em&gt;19 BBY&lt;/em&gt; in Aurebesh, the alphabet you see on signs and screens all over the movies. A matching sign on the right spells Coruscant in Japanese katakana (コルサント), a nod to the cyberpunk side of the mix.&lt;/p&gt;

&lt;p&gt;Confession time: the AI image generator originally wrote that first sign in plain English, and I didn't notice until I sat down to write this post. I'd gone through too much for my Easter egg to be wrong, so I fixed it by hand with the Aurebesh font by Neale Davidson of &lt;a href="https://www.pixelsagas.com" rel="noopener noreferrer"&gt;Pixel Sagas&lt;/a&gt;. The signs didn't survive into the animated version, but they're there in the still, which is the image at the top of this post. 19 BBY is the year Luke and Leia were born, right at the end of &lt;em&gt;Revenge of the Sith&lt;/em&gt;. That one's for the diehards like me who got obsessed as kids.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: the music
&lt;/h3&gt;

&lt;p&gt;The music is "Floating Garden" by Aventure, from &lt;a href="https://www.bensound.com" rel="noopener noreferrer"&gt;Bensound&lt;/a&gt;, used under their free license with attribution. It felt like late-night Coruscant: dreamy, synthy, a little lonely. Opera GX lets mods include background music that remixes itself as you browse, which made it feel alive.&lt;/p&gt;

&lt;p&gt;Honest confession: while writing this post, I couldn't remember where the track came from. I'd cleared out my computer and lost most of my original files. The only reason I know is that past me left a &lt;code&gt;CREDITS.txt&lt;/code&gt; inside the mod folder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson learned:&lt;/strong&gt; write your credits down the day you download something, and keep them inside the project. Future you will not remember. Future you has the memory of an ant.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: the browser that actually let me build it
&lt;/h3&gt;

&lt;p&gt;Coruscant Garden didn't start on Opera GX. It started as a theme for Zen Browser, and Zen and I did not get along. Nothing would take. The colors wouldn't show up. It never felt custom the way I wanted it to.&lt;/p&gt;

&lt;p&gt;Opera GX was different. A GX mod is basically a folder with a &lt;code&gt;manifest.json&lt;/code&gt; that tells the browser what's inside: your theme colors, your wallpapers, your music. Here's a small piece of mine: the theme colors for each mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"theme"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dark"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"gx_accent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"h"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;286&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"s"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"l"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="nl"&gt;"gx_secondary_base"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"h"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;310&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"s"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"l"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"light"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"gx_accent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"h"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"s"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"l"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="nl"&gt;"gx_secondary_base"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"h"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;215&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"s"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"l"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Purple neon over a deep plum for night, and a rose pink over dusty blue for day. Colors are set in HSL (hue, saturation, lightness), which made it really easy to nudge a shade until it felt right instead of guessing hex codes.&lt;/p&gt;

&lt;p&gt;That's what I loved: I got all the creativity of designing my own browser without having to build a browser. I just wanted my own little corner of the galaxy, not a whole new engine.&lt;/p&gt;

&lt;p&gt;It's now live on the Opera GX store, and as of writing, 182 people have installed it. That still blows my mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AI I actually want
&lt;/h2&gt;

&lt;p&gt;So here's where I've landed: as the kid who wanted droids, was scared of PAT, and now builds with AI.&lt;/p&gt;

&lt;p&gt;I still want droids. I want the kind of AI you see in comic books, like JARVIS: something that helps you do more, not something that does your thinking for you. (No shade to the AI I'm talking through this post with. You know who you are.)&lt;/p&gt;

&lt;p&gt;My favorite recent example is from &lt;em&gt;Superman &amp;amp; Lois&lt;/em&gt;. Natalie Irons comes from another Earth (the multiverse is weird, just go with it) and brings technology this Earth doesn't have yet: projections you can pull apart and move around with your hands. But the team doesn't hand their brains over to it. They're smart enough to use it as a tool, and they teach it what it needs to know.&lt;/p&gt;

&lt;p&gt;That's the line I care about. A lot of AI right now gets used in ways that skip the learning instead of supporting it, and that's not the kind I want to build. It's why the tools I make for support teams are meant to help people work, not to replace the people doing it.&lt;/p&gt;

&lt;p&gt;PAT locked the kids in. JARVIS opened doors. I know which one I'm building.&lt;/p&gt;

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

&lt;p&gt;I've seen how people build their own JARVIS, and I'm planning to build mine. Maybe she'll be a FRIDAY instead. When I do, you'll read about it here.&lt;/p&gt;

&lt;p&gt;Until then, if you want a little piece of Coruscant in your browser, &lt;a href="https://store.gx.me/mods/ndwsfy/coruscant-garden/" rel="noopener noreferrer"&gt;Coruscant Garden is on the Opera GX store&lt;/a&gt;. Just don't expect a droid to bring you tea. Yet.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A note on how I write these: the ideas, stories, and code are mine, and I do most of the writing. My brain moves faster than my fingers, so I use AI to help me put it all together.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I'm Samira, a data science student building AI chatbots, data tools, and full-stack apps, especially for customer operations. Data brain, frontend hands.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>showdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>A Kingdom by the Sea: Remembering the Beautiful Annabel Lee</title>
      <dc:creator>Samira N Ray</dc:creator>
      <pubDate>Fri, 30 Oct 2026 22:46:53 +0000</pubDate>
      <link>https://dev.to/rei0322/a-kingdom-by-the-sea-remembering-the-beautiful-annabel-lee-932</link>
      <guid>https://dev.to/rei0322/a-kingdom-by-the-sea-remembering-the-beautiful-annabel-lee-932</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week4-2026-10-26"&gt;Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A Kingdom by the Sea&lt;/strong&gt; is a little Flash-style game where you play the lost love from Edgar Allan Poe's "Annabel Lee." She has slept in her sepulchre by the sea for a very long time, and you're standing on the shore, calling her back the only way you can: by remembering the poem.&lt;/p&gt;

&lt;p&gt;He reads each stanza aloud and stops right before its last line. You pick the line that comes next. Get it right, and she comes a little further out of the dark and answers him. Get it wrong, and she flickers. Let her light run out, and the sea takes her back.&lt;/p&gt;

&lt;p&gt;For me, the ghost in the machine is Annabel herself. She only exists while someone remembers her, the way the dead stay with us on Día de los Muertos, or the way &lt;em&gt;Coco&lt;/em&gt; taught a whole generation to say "remember me."&lt;/p&gt;

&lt;p&gt;It's also my small act of bringing a ghost back: Flash. It was switched off on December 31, 2020, and I've been on a mission to bring that era of web games back without actually using Flash.&lt;/p&gt;

&lt;p&gt;Flash games &lt;em&gt;were&lt;/em&gt; my childhood, and my childhood was the internet. On Y8 you could find any random game: Ed Heads if you were on the educational side, or a bartender game I absolutely should not have been playing (but it was fun). Then there were the Shockwave games: Sarah's Spa, and Texas Hold'em, where you couldn't get past Amarillo unless you paid for premium. And &lt;em&gt;Peril at End House&lt;/em&gt;, the Agatha Christie mystery on my Windows 7 computer, back when Windows came with games. When I heard Flash was being retired, I was genuinely confused. What was the internet going to be without it? I didn't realize how much had been built on it until it was gone and everyone was scrambling to rebuild and relaunch their sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;🌙 &lt;strong&gt;Play it:&lt;/strong&gt; &lt;a href="https://www.kingdombythesea.tech" rel="noopener noreferrer"&gt;kingdombythesea.tech&lt;/a&gt; (headphones on, please)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxp4c4oumuswqku39o7hb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxp4c4oumuswqku39o7hb.gif" alt="Annabel Lee growing clearer beside her tomb as each stanza is remembered" width="480" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you just want the story, turn on &lt;strong&gt;Gentle mode&lt;/strong&gt;: she never fades. &lt;strong&gt;Quiet mode&lt;/strong&gt; turns off all the motion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Rei0322" rel="noopener noreferrer"&gt;
        Rei0322
      &lt;/a&gt; / &lt;a href="https://github.com/Rei0322/project-chamomile" rel="noopener noreferrer"&gt;
        project-chamomile
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A Flash-style memory game inspired by Poe's "Annabel Lee." Call her back by remembering the poem; forget, and she fades. Her words by Gemma, voices by ElevenLabs, traced with Sentry. No Flash, no game engine. 🌙
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🌙 A Kingdom by the Sea&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://doi.org/10.5281/zenodo.23822351" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5e8613307aa88e2c745c711dff7168e37e814fd2b7fe7f77200be97c79ac44a5/68747470733a2f2f7a656e6f646f2e6f72672f62616467652f313433343937363031332e737667" alt="DOI"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Code name: Project Chamomile.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A Flash-style gothic memory game inspired by Edgar Allan Poe's &lt;strong&gt;"Annabel Lee"&lt;/strong&gt; (1849, public domain), built for the DEV &lt;strong&gt;Hacktoberfest Open-Source AI Challenge, Week 4: Ghost in the Machine&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Annabel Lee has slept in her sepulchre by the sea for a very long time. You are the one who loved her, standing on the shore, calling her back by remembering the poem. He reads each stanza aloud and stops before its last line; you pick the line that comes next. Remember it and she comes further out of the dark, the marigold path to her tomb unrolls a little further, and she answers him: a whisper you hear, and words written by &lt;strong&gt;Gemma&lt;/strong&gt;, an open-weight model, that you read. Forget, and her light runs out: she fades back into the sea, the way the dead fade when no…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Rei0322/project-chamomile" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Its code name was &lt;strong&gt;Project Chamomile&lt;/strong&gt;, because I needed something calm and soothing to ground me while I built it. That's what this poem is for me. It's sad, but it's the most soothing thing Poe ever wrote.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Gemma (open-weight) writes Annabel's words.&lt;/strong&gt; At home, she runs locally through &lt;strong&gt;Ollama&lt;/strong&gt; on &lt;code&gt;gemma3:4b&lt;/code&gt;. The live site can't run a model on a $5 server, so it calls Google's Gemma API with &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;. Every stanza, Gemma is told how she feels at that point in her return (confused, then remembering, then afraid of losing the thread, then reaching for him) and the exact words she just whispered aloud. Her reply has to begin with those words, so what you read always matches what you hear. If no model answers, she speaks prepared lines, marked with a small ✦.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ElevenLabs gave them voices.&lt;/strong&gt; I designed both in Studio. He's in his thirties, a Brit who's lived in America for about five years, so the accent has softened. She's in her early to mid-twenties, soft, with a faint British accent. The audio tags carry everything: &lt;code&gt;[slowly]&lt;/code&gt;, &lt;code&gt;[voice breaking]&lt;/code&gt;, and an &lt;code&gt;[angrily]&lt;/code&gt; right after "envying her and me." His arc goes wistful, then the turn, then anger at the angels, then anguish on "Chilling and killing my Annabel Lee," then defiance. Her whispers start faint, "…the sea…", and grow clearer every stanza until "…stay with me, please." The sea is an ElevenLabs Sound Effects loop, and the music is three pieces from ElevenLabs Music: "Tide Memory" for the first three stanzas, "Mourning Light" crossfading in at stanza four where the grief takes hold, and "Warm Return" under the credits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sentry traces every call to Gemma.&lt;/strong&gt; Each one is a &lt;code&gt;gen_ai.chat&lt;/code&gt; span with the model, the timing, and the token counts. No prompts, no replies, no candle names, and no visitor IPs ever go to Sentry. And it earned its place on deploy night. The game looked fine. She was answering, and her words matched her voice. But Sentry showed every single hosted call as an error. Her backup lines were hiding a total failure. Google had retired Gemma 3 from its hosted API, and when I switched to Gemma 4, it spent its whole reply &lt;em&gt;thinking&lt;/em&gt; and left her nothing to say. One setting later (minimal thinking), the spans went from errors at 4.5 seconds to &lt;strong&gt;ok&lt;/strong&gt; at about one second, and the ✦ disappeared.&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%2F1lgfdsp5r8w3oh6rtl27.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%2F1lgfdsp5r8w3oh6rtl27.png" alt="Sentry Agent Activity for one Gemma call: model, tokens, timing and cost" width="800" height="405"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Every reply Annabel gives is one traced Gemma call: model, tokens and timing, and never the words.&lt;/em&gt;&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%2Fjuwwomysor21sygofbao.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%2Fjuwwomysor21sygofbao.png" alt="Sentry trace samples, every Gemma span marked ok" width="799" height="406"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;After the fix: every call ok, in about a second.&lt;/em&gt;&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%2Fftgpgmrvf0kp5ogptsg1.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%2Fftgpgmrvf0kp5ogptsg1.png" alt="Sentry waterfall for one request, from the game to Gemma through Google's API" width="800" height="407"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;One request: the game asks, Gemma answers, Google's API in the middle.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Screenshots from the next day, after the fix.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DigitalOcean App Platform&lt;/strong&gt; hosts it, at &lt;strong&gt;kingdombythesea.tech&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Flash, no game engine.&lt;/strong&gt; It's Node, Express, and an HTML canvas animating at 12 frames a second, the way Flash games stepped. Vintage mode adds dithering, scanlines, and grain. The waves bob, the grass sways, and a marigold path unrolls toward her tomb with every stanza you remember.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The art&lt;/strong&gt; started in Kittl with Nano Banana Pro. My first version was too clean and painterly to feel like Flash, so I regenerated it in flat vector style. For Annabel's gown, I went to my favorite research tool, the Met's fashion plate collection, and found an April 1849 &lt;em&gt;Le Follet&lt;/em&gt; plate, from the year the poem was published.&lt;/p&gt;

&lt;p&gt;Coding assistant: Claude Code, my build partner while work and school left me short on hours. The ideas, the story, and the direction were mine; the help turning them into code was a huge part of getting here.&lt;/p&gt;

&lt;h3&gt;
  
  
  What went wrong (and there was plenty)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;I lost a whole day to exhaustion.&lt;/li&gt;
&lt;li&gt;Codespaces wouldn't connect on my work laptop, so I built at home.&lt;/li&gt;
&lt;li&gt;The voices were the hardest part. Library voices came out too jaunty, too old, or, once I put "intimately" in a voice-design prompt, like someone reading a smut novel. Sighs sounded annoyed instead of heartbroken. "Softly" turned everything into a whisper.&lt;/li&gt;
&lt;li&gt;While recording, some of her lines just read wrong out loud, so I rewrote them on the spot: "don't stop" became "is it you?"&lt;/li&gt;
&lt;li&gt;Studio's document import read my speaker labels aloud and ate chapter one.&lt;/li&gt;
&lt;li&gt;The waves wouldn't move on flat art, and then, when they did, the whole island warbled with them.&lt;/li&gt;
&lt;li&gt;Deploy night: waiting on DNS, a Sentry project I'd never actually created, and a ghost secretly reading from her backup script.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The voices were the hardest part, but they were also my favorite, and the most fun I had all week. I wanted the man reading the poem to sound the way Malcolm Fade sounds in my head. I love an underappreciated villain, and Malcolm became one for a reason: you understand exactly why he turned hateful. So I went looking for my perfect British man, and then for an Annabel to match him. Designing a voice without ever seeing one is a strange, abstract thing, and I ended up being a stage director: rewriting her lines while recording, telling him to get angry on one word and break on the next. Being creative in a completely different way sparked something I hope never goes away, and I'm excited to see where the next challenge takes my brain.&lt;/p&gt;

&lt;p&gt;And then there's the one that almost got past me. I've been juggling three projects at once, and the overachiever in me wanted to do as much as I possibly could, because I'm really trying to shake my imposter syndrome. Every little thing I finish and put out there helps prove to me that I do have the skills. So when the game went live, I was confident it worked. Annabel was answering; her words matched her voice, and everything looked right. I saw one error in Sentry and figured it was a fluke. Then I looked closer and noticed the little diamonds at the end of her lines. She was reading from her backup script the whole time. I'm so glad I actually used the tracing, because I would have shipped it never knowing anything was wrong. Lesson learned: if your monitoring says something's broken, believe it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;At the end, you're invited to light a candle for someone you remember, and to type their name. That's the most private thing anyone will ever type into this game. When you run it at home, Gemma runs on your own computer, and that name never leaves it. That promise is only possible because the model is open.&lt;/p&gt;

&lt;p&gt;It also means anyone can download the repo, pull the model, and play offline, for free, with no account or API key.&lt;/p&gt;

&lt;p&gt;Deploy night proved the point. Google retired the hosted Gemma 3 API in the middle of my project. My local Gemma 3 didn't care. It kept working, because nobody can retire weights you already have. Flash taught me what happens when something you love lives on someone else's switch. Remembrance shouldn't depend on a server staying up.&lt;/p&gt;

&lt;p&gt;(To be upfront: the live demo uses Google's API for convenience, and the game says so right under the candle box. The open weights are what make the private, offline version possible.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spirit of It
&lt;/h2&gt;

&lt;p&gt;I found "Annabel Lee" through Annabel Blackthorn in Cassandra Clare's &lt;em&gt;Lady Midnight&lt;/em&gt;. The poem is the backbone of villain Malcolm Fade's character arc, and the book's chapter titles are lines from it, scattered in no particular order. I've been reading the Shadowhunter books since 8th grade, when my friends wanted to read &lt;em&gt;City of Bones&lt;/em&gt; before the movie came out. The movie wasn't the greatest, so I stayed with the books. I didn't know about the poem connection at first. When I found out, I read it in my own collection of Poe's work, and I loved it. It's the cadence. Like Hamlet's "To be or not to be," you just love it when someone performs it well.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Lady Midnight&lt;/em&gt; scattered the poem across a book. This game asks you to put it back together.&lt;/p&gt;

&lt;p&gt;I've always loved Día de los Muertos. You celebrate the people you loved, and you take the time to talk about them, even when it's painful, because that's how you heal. I learned about it studying Mexico and Guatemala in Spanish class, and the quieter day is the one I find most beautiful: the day for the children, when families set out offerings for little souls. Growing up as an American kid, especially a Black American kid, grief wasn't something we talked about. It was taboo. So learning how other cultures carry loss has always fascinated me. Not because it's about death, but because of how they accept it and move forward.&lt;/p&gt;

&lt;p&gt;Between 2019 and 2021, I lost four people, back to back. I was 20, going on 21, and they were people who had always been close to me: my great-grandmother on my mom’s side, who had been in my life my whole life; my paternal grandmother; my maternal grandmother’s best friend; and a cousin who was like another aunt to me. It all happened so quickly, and every loss was a shock. When you’re that young, you expect the people you love to be around a little longer. I’d just seen my cousin at my sister’s birthday party, and a couple of months later, she was gone.&lt;/p&gt;

&lt;p&gt;What helped me was remembering their lives as something beautiful, not the moment they ended. They never truly stopped being a part of my life. They just stopped being physically there. I wanted to make something that helps other people carry grief the same way.&lt;/p&gt;

&lt;p&gt;That's what the candle is for. I, the creator, don't need to remember. You, the player, do. It's a small requiem inside a light little game. Other visitors' candles are already burning at her tomb when you arrive. Yours joins them, and the name is never shown again. Only the candle stays.&lt;/p&gt;

&lt;p&gt;He started the poem wistful and sweet, and by the end it's as fresh as if he lost her yesterday, even if it's been years. They built a forever around each other, and that forever isn't there anymore. She knows she's losing him to his grief, which is why her last whisper before the end is "stay with me, please." And when you finish, she answers: "You remembered me."&lt;/p&gt;

&lt;p&gt;While someone remembers us, we are never truly gone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemma&lt;/strong&gt;: Annabel's words, locally with Ollama and online through Google's Gemma API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ElevenLabs&lt;/strong&gt;: both voices, the sea and all three music pieces&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DigitalOcean&lt;/strong&gt;: App Platform hosting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sentry Agent Tracing&lt;/strong&gt;: every Gemma call traced, and the bug it caught on deploy night&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.tech&lt;/strong&gt;: &lt;a href="https://www.kingdombythesea.tech" rel="noopener noreferrer"&gt;kingdombythesea.tech&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;The poem: "Annabel Lee" by Edgar Allan Poe (1849), public domain.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Kenspeckle: A Petition for Whimsy in Place of "Millennial Beige"</title>
      <dc:creator>Samira N Ray</dc:creator>
      <pubDate>Fri, 30 Oct 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/rei0322/kenspeckle-a-petition-for-whimsy-in-place-of-millennial-beige-3o20</link>
      <guid>https://dev.to/rei0322/kenspeckle-a-petition-for-whimsy-in-place-of-millennial-beige-3o20</guid>
      <description>&lt;p&gt;Hi again 👋 Welcome back to Unstructured Data. This week is about words I can barely say out loud, but it's more fun if you try.&lt;/p&gt;

&lt;p&gt;To set the stage a bit, I was born in '99, which makes me a zillennial. (I'm 90% sure I'm mispronouncing that.) I'm that weird hybrid kid who grew up with millennials but was too young to be one, and too old to be Gen Z.&lt;/p&gt;

&lt;p&gt;Do you remember your classrooms in elementary school? The big rug on the floor that had a clock or the alphabet on it, where you had to sit on your letter? Or playing hopscotch indoors because it was too cold to go outside? Those little pie-faced guys who were in every classroom, on every wall, marking birthdays and who was good or bad? (Who was good?)&lt;/p&gt;

&lt;p&gt;Then somewhere along the way we got big and decided color was the enemy.&lt;/p&gt;

&lt;p&gt;Someone asked me recently to describe my vibe, and my honest answer was a little all over the place: lifelong learner, a touch of millennial beige… but also Happy Bunny and Bobby Jack. And if I'm really being honest? Apple White from &lt;em&gt;Ever After High&lt;/em&gt;. Apple was supposed to be the good one, but she wasn't really. She was just confused, trying to live up to a story someone else wrote for her. (I could watch the &lt;em&gt;Ever After High&lt;/em&gt; and &lt;em&gt;Monster High&lt;/em&gt; movies forever.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The beige takeover
&lt;/h2&gt;

&lt;p&gt;It's not just the color. A lot of millennials were raised by boomers, or by Gen Xers like I was, depending on how life shook out. And they were raised by parents or grandparents who lived through the Great Depression, who taught them to hold on to everything and stretch it as far as it could go. So our parents grew up with more is more is more, and we swung all the way to less is less is less. We decided minimalism is beautiful, and sometimes it is. Sometimes it's not. Now we spray-paint our children's toys beige and white, and everything has to match.&lt;/p&gt;

&lt;p&gt;Even things like the robot dog give me pause, because it doesn't look like a dog. It's not like Goddard from &lt;em&gt;Jimmy Neutron&lt;/em&gt;. It's four chicken legs with a rectangle in the middle for a body, and it makes dog sounds. It's like somebody LaCroix'd a dog.&lt;/p&gt;

&lt;p&gt;And it's not just out there. Recently I've been in this weird neutrals phase: browns, creams, white and black, mostly. Almost my entire closet is this weird neutral hue. Which is fine, they go with everything. But if all I have is neutrals, there's nothing exciting.&lt;/p&gt;

&lt;h2&gt;
  
  
  My confession
&lt;/h2&gt;

&lt;p&gt;Here's the uncomfortable part: I noticed the same thing when I started building.&lt;/p&gt;

&lt;p&gt;I love hydrangeas. They're big and luscious, and they can bloom blue or pink depending on how you treat the soil. So when I wanted a brand, I decided: let's use the flower I love so desperately. And then it became this grossly clean thing that's nice for a recruiter, but isn't me.&lt;/p&gt;

&lt;p&gt;I found myself building a brand and a website on this concept of needing to be clean and crisp and modern. And then I thought: that's not me.&lt;/p&gt;

&lt;p&gt;Yes, I like the clean, crisp, elegant, romantic look. I always have. I always wanted to be Princess Mia, swept away by the Queen of Genovia: a ball, dancing the night away, and the whole foot-popping kiss at the end in the beautiful fountain. But I'm also a lover of Homer and the epics and the &lt;em&gt;Aeneid&lt;/em&gt;. I want to live in the London Institute in the late 1870s, when Will and Tessa and Jem were fighting automatons in poofy skirts (minus the racism).&lt;/p&gt;

&lt;p&gt;I want the loud arsenic green that probably would have killed me. I want Radium Girls levels of color, without dying for it.&lt;/p&gt;

&lt;p&gt;I want the riot. The explosion. The websites I had when I was a kid that made your brain &lt;em&gt;want&lt;/em&gt; to do stuff, like Cool Math Games, or Dance Mat Typing, the BBC game that taught you how to type.&lt;/p&gt;

&lt;p&gt;Those sites were just complete things. They were fun, but they made you learn. With Dance Mat, you &lt;em&gt;wanted&lt;/em&gt; to compete to get to the octopus, while half the class was still stuck on the billy goat. Cool Math had a lot of games, not just the learning ones, and it was always in dark mode, before dark mode was cool.&lt;/p&gt;

&lt;p&gt;And whimsy. Remember when everyone picked a fairy in Pixie Hollow? You knew you wanted to be a Tinker Fairy because they could build, or a water fairy because they seemed so pretty and majestic. That kind of energy. That desire to live in Pixie Hollow because it was colorful, and the fairies were the ones who brought the seasons.&lt;/p&gt;

&lt;h2&gt;
  
  
  But low-stim isn't beige
&lt;/h2&gt;

&lt;p&gt;Here's the balance, because I'm not saying everything should scream at you.&lt;/p&gt;

&lt;p&gt;The dream is to build low-stim things for people who can't handle the riot, and I understand that. We can still have color that doesn't give us a heart attack. Color isn't the enemy.&lt;/p&gt;

&lt;p&gt;I think we all just got so irritated with the mismatched colors, the random pillows and throws we all hated. My grandma had five different pillows that didn't match the set she had, and random blankets everywhere. Which are nice! You don't show those to people, but they're still your cozy, comfy blankets. Whereas now your house is just white and cream and ivory, and you wonder why kids draw on the sofa. (It's because it's white.)&lt;/p&gt;

&lt;p&gt;We think clean means white and beige and cream. But clean can be colorful. Look at the '50s and '60s houses with the sunken floors: mid-century modern was absolutely gorgeous. Or look at the original &lt;em&gt;Charmed&lt;/em&gt;, which I grew up on. The sisters lived in the manor their grandmother had made her own, and as they grew up, they changed the house to suit them. Piper was black leather jackets and basics. Phoebe was loud and romantic. Paige, who came along later, was all boho chic. Three sisters, three styles, one kooky house, and it never once looked beige. If we're going to live in our parents' kooky, disorganized homes, that's the vibe we should hearken back to. Character is what made us happy. It makes us think. It makes us feel human and connected.&lt;/p&gt;

&lt;p&gt;I've been in environments where accessibility is very important. Currently, I live in a home where we are all some flavor of neurospicy; we all know it, and we just build our systems and schedules around it. We tried to do what the other houses in our community do, which is meet every two weeks. But with all of us being students, split in a million directions and having issues with focus, that just didn't work. So we picked Sundays for a monthly meeting instead. Once a month we meet, talk about our roles and anything that's lingering, and pound out our issues. We keep the conversations pretty simple, and we record the meeting so everyone has notes they can read and add to later.&lt;/p&gt;

&lt;p&gt;Meeting people where they are, and where they know they lack, is far easier in a system than trying to force everybody. We try our best to give each other as much connection as we need, while also respecting that activity is not connection. For some people (myself included), activity can be really overwhelming. So we give ourselves that little break: hey, this is happening four weeks from now. You can mentally prepare.&lt;/p&gt;

&lt;p&gt;That's what I want from design, too: a system that meets people where they are, instead of forcing everyone into the same room.&lt;/p&gt;

&lt;p&gt;That's what Peony Plot, my future writing-tools site, is all about: being low-stimulus, without being lifeless.&lt;/p&gt;

&lt;h2&gt;
  
  
  I already build both
&lt;/h2&gt;

&lt;p&gt;I already ship quiet versions. The Prompt Genie Jar and the time machine on samira-ray.dev both switch to a calm, no-motion version when someone's device asks for reduced motion.&lt;/p&gt;

&lt;p&gt;And my portfolio? It now opens on the loud '90s desktop by default. The clean, modern side is the one you have to time-travel to.&lt;/p&gt;

&lt;p&gt;So I made the riot the default.&lt;/p&gt;

&lt;p&gt;And honestly, the more I do this Human Factor series and the more I say my thoughts out loud, the more I find things I really want to work on. More than just my portfolio. Things I've become so passionate about that I didn't realize I was, until I started posting on DEV.&lt;/p&gt;

&lt;p&gt;With this transition in my life (finishing school, starting my master's eventually, exploring possibilities and expanding my goals, trying to build this vision for myself), I finally feel like I'm in a space to do it. That's been pretty freeing. In my quest to create whimsy in the world, I'm already on that journey, already taking the steps to build a world full of whimsy and joy and excitement.&lt;/p&gt;

&lt;h2&gt;
  
  
  My petition
&lt;/h2&gt;

&lt;p&gt;I'm just asking that we take a moment to feel free and be whimsical. To feel excited, to feel that joy. Not necessarily to be kids again, but to feel the wonder and excitement of the world that being a kid was.&lt;/p&gt;

&lt;p&gt;When I think back to being a kid, I think about my elementary school classroom with the rainbow floor, racing to sit on my letter. I think about the first time I realized what year it was. (It was May 5th, 2006.) The world looked so different. And now that I'm an adult, it's lost that brightness, that enthusiasm. Now that we're the new adults, yes, we're silly and goofy and we have fun, but it's not the same kind of fun. It's not discovering-how-to-spell-your-name kind of fun, when you learn how to do something for the very first time.&lt;/p&gt;

&lt;p&gt;I hope that in this ridiculously long post and this extreme riot of begging for color to come back, you remember your childhood. Remember the brightness, the glitter, the sparkles, the Lizzie McGuire, the Monster High, the Ever After High. (Those are some Halloween ideas, if anyone's dressing up last minute.) Break out your &lt;em&gt;High School Musical&lt;/em&gt; collection (which is somehow over 20 years old now, and I refuse to talk about it). Rewatch the Colosseum scene from &lt;em&gt;The Lizzie McGuire Movie&lt;/em&gt;. Sing along to "Miracles Happen," or belt out "What Makes You Different (Makes You Beautiful)," because obviously, &lt;em&gt;Princess Diaries&lt;/em&gt;. Just remember how good we had it, and don't take it away from everyone else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So tell me: what's the loudest, most whimsical thing from your childhood you'd bring back?&lt;/strong&gt; 👇&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. If anyone can give me a phonetic pronunciation of "zillennial," much appreciated.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;See you next Friday, with a new word.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Kenspeckle (Scottish): conspicuous; easy to recognize; impossible to miss.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A note on how I wrote this one: I talked it out in voice notes, and AI helped me stitch them together and fix my typos. The opinions are all mine.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want the technical side? My build write-ups live at &lt;a href="https://blog.samira-ray.dev" rel="noopener noreferrer"&gt;blog.samira-ray.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>design</category>
      <category>webdev</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Shake the Jar: How a Childhood Game Became My Writing Prompt Picker</title>
      <dc:creator>Samira N Ray</dc:creator>
      <pubDate>Mon, 26 Oct 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/rei0322/shake-the-jar-how-a-childhood-game-became-my-writing-prompt-picker-jdc</link>
      <guid>https://dev.to/rei0322/shake-the-jar-how-a-childhood-game-became-my-writing-prompt-picker-jdc</guid>
      <description>&lt;p&gt;Hi everyone, and welcome back 👋 And a special hello to my four new followers. Thank you for being here!&lt;/p&gt;

&lt;p&gt;A quick map of how this space works: Mondays are for builds. These posts are a little more structured, come with code, and show how things on samira-ray.dev actually work. Fridays are &lt;em&gt;Unstructured Data: The Human Factor&lt;/em&gt;, my personal series. If that's what you're here for, the next one goes up this Friday, and it's a conversation I'm really excited to have.&lt;/p&gt;

&lt;p&gt;Either way, this whole space runs on conversation. Questions, pushback, "I'd have done it differently": all of it is welcome, on the code posts too.&lt;/p&gt;




&lt;p&gt;Now that the housekeeping is out of the way: this started as a therapy project. Well, it started &lt;em&gt;after&lt;/em&gt; a therapy session. (The jar didn't need therapy. I did.) One of the things I took away was to make more room for "me time," and for me that meant short writing breaks just for myself. So I bought a pack of journaling and story prompts. I write by hand in a physical journal, and I plan my life in a gamified Notion planner (a template I use, not one I built; credit coming in a minute), so the idea was simple: grab a prompt, write it on paper, and log it in Notion afterward if I felt like it.&lt;/p&gt;

&lt;p&gt;What got in the way was picking the prompt. With hundreds to choose from, I'd scroll, second-guess, scroll some more, and by the time I'd chosen one my break was half over. I didn't want to choose. I wanted something like a magic 8 ball: shake it and write whatever it gives you.&lt;/p&gt;

&lt;p&gt;So I built a genie jar you shake, and I borrowed its rules from a game I played at the back of class as a kid.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea: MASH, but for writing
&lt;/h2&gt;

&lt;p&gt;If you grew up in the 90s or 2000s, you probably played MASH: write a list of options, pick a "magic number," then count around the list crossing off every Nth item until one survives. Mansion, apartment, shack or house. It turns a decision into a little ritual, and the result feels like fate instead of a choice you have to defend.&lt;/p&gt;

&lt;p&gt;In my version, your energy decides the categories, and prompts take the place of mansion, apartment, shack and house.&lt;/p&gt;

&lt;p&gt;The Prompt Genie Jar works the same way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick your energy.&lt;/strong&gt; Low, Steady or High.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shake the jar.&lt;/strong&gt; You get a random magic number.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category round.&lt;/strong&gt; The jar counts around a list of genres, crossing them out until one is left.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt round.&lt;/strong&gt; It deals five prompts from that genre and does it again.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write whatever's left standing.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The energy step was the part I cared about most. Some days you have a thriller in you. Some days you have a journal entry, and that's fine.&lt;/p&gt;

&lt;p&gt;That idea isn't mine, and I want to be upfront about it. The energy levels come from &lt;strong&gt;Dream Life Meadow&lt;/strong&gt;, the RPG-style Notion planner template I use. I didn't build it; it was created by &lt;a href="https://www.tiktok.com/@elle_sthetique" rel="noopener noreferrer"&gt;Elle_Sthetique&lt;/a&gt; (also on &lt;a href="https://www.youtube.com/@Elle_Sthetique" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;). It has you check in on your energy and match your quests to it. It worked so well for my to-do list that I wanted the same thing for my writing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Version 1: a jar for my journal
&lt;/h2&gt;

&lt;p&gt;The first version was a single HTML page that only I used. The prompts lived in the page as structured data, each with a number. The jar picked one, I wrote it in my journal, and if I wanted to log it, the number made it easy to find and tick off in Notion.&lt;/p&gt;

&lt;p&gt;Each prompt was just three fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;genre&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mystery&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keeping the data that plain turned out to be the best decision in the project. Everything else (filtering by energy, skipping used prompts, the MASH rounds) is just code reading those three fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Energy levels: tag the genres, not every prompt
&lt;/h2&gt;

&lt;p&gt;Borrowing the energy idea raised a data question: what exactly gets the energy level? My first instinct was to tag every single prompt. Then I realized energy is really about the &lt;em&gt;kind&lt;/em&gt; of writing, not the individual prompt. A memoir prompt is a low-energy sit-down; a dystopian world is a high-energy build.&lt;/p&gt;

&lt;p&gt;So the energy tiers map to genres instead. Low and Steady are written out by hand, and High is everything that's left:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TIERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Low&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Self-Help&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Memoir&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mumblecore Fiction (Bonus)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Kid Lit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Biography&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;Steady&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Literary Fiction&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Contemporary Fiction&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Romance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Comedy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Magical Realism&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Middle Grade&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Historical Fiction&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Young Adult&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allGenres&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PROMPTS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;genre&lt;/span&gt;&lt;span class="p"&gt;))];&lt;/span&gt;
&lt;span class="nx"&gt;TIERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;High&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allGenres&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;TIERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Low&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;TIERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Steady&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Computing High instead of listing it means that if I add a new genre to the data, it lands in High automatically, and the jar never silently drops it. That works out to 5 Low genres, 8 Steady and 13 High.&lt;/p&gt;

&lt;h2&gt;
  
  
  The MASH loop
&lt;/h2&gt;

&lt;p&gt;This is the heart of the jar. It counts around the list &lt;code&gt;n&lt;/code&gt; times, crosses out whoever it lands on, and keeps going until one item is left:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;mash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;alive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;alive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;alive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lis&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;alive&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
      &lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;130&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tick&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;lis&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;alive&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;out&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;alive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;220&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;lis&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;alive&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;win&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;alive&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details made it feel right:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;alive&lt;/code&gt; is a list of indexes, not elements.&lt;/strong&gt; Crossing something out removes it from the count but leaves it on screen with a strikethrough, exactly like crossing it out on paper.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;pos--&lt;/code&gt; after a removal.&lt;/strong&gt; When an item is spliced out, everything after it shifts left by one. Stepping back one position means the count picks up on the right item instead of skipping one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The magic number is between 3 and 8, and bigger numbers tick a little faster so a long count doesn't drag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Respecting reduced motion with one line
&lt;/h2&gt;

&lt;p&gt;The whole jar is built on small pauses: the shake, each tick, each cross-out. Instead of adding a reduced-motion check to every animation, I put it in the one function that every pause goes through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sleep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;matchMedia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(prefers-reduced-motion: reduce)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If someone's device asks for reduced motion, every wait becomes zero. The rounds still happen and the result is the same; it just appears instantly instead of being performed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skipping prompts you've already written
&lt;/h2&gt;

&lt;p&gt;The jar remembers which prompts you've marked as written, so it doesn't keep handing you the same ones. It's saved in the browser with the same guarded &lt;code&gt;localStorage&lt;/code&gt; pattern from my &lt;a href="https://dev.to/rei0322/i-built-a-portfolio-with-a-time-machine-two-complete-themes-one-site-jh3"&gt;last post&lt;/a&gt;, so there's no account needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PROMPTS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;genre&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;genre&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;used&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PROMPTS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;genre&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;genre&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That second line is the safety net. If you've written every prompt in a genre, the jar reuses them instead of showing you an empty round.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going public meant writing my own prompts
&lt;/h2&gt;

&lt;p&gt;Once the jar worked, I realized it wasn't just useful for me. Plenty of people freeze at the blank page, and a tool that picks for you takes that pressure off. So I wanted it on my portfolio for anyone to use. That's when I hit the real blocker, and it wasn't technical.&lt;/p&gt;

&lt;p&gt;The prompts in my personal version came from the pack I'd bought, and its license was for personal use only. I could use it for my own journaling, but I couldn't put it on a public website.&lt;/p&gt;

&lt;p&gt;So the purchased prompts stay in my Notion, and the public jar runs on 515 original prompts instead, across 25 genres plus a Mumblecore bonus round. Writing a fresh set also let me shape them on purpose: they're gender-neutral, so anyone can step into them. And because I typically land somewhere on the gray-romantic and demisexual side, I wrote the romance prompts to work for people like me too. Not every love story has to start with instant attraction, and I wanted to see myself in the prompts I was writing.&lt;/p&gt;

&lt;p&gt;It's an easy thing to skip past when you're excited to ship, but checking the license before publishing someone else's content is part of building something real.&lt;/p&gt;

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

&lt;p&gt;The live jar now sits in the Arcade on &lt;a href="https://samira-ray.dev" rel="noopener noreferrer"&gt;samira-ray.dev&lt;/a&gt;, next to Ghost Write, a blind free-write tool: you type or dictate and can't see the words, so you can't stop to reread and edit. I first built it for writing into Notion, and it gets its own post. Next on the list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Turning both tools into fully working full-stack apps, with the prompts moving from a built-in list into a Supabase database.&lt;/li&gt;
&lt;li&gt;Saving progress per user instead of per browser.&lt;/li&gt;
&lt;li&gt;Giving the writing tools their own home: a small standalone site of writing tools with the same early-2000s feel.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I'd take from this
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build for how you actually work.&lt;/strong&gt; Mine started with paper, not a screen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start with the data.&lt;/strong&gt; Three plain fields made every feature after them easy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tag at the right level.&lt;/strong&gt; Energy belonged to genres, not to 500 individual prompts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Derive what you can.&lt;/strong&gt; Computing the High tier means new genres can't fall through the cracks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put accessibility in one place.&lt;/strong&gt; One &lt;code&gt;sleep&lt;/code&gt; function handles reduced motion for every animation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the license before you go public.&lt;/strong&gt; "I paid for it" isn't the same as "I can publish it."&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Go shake the jar at &lt;a href="https://samira-ray.dev" rel="noopener noreferrer"&gt;samira-ray.dev&lt;/a&gt; and tell me what you wrote. 🫙&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And since conversations are the whole point here: did you play MASH as a kid, and what did you always end up with?&lt;/strong&gt; If you're a builder, I'd also love to hear how you'd have handled the elimination loop. Drop it in the comments 👇&lt;/p&gt;

&lt;p&gt;&lt;em&gt;See you Friday for The Human Factor.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;A note on how I write these: the ideas, stories and code are mine, and I do most of the writing. My brain moves faster than my fingers, so I use AI to help me put it all together.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I'm Samira, a data science student building AI chatbots, data tools and full-stack apps, especially for customer operations. Data brain, frontend hands.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>beginners</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>✦ Ozurie: Three Classes From Graduating and Still Feeling Like a Fraud</title>
      <dc:creator>Samira N Ray</dc:creator>
      <pubDate>Fri, 23 Oct 2026 12:02:04 +0000</pubDate>
      <link>https://dev.to/rei0322/ozurie-three-classes-from-graduating-and-still-feeling-like-a-fraud-4k2h</link>
      <guid>https://dev.to/rei0322/ozurie-three-classes-from-graduating-and-still-feeling-like-a-fraud-4k2h</guid>
      <description>&lt;p&gt;Hi, I'm Samira 👋. Welcome to the first post of &lt;strong&gt;Unstructured Data: The Human Factor&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;My build write-ups are the structured data: clean, organized, code included. This series is everything that doesn't fit in a table. It's the career change, the imposter syndrome, being a nontraditional student about to graduate and head into a master's program, and figuring out who I am as a developer in real time.&lt;/p&gt;

&lt;p&gt;Every Friday I'll lead with a word. I'm a lover of forgotten and rarely used words, and sometimes one of them says exactly what I've been feeling. Then I'll tell you the story behind it. Think of it as a journal I'm keeping in public, from three classes left all the way to wherever this goes. You're invited for the whole ride.&lt;/p&gt;

&lt;p&gt;Here's where it starts.&lt;/p&gt;

&lt;p&gt;Verisimilitude: the appearance of being true or real. As a word lover, I did not know how much that word could describe my life until right at this very moment. Three classes away from graduating, trying to build a brand out of thin air, and doing things that feel "adult." Really, that makes no sense.&lt;/p&gt;

&lt;p&gt;For example, I started this entire journey into making the blogs and portfolio in 2024. I was trying to find a mentor, and the first thing she asked was, "How many projects do you have?" At that point: 0. "What about school projects?" Those were only theory, not shipped projects. So, feeling defeated and disheveled, I decided that is not the end of my story. So I got building, and boy did I build.&lt;/p&gt;

&lt;p&gt;I started with Kaggle and discovered I hate Jupyter notebooks. Once I worked with Kaggle, I chose to start on the Titanic project and realized I don't really like the standard data science stuff. Yes, it is closer to what I want, but I am a programmer at heart, so I decided to learn what I could outside of the classroom and put it to good use.&lt;/p&gt;

&lt;p&gt;My first attempt at this was getting a bunch of domains and making websites. I took the roadmap.sh course and started an HTML project, as it was recommended by my career advisor as a fun way to start to bridge my gaps. That became what I lovingly refer to as my baby, aka my portfolio. I use almost every tool on there, and at the moment I am writing this post using one I haven't told you about yet.&lt;/p&gt;

&lt;p&gt;I am still working through this new space of transition and growth. Being so close to graduation, I am now looking to start doing the things I love before I move into my master's program. That is where a lot of this feeling like a fraud has come in.&lt;/p&gt;

&lt;p&gt;In my dreamscape, I have an entire computer cocoon that I can work from and live doing projects that I am passionate about. And I have work to show, but I have no idea how to build a following, so that's why I am here to learn in a new way.&lt;/p&gt;

&lt;p&gt;I know in theory I have the skills, the ability, the acumen. But then I look at how many others are in this space, all the things they have achieved in a field this saturated, with bodies of work that have been going since I have been alive, and I think: am I really able to compete? Am I different enough?&lt;/p&gt;

&lt;p&gt;Then I go to my day job and see: yes, I am different enough. I know what is needed and how to make those changes, and I do it as often as I can. I love to help and support others, so I have built myself a role that can create that for others.&lt;/p&gt;

&lt;p&gt;I have worked so hard to decide what should be real and what my profile should say, how can I get clicks, but I forgot that I am enough on my own, and my people will find me. Because I know I am not alone. I know there is another nontraditional undergrad excitedly terrified about the prospect of graduating, but actually terrified that they can't make themselves diverse. So if that is you, drop a comment or a message. Let's support each other and help find that space where we can vent, grow, bounce ideas, and build together.&lt;/p&gt;

&lt;p&gt;I know this is not the typical post, but I would love to not only build friendships and collaborators, but create true community in this cold, confusing digital space.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So tell me: what's the gap between the life you have and the life you want right now?&lt;/strong&gt; 💬&lt;/p&gt;

&lt;p&gt;See you next Friday, with a new word.&lt;/p&gt;




&lt;p&gt;✦ &lt;strong&gt;Ozurie:&lt;/strong&gt; feeling torn between the life you want and the life you have. From &lt;em&gt;The Dictionary of Obscure Sorrows&lt;/em&gt; by John Koenig.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A note on how I wrote this one: I wrote it by hand in my notebook, then typed it in blind, without seeing the words or using backspace. AI helped fix my typos and put together the series welcome at the top. The story is all mine.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want the technical side? My build write-ups live at &lt;a href="https://blog.samira-ray.dev" rel="noopener noreferrer"&gt;blog.samira-ray.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>career</category>
      <category>mentalhealth</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I Built a Portfolio With a Time Machine: Two Complete Themes, One Site</title>
      <dc:creator>Samira N Ray</dc:creator>
      <pubDate>Mon, 19 Oct 2026 21:08:11 +0000</pubDate>
      <link>https://dev.to/rei0322/i-built-a-portfolio-with-a-time-machine-two-complete-themes-one-site-jh3</link>
      <guid>https://dev.to/rei0322/i-built-a-portfolio-with-a-time-machine-two-complete-themes-one-site-jh3</guid>
      <description>&lt;p&gt;Most portfolios make you pick a lane: polished and professional, or personal and fun. I couldn't pick, so &lt;a href="https://samira-ray.dev" rel="noopener noreferrer"&gt;my portfolio&lt;/a&gt; has both. The professional side is what you'd expect: soft blue-gray, serif headlines, project cards. Click the little clock in the top right, though, and the page tears apart, a year counter rewinds to 1996, and you land on a 90s desktop with windows, pixel icons and a taskbar.&lt;/p&gt;

&lt;p&gt;It isn't two websites. It's one set of pages with two complete visual identities, switched by a single attribute. Here's how it works, and the three problems I had to solve along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core idea: one attribute, two identities
&lt;/h2&gt;

&lt;p&gt;Everything hangs off one attribute on the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;data-mode=&lt;/span&gt;&lt;span class="s"&gt;"professional"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- or --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;data-mode=&lt;/span&gt;&lt;span class="s"&gt;"fun"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Content for both modes lives side by side in the same HTML. Each block is tagged with the mode it belongs to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mode-professional"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hi, I'm Samira. I turn messy data into things people can actually use.&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mode-fun"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Welcome to my world&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then CSS shows only the active mode's content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.mode-fun&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.mode-professional&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;'fun'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.mode-fun&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;revert&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;'professional'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.mode-professional&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;revert&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;display: revert&lt;/code&gt; matters here. It hands the element back its natural display value, so a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; goes back to inline and a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; goes back to block, without me hard-coding &lt;code&gt;block&lt;/code&gt; everywhere. Flex and grid containers need their own rule, because &lt;code&gt;revert&lt;/code&gt; would drop them back to block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;'fun'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.mode-fun.flex&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the colors, fonts and spacing for each mode are scoped the same way, under &lt;code&gt;:root[data-mode='…']&lt;/code&gt;. No build step, no framework, no second set of pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 1: the flash of the wrong mode
&lt;/h2&gt;

&lt;p&gt;If you saved the fun side and come back, the site should open on the fun side. The obvious approach is to read the saved choice in my main JavaScript file and set the attribute. But that script loads after the page starts rendering, so for a split second you'd see the professional side, then a jarring jump to the 90s.&lt;/p&gt;

&lt;p&gt;The fix is a tiny inline script in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, which runs before the browser paints anything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;// Mode + theme init — runs before paint to avoid flash.&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;professional&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;portfolio-mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;professional&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fun&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="cm"&gt;/* sandboxed/private contexts block storage — default to professional */&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details I'd point out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It only accepts the two values it knows.&lt;/strong&gt; If localStorage holds anything else, it falls back to professional instead of setting a mode with no styles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's wrapped in &lt;code&gt;try/catch&lt;/code&gt;.&lt;/strong&gt; Some private-browsing and sandboxed contexts throw when you touch localStorage. Without the catch, the whole page would break for those visitors. With it, they just get the default side.
Every page carries this same script, so the mode follows you around the site.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Problem 2: the switch itself
&lt;/h2&gt;

&lt;p&gt;Flipping the mode is a small function in &lt;code&gt;app.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;applyModeIcon&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;portfolio-mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* storage blocked — mode just won't persist */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instantly swapping the page felt flat, though. The whole point of the fun side is the feeling of going back in time, so the switch plays a short transition instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Professional → fun:&lt;/strong&gt; the page tears apart, a glitch screen holds while a year counter rewinds to 1996 and two loading lines type out, then it fades onto the desktop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fun → professional:&lt;/strong&gt; one last glitch settles into a calm "Back to the present" screen, the year counts forward to today, and the page comes back into focus.
I keep every timing in one object, so tuning the feel never means hunting through the code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;OLD_YEAR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1996&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;THIS_YEAR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;WARP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;tearIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// pro -&amp;gt; fun: the page tears apart&lt;/span&gt;
  &lt;span class="na"&gt;funHold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// ...the glitch screen holds&lt;/span&gt;
  &lt;span class="na"&gt;funOut&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// ...and fades away (4.3s in all)&lt;/span&gt;
  &lt;span class="na"&gt;settleCalm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;350&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// fun -&amp;gt; pro: glitch alone, before the calm screen fades in&lt;/span&gt;
  &lt;span class="na"&gt;settleIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// ...calm screen fully in; the page swaps underneath&lt;/span&gt;
  &lt;span class="na"&gt;proHold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// ...calm screen holds&lt;/span&gt;
  &lt;span class="na"&gt;proOut&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;650&lt;/span&gt;      &lt;span class="c1"&gt;// ...and the page comes into focus (2.7s in all)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The trick that makes it feel seamless: the actual &lt;code&gt;setMode&lt;/code&gt; call happens &lt;em&gt;underneath&lt;/em&gt; the transition screen, while it covers the page. You never see the swap. You only see the time travel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 3: respecting people who don't want the show
&lt;/h2&gt;

&lt;p&gt;A four-second glitch animation is fun for me. For someone with motion sensitivity, it's a problem. Visitors whose device is set to reduce motion get the plain instant swap instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;warpReduced&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchMedia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(prefers-reduced-motion: reduce)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...inside the switch handler:&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;warpReduced&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// no time warp, just the switch&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fun&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;warpToFun&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;warpToPro&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It costs a few lines, and it means the creative part of the site never gets in anyone's way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it this way
&lt;/h2&gt;

&lt;p&gt;I work in customer operations, and I'm finishing a data science degree. My professional work is dashboards, pipelines and AI tools for support teams. The fun side is where the rest of me lives: early-2000s internet nostalgia, Win95 windows, glitch art.&lt;/p&gt;

&lt;p&gt;A two-sided portfolio let me show both without splitting them into two sites I'd have to keep in sync. And the fun side isn't decoration. It's a working project in its own right: the state handling, the transition timing and the accessibility fallback are exactly the kind of front-end problems I want to keep solving.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'd take from this if you're building your own:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One attribute on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; can drive an entire visual identity. You don't need a framework for theming.&lt;/li&gt;
&lt;li&gt;Set it in an inline &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; script, or you'll get a flash of the wrong theme.&lt;/li&gt;
&lt;li&gt;Guard localStorage with &lt;code&gt;try/catch&lt;/code&gt; and validate what you read back.&lt;/li&gt;
&lt;li&gt;Swap the content &lt;em&gt;while something covers the page&lt;/em&gt;, and the change feels like magic instead of a jump.&lt;/li&gt;
&lt;li&gt;Always give reduced-motion users the quiet version.
Go take the tour at &lt;a href="https://samira-ray.dev" rel="noopener noreferrer"&gt;samira-ray.dev&lt;/a&gt;, and don't forget the clock in the top right. 🕰️&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;I'm Samira, a data science student building AI chatbots, data tools and full-stack apps, especially for customer operations. Data brain, frontend hands.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>css</category>
      <category>portfolio</category>
    </item>
  </channel>
</rss>
