<?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: Minh Long</title>
    <description>The latest articles on DEV Community by Minh Long (@minhlong2605).</description>
    <link>https://dev.clauneck.workers.dev/minhlong2605</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%2F2947620%2Fcc910ef2-20bd-4bcb-8926-fe665ea5584d.png</url>
      <title>DEV Community: Minh Long</title>
      <link>https://dev.clauneck.workers.dev/minhlong2605</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.clauneck.workers.dev/feed/minhlong2605"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Minh Long</dc:creator>
      <pubDate>Mon, 15 Jun 2026 15:23:57 +0000</pubDate>
      <link>https://dev.clauneck.workers.dev/minhlong2605/-h2k</link>
      <guid>https://dev.clauneck.workers.dev/minhlong2605/-h2k</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/solstice-shift-time-reshape-the-world-june-solstice-game-jam-entry-36bl" class="crayons-story__hidden-navigation-link"&gt;🏃 SOLSTICE: Shift Time, Reshape the World (June Solstice Game Jam Entry)&lt;/a&gt;
    &lt;div class="crayons-article__cover crayons-article__cover__image__feed"&gt;
      &lt;iframe src="https://www.youtube.com/embed/u7lJvqdN9Y8" title="🏃 SOLSTICE: Shift Time, Reshape the World (June Solstice Game Jam Entry)"&gt;&lt;/iframe&gt;
    &lt;/div&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/solstice-shift-time-reshape-the-world-june-solstice-game-jam-entry-36bl" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;June Solstice Game Jam Submission&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/minhlong2605" class="crayons-avatar  crayons-avatar--l  "&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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2947620%2Fcc910ef2-20bd-4bcb-8926-fe665ea5584d.png" alt="minhlong2605 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/minhlong2605" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Minh Long
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Minh Long
                
              
              &lt;div id="story-author-preview-content-3899725" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/minhlong2605" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2947620%2Fcc910ef2-20bd-4bcb-8926-fe665ea5584d.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Minh Long&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/solstice-shift-time-reshape-the-world-june-solstice-game-jam-entry-36bl" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 14&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/solstice-shift-time-reshape-the-world-june-solstice-game-jam-entry-36bl" id="article-link-3899725"&gt;
          🏃 SOLSTICE: Shift Time, Reshape the World (June Solstice Game Jam Entry)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/gamechallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;gamechallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/gamedev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;gamedev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/solstice-shift-time-reshape-the-world-june-solstice-game-jam-entry-36bl" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;17&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/solstice-shift-time-reshape-the-world-june-solstice-game-jam-entry-36bl#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              3&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>🏃 SOLSTICE: Shift Time, Reshape the World (June Solstice Game Jam Entry)</title>
      <dc:creator>Minh Long</dc:creator>
      <pubDate>Sun, 14 Jun 2026 16:04:50 +0000</pubDate>
      <link>https://dev.clauneck.workers.dev/minhlong2605/solstice-shift-time-reshape-the-world-june-solstice-game-jam-entry-36bl</link>
      <guid>https://dev.clauneck.workers.dev/minhlong2605/solstice-shift-time-reshape-the-world-june-solstice-game-jam-entry-36bl</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.clauneck.workers.dev/challenges/june-game-jam-2026-06-03"&gt;June Solstice Game Jam&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This project was built with Google Gemini throughout: game code, level design, debugging, and this writeup. I directed the concept, reviewed output, and iterated until it played fair; Gemini did the heavy lifting on implementation and polish.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;SOLSTICE&lt;/strong&gt; is a browser puzzle platformer about the moment the year stops turning.&lt;/p&gt;

&lt;p&gt;You play as the Sunkeeper. The longest day has frozen halfway between dawn and dusk. The only way forward is to &lt;strong&gt;shift time&lt;/strong&gt; between Day and Night. That is not a visual filter. It rewires the level. Sun blocks hold you up in daylight and vanish at night. Moon blocks are ghost platforms until you flip to darkness. Water kills you under the sun and becomes walkable ice when the stars come out.&lt;/p&gt;

&lt;p&gt;The campaign is five levels that teach the rules one beat at a time, ending at the great Solstice Shrine. After that you can drop into &lt;strong&gt;Endless Mode&lt;/strong&gt;, where the game keeps serving new realms forever.&lt;/p&gt;

&lt;p&gt;I built it for the solstice theme on purpose. Light and dark are not just palette swaps here. They are the puzzle. Every jump, every collectible, the exit asks you to read the world twice and pick the right phase of time.&lt;/p&gt;

&lt;p&gt;You can try it inline below. &lt;strong&gt;For the best experience, play the standalone web version.&lt;/strong&gt; Keyboard focus, audio, and the Gemini AI settings panel all behave more reliably outside the embed.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/longphanquangminh/embed/YPNGYXZ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Play it now (recommended):&lt;/strong&gt; &lt;a href="https://longphanquangminh.github.io/SOLSTICE-jump/" rel="noopener noreferrer"&gt;https://longphanquangminh.github.io/SOLSTICE-jump/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No install. Click once on the canvas if the keyboard feels dead, then go.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick reference
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tile&lt;/th&gt;
&lt;th&gt;Day&lt;/th&gt;
&lt;th&gt;Night&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;S&lt;/code&gt; Sun block&lt;/td&gt;
&lt;td&gt;Solid&lt;/td&gt;
&lt;td&gt;Vanishes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;M&lt;/code&gt; Moon block&lt;/td&gt;
&lt;td&gt;Invisible&lt;/td&gt;
&lt;td&gt;Solid (shift to reveal stairs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;W&lt;/code&gt; Water / Ice&lt;/td&gt;
&lt;td&gt;Deadly water&lt;/td&gt;
&lt;td&gt;Walkable ice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;#&lt;/code&gt; Stone&lt;/td&gt;
&lt;td&gt;Solid&lt;/td&gt;
&lt;td&gt;Solid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;^&lt;/code&gt; Spikes&lt;/td&gt;
&lt;td&gt;Deadly&lt;/td&gt;
&lt;td&gt;Deadly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;o&lt;/code&gt; Sun mote&lt;/td&gt;
&lt;td&gt;Collect&lt;/td&gt;
&lt;td&gt;Collect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;E&lt;/code&gt; Solstice Shrine&lt;/td&gt;
&lt;td&gt;Exit&lt;/td&gt;
&lt;td&gt;Exit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Controls:&lt;/strong&gt; &lt;code&gt;←/→&lt;/code&gt; or &lt;code&gt;A/D&lt;/code&gt; to move · &lt;code&gt;Space&lt;/code&gt;/&lt;code&gt;W&lt;/code&gt; to jump · &lt;code&gt;Shift&lt;/code&gt;/&lt;code&gt;J&lt;/code&gt;/&lt;code&gt;F&lt;/code&gt; to flip time · &lt;code&gt;Enter&lt;/code&gt; to start · &lt;code&gt;E&lt;/code&gt; for Endless Mode from the title screen · &lt;code&gt;R&lt;/code&gt; to restart · &lt;code&gt;M&lt;/code&gt; to mute&lt;/p&gt;




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

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/u7lJvqdN9Y8"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;▶ &lt;strong&gt;Direct link:&lt;/strong&gt; &lt;a href="https://www.youtube.com/watch?v=u7lJvqdN9Y8" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=u7lJvqdN9Y8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The clip walks through the core loop: run, jump, collect sun motes, hit &lt;strong&gt;Shift&lt;/strong&gt; to flip the world, reach the Shrine. You will see the gold day palette snap into indigo night, moon stairs appearing out of nowhere, and a frozen river turning from hazard into a bridge.&lt;/p&gt;

&lt;p&gt;Raw capture in the repo: &lt;a href="https://github.com/longphanquangminh/SOLSTICE-jump/blob/main/jump.wmv" rel="noopener noreferrer"&gt;&lt;code&gt;jump.wmv&lt;/code&gt;&lt;/a&gt;&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/longphanquangminh" rel="noopener noreferrer"&gt;
        longphanquangminh
      &lt;/a&gt; / &lt;a href="https://github.com/longphanquangminh/SOLSTICE-jump" rel="noopener noreferrer"&gt;
        SOLSTICE-jump
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;SOLSTICE — A Game of Light &amp;amp; Time&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Play now:&lt;/strong&gt; &lt;a href="https://longphanquangminh.github.io/SOLSTICE-jump/" rel="nofollow noopener noreferrer"&gt;https://longphanquangminh.github.io/SOLSTICE-jump/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A browser-based 2D puzzle-platformer built for the &lt;strong&gt;&lt;a href="https://dev.clauneck.workers.dev/challenges/june-2026-solstice" rel="nofollow"&gt;DEV June Solstice Game Jam 2026&lt;/a&gt;&lt;/strong&gt;. You are the &lt;strong&gt;Sunkeeper&lt;/strong&gt;. On the longest day of the year, time has stalled between day and night. Use &lt;strong&gt;SHIFT TIME&lt;/strong&gt; (Day ↔ Night) to reshape the world, collect sun motes, and light the &lt;strong&gt;Solstice Shrines&lt;/strong&gt; to restore the cycle.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Demo&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=u7lJvqdN9Y8" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4af5ee2583cbf8612935d692643ec0a1048389bb65c947cd3aa61b0aeb9ce4a9/68747470733a2f2f696d672e796f75747562652e636f6d2f76692f75376c4a7671644e3959382f6d617872657364656661756c742e6a7067" alt="Watch SOLSTICE gameplay on YouTube"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;▶ &lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=u7lJvqdN9Y8" rel="nofollow noopener noreferrer"&gt;YouTube — SOLSTICE gameplay&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Original video file in the repo: &lt;a href="https://github.com/longphanquangminh/SOLSTICE-jump/jump.wmv" rel="noopener noreferrer"&gt;&lt;code&gt;jump.wmv&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How to Play&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Press &lt;strong&gt;SHIFT&lt;/strong&gt; to flip time — the physical world changes with the light/dark phase:&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tile&lt;/th&gt;
&lt;th&gt;Day&lt;/th&gt;
&lt;th&gt;Night&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;S&lt;/code&gt; Sun-block&lt;/td&gt;
&lt;td&gt;Solid&lt;/td&gt;
&lt;td&gt;Vanishes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;M&lt;/code&gt; Moon-block&lt;/td&gt;
&lt;td&gt;Invisible / not standable&lt;/td&gt;
&lt;td&gt;Solid (hidden stairs — SHIFT to reveal)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;W&lt;/code&gt; Water / Ice&lt;/td&gt;
&lt;td&gt;Deadly water&lt;/td&gt;
&lt;td&gt;Walkable ice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;#&lt;/code&gt; Stone&lt;/td&gt;
&lt;td&gt;Solid in both phases&lt;/td&gt;
&lt;td&gt;Solid in both phases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;^&lt;/code&gt; Spikes&lt;/td&gt;
&lt;td&gt;Always deadly&lt;/td&gt;
&lt;td&gt;Always deadly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;o&lt;/code&gt; Sun mote&lt;/td&gt;
&lt;td&gt;Collectible&lt;/td&gt;
&lt;td&gt;Collectible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;E&lt;/code&gt; Solstice Shrine&lt;/td&gt;
&lt;td&gt;Level exit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/longphanquangminh/SOLSTICE-jump" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/longphanquangminh/SOLSTICE-jump" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/SOLSTICE-jump&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole game lives in a single &lt;a href="https://github.com/longphanquangminh/SOLSTICE-jump/blob/main/index.html" rel="noopener noreferrer"&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;/a&gt;. Canvas 2D, fixed timestep physics, tile maps, WebAudio synth, the Gemini client, and the level validator all ship in one file so GitHub Pages can host it with zero build step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SOLSTICE-jump/
├── index.html      # The entire game (HTML + CSS + JS)
├── jump.wmv        # Gameplay demo video
├── README.md
└── working-doc.md  # Dev notes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;I started with one question: what if changing time changed &lt;em&gt;geometry&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;From there I worked iteratively with Gemini: describing mechanics, getting code back, playtesting, and sending fixes until the game felt right. Levels are ASCII grids. &lt;code&gt;#&lt;/code&gt; is stone. &lt;code&gt;S&lt;/code&gt; and &lt;code&gt;M&lt;/code&gt; are phase locked blocks. &lt;code&gt;W&lt;/code&gt; is water or ice depending on the sky. &lt;code&gt;o&lt;/code&gt; is a sun mote. &lt;code&gt;E&lt;/code&gt; is the Shrine. The parser pads uneven rows so a sloppy AI row never crashes the game.&lt;/p&gt;

&lt;h3&gt;
  
  
  Physics and feel
&lt;/h3&gt;

&lt;p&gt;Movement uses coyote time and jump buffering because platformers live or die on forgiveness. Shifting phases runs through a trap check first. If the new phase would crush the player inside solid tile, the shift is denied with a little shake and a sour note. You are never soft locked by your own power.&lt;/p&gt;

&lt;h3&gt;
  
  
  Proving levels are fair
&lt;/h3&gt;

&lt;p&gt;Early playtests caught a nasty bug: motes floating four tiles in the air when the jump apex only reaches about two. That felt like a secret rule instead of a skill check. With Gemini I rebuilt placement around three reachable patterns: a short hop, a climbable staircase, or a moon stair you only see after shifting to night.&lt;/p&gt;

&lt;p&gt;Then we added a phase aware reachability search (BFS) that understands walk, step up, jump arcs, falls, and day/night toggles. Every campaign level, every sample realm, and every runtime Gemini output gets filtered through it before you play. If the Shrine is unreachable, the level is rejected. If a mote is unreachable, it gets stripped so 100% collection stays honest.&lt;/p&gt;

&lt;p&gt;A greedy hold jump bot was also run against the campaign until it cleared all five levels including the finale. That caught missing player spawn markers and floating steps that looked cool but broke progression.&lt;/p&gt;

&lt;h3&gt;
  
  
  Campaign levels
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;I · First Light&lt;/strong&gt; · learn SHIFT and the moon bridge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;II · Meltwater&lt;/strong&gt; · deadly water by day, frozen ice by night&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;III · Twilight Rhythm&lt;/strong&gt; · alternating sun stone and moon stone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IV · Frostfall&lt;/strong&gt; · every mechanic combined&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;V · The Longest Day&lt;/strong&gt; · the finale; light the great Shrine&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Beating the campaign unlocks &lt;strong&gt;Endless Solstice&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Gemini was used to build the game
&lt;/h3&gt;

&lt;p&gt;Gemini was not a one off feature bolted on at the end. It was the main development partner.&lt;/p&gt;

&lt;p&gt;For the &lt;strong&gt;codebase&lt;/strong&gt;, I described systems in plain language (physics, tile parsing, phase shift, WebAudio, UI) and iterated with Gemini until everything landed in one self contained &lt;code&gt;index.html&lt;/code&gt;. Bug fixes, the reachability validator, the verification bot, and the Endless Mode pipeline all went through the same loop: prompt, generate, test, refine.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;campaign and sample levels&lt;/strong&gt;, Gemini helped draft and revise ASCII maps against the jump limits and tile rules. I still validated every map with the in game BFS before shipping, which is how unreachable motes and missing spawn points got caught.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;this post&lt;/strong&gt;, Gemini helped structure and polish the writeup so judges could actually follow the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Gemini shows up inside the game
&lt;/h3&gt;

&lt;p&gt;This is the second layer, and the one judges can play with directly.&lt;/p&gt;

&lt;p&gt;Endless Mode uses a pluggable &lt;strong&gt;LevelManager&lt;/strong&gt; with a clear fallback chain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ask &lt;strong&gt;Google Gemini&lt;/strong&gt; to invent a brand new map at runtime (if the player enabled AI and supplied their own API key via the &lt;strong&gt;✦ AI&lt;/strong&gt; panel)&lt;/li&gt;
&lt;li&gt;Pull from a shuffled pool of eight verified sample realms from the build&lt;/li&gt;
&lt;li&gt;Echo a random known realm so loading never dead ends&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So Gemini shows up twice: once as the dev tool that built SOLSTICE, and once as a live level designer players can turn on in Endless Mode.&lt;/p&gt;

&lt;p&gt;The runtime path sends a detailed level design brief: tile legend, jump limits (about two tiles up, three across), staircase rules, mote counts, and a full JSON example of a real solvable level from the game. The model must answer with structured JSON via &lt;code&gt;responseSchema&lt;/code&gt;, matching fields like &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;sub&lt;/code&gt;, &lt;code&gt;tip&lt;/code&gt;, &lt;code&gt;startDay&lt;/code&gt;, and &lt;code&gt;rows&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Implementation details judges might care about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The client tries the official &lt;code&gt;@google/genai&lt;/code&gt; SDK with streaming first, then falls back to raw REST if the CDN is blocked&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AbortController&lt;/code&gt; plus a 30 second timeout so a slow network never freezes the run&lt;/li&gt;
&lt;li&gt;API keys live in &lt;code&gt;localStorage&lt;/code&gt; on the player's machine only. No key? Endless Mode still works on the built in pool. Runtime AI is a bonus layer, not a paywall&lt;/li&gt;
&lt;li&gt;Every generated map passes the same reachability validator as campaign content before it hits the canvas&lt;/li&gt;
&lt;li&gt;The HUD shows where the current realm came from (&lt;code&gt;Gemini AI&lt;/code&gt;, &lt;code&gt;Sample realm&lt;/code&gt;, or &lt;code&gt;Echo&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gemini is not generating flavor text off to the side. At build time it helped write the game. At runtime it can dream up the next lawful puzzle inside rules strict enough to reject bad output automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Polish
&lt;/h3&gt;

&lt;p&gt;Visuals are all procedural: gold sun motes, indigo night sky, star fields, phase crossfades, particle bursts on shift and collect. Audio is tiny synthesized bleeps so the file stays portable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prize Category
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Best Google AI Usage
&lt;/h3&gt;

&lt;p&gt;This category fits SOLSTICE on two levels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build time:&lt;/strong&gt; Gemini helped write the full game: physics, rendering, audio, level data, the reachability validator, and the Endless Mode pipeline. I steered the design and kept iterating until every campaign level was provably solvable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime:&lt;/strong&gt; Gemini is embedded in the playable product. Endless Mode can call the same model live to invent new maps, with structured JSON output, streaming, graceful fallback, and the same validator that rejects unfair levels.&lt;/p&gt;

&lt;p&gt;That is end to end Google AI usage: from jam concept to shippable code to a feature players can switch on with their own API key.&lt;/p&gt;

&lt;p&gt;Players opt in through the in game &lt;strong&gt;✦ AI&lt;/strong&gt; settings panel. The game never blocks if they skip runtime generation. Built in sample realms and echo fallback keep Endless Mode running either way.&lt;/p&gt;

&lt;p&gt;I am not submitting for &lt;strong&gt;Best Ode to Alan Turing&lt;/strong&gt; this round. The theme here is solstice light and the turning of time rather than computing history.&lt;/p&gt;




&lt;p&gt;Thanks for reading. If you try Endless Mode with Gemini enabled, tell me the weirdest lawful realm it conjured. I am curious which shift puzzle it thinks is clever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Play (recommended): &lt;a href="https://longphanquangminh.github.io/SOLSTICE-jump/" rel="noopener noreferrer"&gt;https://longphanquangminh.github.io/SOLSTICE-jump/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CodePen: &lt;a href="https://codepen.io/longphanquangminh/pen/YPNGYXZ" rel="noopener noreferrer"&gt;https://codepen.io/longphanquangminh/pen/YPNGYXZ&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/longphanquangminh/SOLSTICE-jump" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/SOLSTICE-jump&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Demo: &lt;a href="https://www.youtube.com/watch?v=u7lJvqdN9Y8" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=u7lJvqdN9Y8&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Jam: &lt;a href="https://dev.clauneck.workers.dev/challenges/june-game-jam-2026-06-03"&gt;https://dev.clauneck.workers.dev/challenges/june-game-jam-2026-06-03&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>gamechallenge</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>🕹️ SOLSTICE: Hold the Light Until Dawn - A 3D Browser Game for the June Solstice Jam</title>
      <dc:creator>Minh Long</dc:creator>
      <pubDate>Sun, 14 Jun 2026 15:42:11 +0000</pubDate>
      <link>https://dev.clauneck.workers.dev/minhlong2605/solstice-hold-the-light-until-dawn-a-3d-browser-game-for-the-june-solstice-jam-3340</link>
      <guid>https://dev.clauneck.workers.dev/minhlong2605/solstice-hold-the-light-until-dawn-a-3d-browser-game-for-the-june-solstice-jam-3340</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.clauneck.workers.dev/challenges/june-game-jam-2026-06-03"&gt;June Solstice Game Jam&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2Ffjcfu665kpk04z1lzp9t.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.amazonaws.com%2Fuploads%2Farticles%2Ffjcfu665kpk04z1lzp9t.png" alt="Demo" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the June solstice the sun stays up longer than any other day of the year. Then it sets anyway. &lt;strong&gt;SOLSTICE&lt;/strong&gt; is what happens after that: the longest night, one stone ring, and you holding the last flame.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://longphanquangminh.github.io/sunbearer/" rel="noopener noreferrer"&gt;Play SOLSTICE&lt;/a&gt;&lt;/strong&gt; · no install, runs in the browser&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;SOLSTICE&lt;/strong&gt; is a 3D action survival game where daylight is not background flavor. It is the mechanic.&lt;/p&gt;

&lt;p&gt;You are the &lt;strong&gt;Sunbearer&lt;/strong&gt;, keeper of an ancient ring of standing stones. When the solstice sun goes down, shadow creatures crawl out to snuff your flame. You fight back with a glowing blade, dash through dark bolts, and vacuum up the light they drop when they break apart.&lt;/p&gt;

&lt;p&gt;The whole run hangs on two meters:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Light&lt;/strong&gt; is your health, your urgency, and your fuel. It ticks down over time and falls hard when something hits you. Let it hit zero and the night wins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dawn&lt;/strong&gt; is how close you are to sunrise. It climbs as you survive and as you kill. Fill it to 100% and the sky actually changes: the solstice sun crests the stones, the shadows burn off, you win.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your light is your life, your weapon, and the clock. When it runs out, the night wins.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I built this for the jam theme on purpose. Light, darkness, and time are not three separate ideas in the UI. They are one loop you feel in your hands: &lt;strong&gt;slash, dodge, collect, survive&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The arena is Stonehenge inspired. The real monument lines up with the solstice sunrise, so defending that ring felt right. The toughest wave and the &lt;strong&gt;Warden of the Long Night&lt;/strong&gt; boss show up late, right before first light. Darkest before dawn is not just flavor text here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Controls&lt;/strong&gt; (laptop friendly, no gamepad needed):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;W&lt;/code&gt; &lt;code&gt;A&lt;/code&gt; &lt;code&gt;S&lt;/code&gt; &lt;code&gt;D&lt;/code&gt; or arrow keys&lt;/td&gt;
&lt;td&gt;Move&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Space&lt;/code&gt; or left click&lt;/td&gt;
&lt;td&gt;Light Slash&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Shift&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dash with brief invulnerability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Solar Flare, charged AoE ultimate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Esc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pause&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three difficulties on the start screen: &lt;strong&gt;Acolyte&lt;/strong&gt; (gentler), &lt;strong&gt;Sunbearer&lt;/strong&gt; (default), &lt;strong&gt;Eclipse&lt;/strong&gt; (two bosses, meaner spawns). You can swap difficulty from pause or the end screen if a run feels wrong.&lt;/p&gt;




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

&lt;p&gt;Full run below: sunset, the swarm, the Warden, and the dawn break.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/1WjNur7JzXk"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Playable build (single HTML file). You can try the CodePen embed below, but &lt;strong&gt;the web link is the best way to play&lt;/strong&gt;: fullscreen, proper keyboard focus, and fewer iframe limits.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/longphanquangminh/embed/myRrpyw?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Play here (recommended):&lt;/strong&gt; &lt;strong&gt;&lt;a href="https://longphanquangminh.github.io/sunbearer/" rel="noopener noreferrer"&gt;https://longphanquangminh.github.io/sunbearer/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




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

&lt;p&gt;Whole game lives in one file. Repo:&lt;/p&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/longphanquangminh" rel="noopener noreferrer"&gt;
        longphanquangminh
      &lt;/a&gt; / &lt;a href="https://github.com/longphanquangminh/sunbearer" rel="noopener noreferrer"&gt;
        sunbearer
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;SOLSTICE — Hold the Light&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A browser-based 3D action-survival game built for the &lt;strong&gt;DEV June Solstice Game Jam (2026)&lt;/strong&gt;. You are the &lt;strong&gt;Sunbearer&lt;/strong&gt;, last keeper of an ancient stone ring. As the solstice sun sets, shadow creatures pour from the dark — your &lt;strong&gt;Light&lt;/strong&gt; is your health, your weapon fuel, and the clock. Survive the longest night and reach dawn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://longphanquangminh.github.io/sunbearer/" rel="nofollow noopener noreferrer"&gt;Play now&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=1WjNur7JzXk" rel="nofollow noopener noreferrer"&gt;Demo video&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The hook&lt;/h2&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Your light is your life, your weapon, and the clock. When it runs out, the night wins.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Light&lt;/strong&gt; drains over time and drops fast when enemies hit you. Slay shadows to collect light fragments and stay alive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dawn&lt;/strong&gt; fills as you survive. Hit 100% and the solstice sun crests the horizon — you win.&lt;/li&gt;
&lt;li&gt;The sky, fog, sun, and stars &lt;strong&gt;repaint in real time&lt;/strong&gt; from sunset through midnight to golden dawn.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Controls&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;W&lt;/code&gt; &lt;code&gt;A&lt;/code&gt; &lt;code&gt;S&lt;/code&gt; &lt;code&gt;D&lt;/code&gt; / Arrow keys&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/longphanquangminh/sunbearer" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Clone and serve locally if you want to poke around (needs HTTP, not &lt;code&gt;file://&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/longphanquangminh/sunbearer.git
&lt;span class="nb"&gt;cd &lt;/span&gt;sunbearer
npx serve &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;I gave myself a hard constraint: &lt;strong&gt;one self contained HTML file&lt;/strong&gt;, no bundler, no downloaded assets, host it anywhere. Open the page, play. That shaped every decision after it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack in short:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Three.js r160 over WebGL, loaded with a native &lt;code&gt;importmap&lt;/code&gt; from jsDelivr&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UnrealBloomPass&lt;/code&gt; for glow on the blade, orbs, and dawn light&lt;/li&gt;
&lt;li&gt;Web Audio only: every sound is synthesized at runtime, zero audio files&lt;/li&gt;
&lt;li&gt;Procedural canvas textures for the ground and particles&lt;/li&gt;
&lt;li&gt;No external models or image assets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three.js comes in clean with an import map, no build step:&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 &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"importmap"&lt;/span&gt;&lt;span class="nt"&gt;&amp;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;imports&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;three&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;https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js&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;three/addons/&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;https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Postprocessing loads dynamically inside &lt;code&gt;try/catch&lt;/code&gt;. If bloom fails on a weird GPU, the game still renders instead of dying on a black screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  The sky is the progress bar
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Dawn&lt;/strong&gt; meter does more than fill a UI bar. One value, &lt;code&gt;dawn&lt;/code&gt; from 0 to 1, drives keyframe blending across sky color, fog, sun angle and intensity, ambient light, hemisphere light, and star opacity. You start at hot sunset, sink into violet dusk and deep midnight, then break into gold when you win. You can read how close sunrise is by looking up, not only by checking HUD numbers.&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;SKY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="c1"&gt;// p,    sky,      fog,      sun,    sunInt, amb, hemi, stars&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xE8743B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x6e3a2e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xffb060&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0c1230&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0a1026&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x6a78c0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;1.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xFFC56B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x9a6a3e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xffe0a0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateDay&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;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dawn&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;dawnMax&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SKY&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;scene&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;background&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lerpColors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sky&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sky&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lerpColors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nb"&gt;sun&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intensity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lerp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sunInt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sunInt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lerp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&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;h3&gt;
  
  
  Combat and waves
&lt;/h3&gt;

&lt;p&gt;Melee uses arc hit detection: range plus facing angle, knockback, combo multiplier on chained kills. Enemies are shades, fast wisps, ranged casters that make you move, and the Warden boss on a wave director that ramps up over the night.&lt;/p&gt;

&lt;p&gt;Difficulty is a thin multiplier layer at run start: enemy HP, damage, speed, spawn rate, light drain, dawn duration, orb drops, enemy cap. Three distinct feels from one codebase without forking logic everywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance on a laptop
&lt;/h3&gt;

&lt;p&gt;Capped device pixel ratio, recycled sprite particle pool, blob shadows on most things with one real shadow casting sun, hard enemy cap. It should stay smooth on a normal laptop without asking for a gaming rig.&lt;/p&gt;

&lt;h3&gt;
  
  
  The design change that actually mattered
&lt;/h3&gt;

&lt;p&gt;Early builds had separate HP and a survival timer. Too noisy. Merging them into &lt;strong&gt;Light&lt;/strong&gt; made every choice sharper: dash away and let the meter tick, or push in for fragments that refill you. Tuning that drain vs reward loop took the most iteration, which is why I added selectable difficulty instead of pretending one balance fits everyone.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prize Category
&lt;/h2&gt;

&lt;p&gt;Submitting for &lt;strong&gt;Best Google AI Usage&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google Gemini&lt;/strong&gt; helped across the whole project, not just this writeup. I used it to generate and iterate on the game code (Three.js setup, combat, wave logic, sky pipeline, Web Audio synthesis), debug issues, and tune balance. I also used it to draft and polish this DEV submission so the theme and technical choices are easy to follow.&lt;/p&gt;

&lt;p&gt;My role was directing the design (light as health, solstice theme, single file constraint), reviewing what Gemini produced, playtesting, and cutting or fixing what did not feel right in actual runs. The final game is a back and forth between my intent and Gemini's output, not something I typed out line by line solo.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This project used &lt;strong&gt;Google Gemini&lt;/strong&gt; for both game development and this blog post. I am noting that openly for transparency and because it fits the jam's Google AI prize category.&lt;/p&gt;




&lt;p&gt;Hold the light until dawn. 🌅&lt;/p&gt;

&lt;p&gt;If you try it, I would love your high score and honest feedback in the comments. Happy solstice, whichever hemisphere you are in.&lt;/p&gt;

&lt;p&gt;Fancy formatted version of this writeup: &lt;a href="https://longphanquangminh.github.io/sunbearer/post" rel="noopener noreferrer"&gt;longphanquangminh.github.io/sunbearer/post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#DEVChallenge&lt;/code&gt; &lt;code&gt;#gamedev&lt;/code&gt; &lt;code&gt;#javascript&lt;/code&gt; &lt;code&gt;#threejs&lt;/code&gt; &lt;code&gt;#webgl&lt;/code&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>gamechallenge</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>🧩LOGIC SOLSTICE CIPHER - A Code-Breaking Ode to Alan Turing</title>
      <dc:creator>Minh Long</dc:creator>
      <pubDate>Tue, 09 Jun 2026 16:48:18 +0000</pubDate>
      <link>https://dev.clauneck.workers.dev/minhlong2605/solstice-cipher-a-code-breaking-ode-to-alan-turing-44f2</link>
      <guid>https://dev.clauneck.workers.dev/minhlong2605/solstice-cipher-a-code-breaking-ode-to-alan-turing-44f2</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.clauneck.workers.dev/challenges/june-game-jam-2026-06-03"&gt;June Solstice Game Jam&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A quick note on AI:&lt;/strong&gt; I used an Gemini while making this. It helped me shape the idea, write the code, and put together a first draft of this post. I read through everything, made my own edits, and did the testing and the deploy myself.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;SOLSTICE CIPHER is a small code breaking game about beating the sunset on the longest day of the year.&lt;/p&gt;

&lt;p&gt;Here is the setup. You are standing at an observatory on June 21. A scrambled signal of colored light keeps pulsing over the horizon, six colors of the spectrum locked in some hidden order, and you have to figure out that order before the sun goes down. Every guess you make costs you an hour of daylight. The sun drops a little lower, the sky slides from midday blue into orange and then deep night, and the stars start coming out. Burn through all your daylight and you lose.&lt;/p&gt;

&lt;p&gt;The part that tells you how close each guess was is not a plain hint box. I named it The Bombe, after the machine Alan Turing built to crack Enigma. If you get stuck, you can spend a Bombe Assist and let it work out one position for you.&lt;/p&gt;

&lt;p&gt;🎮 &lt;strong&gt;Play it now (nothing to install, runs in the browser):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/editor/longphanquangminh/embed/019ead2e-19d4-767f-9418-5bfc71a2a6b1?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Heads up: CodePen does not load on every network. If it will not open for you, try a different network or a VPN, or just use the full screen version below.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Full screen:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://longphanquangminh.github.io/solstice-cipher/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;longphanquangminh.github.io&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;It is built to be played on a laptop keyboard, so you can run the whole thing with the arrow keys and the number row. There are on screen buttons too if you are on your phone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What I was going for was something you can understand in about five seconds but that still makes you think. I also wanted the June theme to live in how the game actually plays, instead of being pasted on top of something unrelated.&lt;/p&gt;

&lt;p&gt;A few ways it ties back to the theme:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;☀️ &lt;strong&gt;The solstice and the passage of time.&lt;/strong&gt; Daylight is your resource. The sun, the sky color, and the stars all move based on how many guesses you have spent, and the longest day of the year hands you the most daylight to work with.&lt;/li&gt;
&lt;li&gt;🌗 &lt;strong&gt;Light against darkness.&lt;/strong&gt; That is literally how you win or lose. Crack the code and the beacon lights up. Run out of daylight and night takes over.&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;A nod to Alan Turing.&lt;/strong&gt; June is his birth month, the whole game is built around breaking a code, and the feedback engine is his Bombe.&lt;/li&gt;
&lt;li&gt;🏳️‍🌈 &lt;strong&gt;A nod to Pride too.&lt;/strong&gt; The signal you are decoding is the six color spectrum, basically a rainbow. Turing was prosecuted for being gay, so decoding a rainbow in his name felt like the right thing for June.&lt;/li&gt;
&lt;/ul&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/longphanquangminh" rel="noopener noreferrer"&gt;
        longphanquangminh
      &lt;/a&gt; / &lt;a href="https://github.com/longphanquangminh/solstice-cipher" rel="noopener noreferrer"&gt;
        solstice-cipher
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🌞 SOLSTICE CIPHER&lt;/h1&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Crack the light before the longest day ends.&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;A code-breaking deduction game about racing the dying light of the June solstice — and a love letter to &lt;strong&gt;Alan Turing&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://longphanquangminh.github.io/solstice-cipher/" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;▶ Play it now&lt;/strong&gt;&lt;/a&gt; · Built for the &lt;a href="https://dev.clauneck.workers.dev/challenges/june-game-jam-2026-06-03" rel="nofollow"&gt;DEV June Solstice Game Jam 2026&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/d07e336d114f3cb35a238061527e1424021420ea22f41e06f34769247fc94171/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f48544d4c352d63616e7661732d4533344632363f6c6f676f3d68746d6c35266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/d07e336d114f3cb35a238061527e1424021420ea22f41e06f34769247fc94171/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f48544d4c352d63616e7661732d4533344632363f6c6f676f3d68746d6c35266c6f676f436f6c6f723d7768697465" alt="HTML5"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/dbee1f712fce91d1cc82f85b5e62462abf2da6cd73c0acd56df847a2a59218c2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4a6176615363726970742d76616e696c6c612d4637444631453f6c6f676f3d6a617661736372697074266c6f676f436f6c6f723d626c61636b"&gt;&lt;img src="https://camo.githubusercontent.com/dbee1f712fce91d1cc82f85b5e62462abf2da6cd73c0acd56df847a2a59218c2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4a6176615363726970742d76616e696c6c612d4637444631453f6c6f676f3d6a617661736372697074266c6f676f436f6c6f723d626c61636b" alt="Vanilla JS"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/aaf374cd2680eb93b56e603f6012fa5e6d192e2d51b43ff17a89e59d52b724bd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6275696c642d6e6f6e652d73756363657373"&gt;&lt;img src="https://camo.githubusercontent.com/aaf374cd2680eb93b56e603f6012fa5e6d192e2d51b43ff17a89e59d52b724bd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6275696c642d6e6f6e652d73756363657373" alt="No build"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/023e725d702069722fc304b22aa791e08ef3e423fe910237fecf0e6ce2550dbb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646570656e64656e636965732d302d73756363657373"&gt;&lt;img src="https://camo.githubusercontent.com/023e725d702069722fc304b22aa791e08ef3e423fe910237fecf0e6ce2550dbb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646570656e64656e636965732d302d73756363657373" alt="Dependencies"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b8cadaa967891081f8f165695470689986c028821dd8a040132f6e661795dc0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c7565"&gt;&lt;img src="https://camo.githubusercontent.com/b8cadaa967891081f8f165695470689986c028821dd8a040132f6e661795dc0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c7565" alt="License"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/longphanquangminh/solstice-cipher/gameplay.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Flongphanquangminh%2Fsolstice-cipher%2FHEAD%2Fgameplay.png" alt="SOLSTICE CIPHER gameplay"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;About&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;A scrambled &lt;strong&gt;light-signal&lt;/strong&gt; pulses over the horizon: six colors of the spectrum locked in a hidden order. Your job is to &lt;strong&gt;decrypt the sequence before the sun sets&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Every guess burns one hour of daylight — the sun slides down its arc, the sky bleeds from noon-blue to golden dusk to indigo night, and the stars come out. Crack the code and the beacon fires; run out of light and &lt;strong&gt;darkness wins&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The machine that grades your guesses is &lt;strong&gt;The Bombe&lt;/strong&gt; — the device Alan Turing designed to break the Enigma cipher.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Theme connection&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Thread&lt;/th&gt;
&lt;th&gt;In the game&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;☀️ &lt;strong&gt;Solstice&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/longphanquangminh/solstice-cipher" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;p&gt;The whole game is one HTML file. No engine, no framework, no build step, and nothing external except two Google Fonts. You open the file and it runs. Keeping it to a single file made it really easy to host and to share.&lt;/p&gt;

&lt;p&gt;Here is what is inside:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML5 Canvas for the sky, the sun, the stars, the floating motes, the particles, and the screen shake&lt;/li&gt;
&lt;li&gt;Plain DOM and CSS for the board, the HUD, and the animations&lt;/li&gt;
&lt;li&gt;The Web Audio API for the little retro machine sounds (there are no audio files anywhere)&lt;/li&gt;
&lt;li&gt;Vanilla JavaScript for the game logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The deduction core.&lt;/strong&gt; Underneath, this is basically Mastermind with repeated colors allowed. The Bombe scores each guess in two passes. First it counts the exact hits, then it goes back over the leftover colors and finds the ones that are right but sitting in the wrong slot.&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;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;guess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&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;exact&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;partial&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&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;gc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&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="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;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;guess&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="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;guess&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;===&lt;/span&gt; &lt;span class="nx"&gt;secret&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="nx"&gt;exact&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;           &lt;span class="c1"&gt;// right color, right slot&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;secret&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;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;guess&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;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;       &lt;span class="c1"&gt;// tally the misses&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;k&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;k&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;partial&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// right color, wrong slot&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;exact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;partial&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;strong&gt;Daylight as the clock.&lt;/strong&gt; There is no real countdown. Your guesses are the clock. One number drives the entire mood: &lt;code&gt;f = guessesUsed / maxGuesses&lt;/code&gt;. The sky is three color keyframes that I blend together based on &lt;code&gt;f&lt;/code&gt;, and the sun rides a curve that drops faster as the light runs low.&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;SKY&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="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;140&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;170&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;214&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;  &lt;span class="c1"&gt;// noon&lt;/span&gt;
  &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;138&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;205&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;  &lt;span class="c1"&gt;// golden dusk&lt;/span&gt;
  &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;        &lt;span class="c1"&gt;// night&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;W&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.42&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// drift toward the western horizon&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;H&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.17&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.62&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// fall faster as the daylight fades&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The stars only fade in once &lt;code&gt;f&lt;/code&gt; gets past about 0.4, so dusk is what actually brings out the night sky as you get low on time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Bombe Assist.&lt;/strong&gt; Pressing B spends one of your two charges. It picks a slot you have not solved yet (it leans toward one you currently have wrong), shows you the right color, and locks it in. It is a small tip of the hat to how the real Bombe ruled out possibilities to shrink the search. It also costs you points, so you actually have to decide whether it is worth it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Making it feel good.&lt;/strong&gt; Crack the code and you get bursts of particles in the spectrum colors plus a quick arpeggio. A wrong guess gets a low buzz, and the lose screen gives the canvas a shake.&lt;/p&gt;

&lt;p&gt;A couple of decisions I am happy with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It plays on the keyboard. Arrows to move, up and down or the number keys to set a color, Enter to decrypt, B for the Bombe. On a laptop you never reach for the mouse.&lt;/li&gt;
&lt;li&gt;Every orb has a number from 1 to 6 printed on it, so you can play by number and not only by color. That makes it work for people who are colorblind.&lt;/li&gt;
&lt;li&gt;Reusing that one &lt;code&gt;f&lt;/code&gt; value for the sky, the sun, and the stars kept the whole atmosphere in sync with the stakes for almost no extra code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It keeps going as long as you do. The codes grow from 4 to 5 to 6 symbols, your daylight scales from 10 to 12 to 14 guesses, and your score (&lt;code&gt;level × 100 + daylight saved × 15 + Bombe charges held × 40&lt;/code&gt;) carries over from level to level until night finally wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Category
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🏅 Best Ode to Alan Turing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I went after this one on purpose, and I tried to work Turing into the game itself rather than just name dropping him.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The actual gameplay is code breaking. The thing that grades your guesses is named The Bombe, after the real machine he built against Enigma, and the Bombe Assist echoes how that machine ruled out dead ends to narrow things down.&lt;/li&gt;
&lt;li&gt;The story around it leans on June being his birth month, with your deduction standing in as the light that holds off the dark.&lt;/li&gt;
&lt;li&gt;The code you are cracking is the six color spectrum, a rainbow, on purpose. Turing was prosecuted for being gay and only pardoned long after he died. Decoding a rainbow under his name pulls the solstice, Pride, and computing history into one picture.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;🌞 Thanks for playing, and happy solstice 🌞&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>gamechallenge</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Minh Long</dc:creator>
      <pubDate>Mon, 08 Jun 2026 15:38:45 +0000</pubDate>
      <link>https://dev.clauneck.workers.dev/minhlong2605/-3i</link>
      <guid>https://dev.clauneck.workers.dev/minhlong2605/-3i</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/solstice-cipher-write-code-break-ciphers-restore-daylight-5h2h" class="crayons-story__hidden-navigation-link"&gt;☀ Solstice Cipher: Write Code, Break Ciphers, Restore Daylight&lt;/a&gt;
    &lt;div class="crayons-article__cover crayons-article__cover__image__feed"&gt;
      &lt;iframe src="https://www.youtube.com/embed/CMjsaYY7nro" title="☀ Solstice Cipher: Write Code, Break Ciphers, Restore Daylight"&gt;&lt;/iframe&gt;
    &lt;/div&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/solstice-cipher-write-code-break-ciphers-restore-daylight-5h2h" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;June Solstice Game Jam Submission&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/minhlong2605" class="crayons-avatar  crayons-avatar--l  "&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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2947620%2Fcc910ef2-20bd-4bcb-8926-fe665ea5584d.png" alt="minhlong2605 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/minhlong2605" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Minh Long
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Minh Long
                
              
              &lt;div id="story-author-preview-content-3849894" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/minhlong2605" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2947620%2Fcc910ef2-20bd-4bcb-8926-fe665ea5584d.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Minh Long&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/solstice-cipher-write-code-break-ciphers-restore-daylight-5h2h" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 8&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/solstice-cipher-write-code-break-ciphers-restore-daylight-5h2h" id="article-link-3849894"&gt;
          ☀ Solstice Cipher: Write Code, Break Ciphers, Restore Daylight
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/gamechallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;gamechallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/gamedev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;gamedev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/solstice-cipher-write-code-break-ciphers-restore-daylight-5h2h" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;21&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/solstice-cipher-write-code-break-ciphers-restore-daylight-5h2h#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              2&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>☀ Solstice Cipher: Write Code, Break Ciphers, Restore Daylight</title>
      <dc:creator>Minh Long</dc:creator>
      <pubDate>Mon, 08 Jun 2026 15:38:32 +0000</pubDate>
      <link>https://dev.clauneck.workers.dev/minhlong2605/solstice-cipher-write-code-break-ciphers-restore-daylight-5h2h</link>
      <guid>https://dev.clauneck.workers.dev/minhlong2605/solstice-cipher-write-code-break-ciphers-restore-daylight-5h2h</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.clauneck.workers.dev/challenges/june-game-jam-2026-06-03"&gt;June Solstice Game Jam&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solstice Cipher&lt;/strong&gt; is a browser puzzle game where you write real JavaScript to decrypt intercepted messages — inside a full &lt;strong&gt;Monaco Editor&lt;/strong&gt; (the same engine that powers VS Code). Each solved cipher pushes back the night until the June 21 solstice breaks.&lt;/p&gt;

&lt;p&gt;🎮 &lt;strong&gt;Play:&lt;/strong&gt; &lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://solstice-cipher-encrypt-coding-game.vercel.app" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;solstice-cipher-encrypt-coding-game.vercel.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





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

&lt;p&gt;The core loop is simple: read an intercepted transmission, implement &lt;code&gt;decrypt(text)&lt;/code&gt; in a live code editor, hit &lt;strong&gt;Run decrypt()&lt;/strong&gt;, and advance if the output matches.&lt;/p&gt;

&lt;p&gt;There are &lt;strong&gt;5 cipher levels&lt;/strong&gt;, each tied to a phase of the solstice day:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Cipher&lt;/th&gt;
&lt;th&gt;Message&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Pre-dawn&lt;/td&gt;
&lt;td&gt;Caesar shift&lt;/td&gt;
&lt;td&gt;HELLO WORLD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Sunrise&lt;/td&gt;
&lt;td&gt;Atbash mirror&lt;/td&gt;
&lt;td&gt;THE COOL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Morning&lt;/td&gt;
&lt;td&gt;ROT13&lt;/td&gt;
&lt;td&gt;PRIDE HUMAN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Midday&lt;/td&gt;
&lt;td&gt;Vigenère (keyword &lt;strong&gt;PRIDE&lt;/strong&gt;)&lt;/td&gt;
&lt;td&gt;BE YOU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Longest Day&lt;/td&gt;
&lt;td&gt;Caesar + word reverse&lt;/td&gt;
&lt;td&gt;THE LIGHT SHINES&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As you progress, a &lt;strong&gt;daylight bar&lt;/strong&gt; fills from 15% to 100% — the sky literally brightens behind the UI. The narrative is set at &lt;strong&gt;Bletchley Park, June 1941&lt;/strong&gt;, framing each puzzle as a transmission Alan Turing's team might have intercepted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My intended goal:&lt;/strong&gt; make a game where &lt;em&gt;writing algorithms&lt;/em&gt; is the gameplay — not clicking tiles or guessing letters. The solstice theme isn't just decoration: every level is a step from darkness toward the longest day, and the final win screen lands on June 21 with Turing's own words.&lt;/p&gt;




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

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/g8eMmj_o9ow"&gt;
  &lt;/iframe&gt;
 &lt;/p&gt;

&lt;p&gt;The demo walks through:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Intro — solstice + Turing context&lt;/li&gt;
&lt;li&gt;Live gameplay — Caesar cipher in Monaco Editor, &lt;strong&gt;Run decrypt()&lt;/strong&gt;, daylight advancing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemini AI hint&lt;/strong&gt; streaming in with line-specific guidance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suggest fix&lt;/strong&gt; → Monaco diff view → Apply patch&lt;/li&gt;
&lt;li&gt;Win screen — &lt;em&gt;THE LIGHT SHINES&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&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/longphanquangminh" rel="noopener noreferrer"&gt;
        longphanquangminh
      &lt;/a&gt; / &lt;a href="https://github.com/longphanquangminh/solstice-cipher-encrypt-coding-game" rel="noopener noreferrer"&gt;
        solstice-cipher-encrypt-coding-game
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;Solstice Cipher ☀&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A &lt;strong&gt;code-breaking puzzle game&lt;/strong&gt; for the &lt;a href="https://dev.clauneck.workers.dev/devteam/join-the-june-solstice-game-jam-1000-in-prizes-3jla" rel="nofollow"&gt;June Solstice Game Jam&lt;/a&gt; on DEV.&lt;/p&gt;
&lt;p&gt;Write JavaScript &lt;code&gt;decrypt()&lt;/code&gt; functions in a real &lt;strong&gt;Monaco Editor&lt;/strong&gt; (VS Code's engine via &lt;code&gt;@monaco-editor/react&lt;/code&gt;) to break ciphers before the June 21 solstice. Each solved level brings more daylight — honoring &lt;strong&gt;Alan Turing&lt;/strong&gt;, &lt;strong&gt;Pride&lt;/strong&gt;, and the passage from darkness to light.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why this idea targets the prizes&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prize category&lt;/th&gt;
&lt;th&gt;How the game fits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Overall theme&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Solstice countdown, daylight progression, June 21 narrative&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best Ode to Alan Turing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bletchley Park story, Caesar/Enigma-style ciphers, algorithms as gameplay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best Google AI Usage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Optional Gemini 3.5 Flash hints via API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick start&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;cd&lt;/span&gt; solstice-cipher
npm install
npm run dev&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Open &lt;a href="http://localhost:5173" rel="nofollow noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Optional: Gemini AI hints&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Create &lt;code&gt;.env&lt;/code&gt; in the project root:&lt;/p&gt;
&lt;div class="highlight highlight-source-dotenv notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-v"&gt;VITE_GEMINI_API_KEY&lt;/span&gt;&lt;span class="pl-k"&gt;=&lt;/span&gt;&lt;span class="pl-s"&gt;your_google_ai_studio_key&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Get a free key at &lt;a href="https://aistudio.google.com/apikey" rel="nofollow noopener noreferrer"&gt;Google AI Studio&lt;/a&gt;. Without it, static hints still work.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How to play&lt;/h2&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Read the intercepted ciphertext and…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/longphanquangminh/solstice-cipher-encrypt-coding-game" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Key files if you want to dig in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/data/levels.ts&lt;/code&gt; — all 5 ciphers, starter code, solutions, narrative&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/components/GameScreen.tsx&lt;/code&gt; — main gameplay loop&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/components/CodeEditor.tsx&lt;/code&gt; — Monaco setup + custom Bletchley terminal theme&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/utils/gemini.ts&lt;/code&gt; — Gemini streaming hints + code fix generation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/utils/analyzeCode.ts&lt;/code&gt; — local static analysis that feeds the AI context&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/utils/runUserCode.ts&lt;/code&gt; — in-browser &lt;code&gt;decrypt()&lt;/code&gt; execution&lt;/li&gt;
&lt;/ul&gt;




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

&lt;h3&gt;
  
  
  Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React 19&lt;/strong&gt; + &lt;strong&gt;TypeScript&lt;/strong&gt; + &lt;strong&gt;Vite&lt;/strong&gt; — fast dev, static deploy, no backend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/@monaco-editor/react" rel="noopener noreferrer"&gt;@monaco-editor/react&lt;/a&gt;&lt;/strong&gt; — the entire gameplay UI lives in Monaco, not a fake textarea&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/@google/genai" rel="noopener noreferrer"&gt;@google/genai&lt;/a&gt;&lt;/strong&gt; — official Google AI SDK for streaming hints&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Motion&lt;/strong&gt; — intro/win screen animations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Monaco as the game engine
&lt;/h3&gt;

&lt;p&gt;The editor uses an &lt;strong&gt;uncontrolled&lt;/strong&gt; pattern (&lt;code&gt;defaultValue&lt;/code&gt; + ref) so typing feels native — no React re-render on every keystroke, which was critical for a smooth coding experience.&lt;/p&gt;

&lt;p&gt;I defined a custom &lt;strong&gt;&lt;code&gt;bletchley-terminal&lt;/code&gt;&lt;/strong&gt; theme: phosphor green strings, hazard red keywords, dark CRT background. Line highlighting marks the exact lines Gemini flags as buggy.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;Suggest fix&lt;/strong&gt;, I use Monaco's &lt;strong&gt;DiffEditor&lt;/strong&gt; — red/green side-by-side diff — with Apply/Dismiss. Patches go through &lt;code&gt;executeEdits&lt;/code&gt; so undo works naturally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running player code safely
&lt;/h3&gt;

&lt;p&gt;Player code runs in-browser via &lt;code&gt;new Function()&lt;/code&gt; with a strict contract: define &lt;code&gt;decrypt(text)&lt;/code&gt;, return a string. Output is normalized (uppercase, trimmed) before comparison. No network, no server — fully static.&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="c1"&gt;// src/utils/runUserCode.ts — simplified&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&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;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
  &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
  if (typeof decrypt !== 'function') throw new Error('Define decrypt(text)');
  return decrypt(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;);
`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Gemini AI — not a chatbot bolt-on
&lt;/h3&gt;

&lt;p&gt;When &lt;code&gt;VITE_GEMINI_API_KEY&lt;/code&gt; is set, &lt;strong&gt;Turing Assist&lt;/strong&gt; activates via &lt;code&gt;gemini-3.5-flash&lt;/code&gt; and &lt;code&gt;generateContentStream&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before any API call, the game runs &lt;strong&gt;local static analysis&lt;/strong&gt; on the player's code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detects untouched starter template lines&lt;/li&gt;
&lt;li&gt;Finds passthrough bugs (&lt;code&gt;result += char&lt;/code&gt; without shifting)&lt;/li&gt;
&lt;li&gt;Classifies run state: &lt;code&gt;NOT_RUN&lt;/code&gt;, &lt;code&gt;RUNTIME_ERROR&lt;/code&gt;, &lt;code&gt;WRONG_OUTPUT&lt;/code&gt;, &lt;code&gt;CORRECT&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Picks a hint mode: &lt;strong&gt;GUIDE&lt;/strong&gt;, &lt;strong&gt;DEBUG&lt;/strong&gt;, or &lt;strong&gt;ERROR&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That analysis is sent to Gemini along with numbered source code. The model returns hints that reference &lt;strong&gt;specific line numbers&lt;/strong&gt; — never the full plaintext answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Suggest fix&lt;/strong&gt; is a second Gemini call that returns a fenced code block. Multiple candidates are validated by actually running them against the encrypted input; the first working patch wins. If Gemini fails, a &lt;strong&gt;local diff engine&lt;/strong&gt; compares starter vs solution line-by-line as fallback — the game works fully offline without an API key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual design
&lt;/h3&gt;

&lt;p&gt;Industrial brutalist CRT aesthetic: scanlines, telemetry chrome, Enigma rotor graphic, and a &lt;strong&gt;Pride stripe&lt;/strong&gt; on the intro display. The &lt;code&gt;--daylight&lt;/code&gt; CSS variable drives a dynamic sky gradient — the UI literally gets brighter as you solve puzzles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interesting decisions
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AI as tutor, not spoiler&lt;/strong&gt; — system prompts forbid revealing answers; hints are contextual to &lt;em&gt;your&lt;/em&gt; broken code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming hints&lt;/strong&gt; — text appears token-by-token like a live terminal feed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual fallback chain&lt;/strong&gt; — Gemini → local analysis → static per-level hints; no dead ends&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code fix validation&lt;/strong&gt; — never apply a patch that doesn't produce the correct decrypt output&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Prize Category
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Best Ode to Alan Turing
&lt;/h3&gt;

&lt;p&gt;This category is the heart of the project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Setting:&lt;/strong&gt; Bletchley Park, June 1941 — the same era Turing cracked Enigma&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mechanics:&lt;/strong&gt; Gameplay &lt;em&gt;is&lt;/em&gt; writing decryption algorithms — Caesar, Atbash, ROT13, Vigenère&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Narrative:&lt;/strong&gt; Each level references how Turing learned patterns, saw symmetry in code, and turned hidden truth into clarity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Win screen:&lt;/strong&gt; Quotes Turing directly — &lt;em&gt;"We can only see a short distance ahead, but we can see plenty there that needs to be done."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI details:&lt;/strong&gt; Enigma rotor, &lt;code&gt;SYS / BP-1941&lt;/code&gt; header, Bletchley telemetry framing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The game doesn't just mention Turing — it asks you to &lt;em&gt;think like him&lt;/em&gt;: break ciphers by writing code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Google AI Usage
&lt;/h3&gt;

&lt;p&gt;Gemini is integrated as &lt;strong&gt;Turing Assist&lt;/strong&gt;, a cryptography tutor that understands your current code state:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;How Gemini is used&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Smart hints&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;generateContentStream&lt;/code&gt; with system prompt + local code analysis → line-specific GUIDE/DEBUG/ERROR hints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Suggest fix&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Second call returns a minimal patch; validated by running against ciphertext&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fallback&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Local static analysis + offline hints when no API key — AI enhances, never blocks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SDK&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Official &lt;code&gt;@google/genai&lt;/code&gt; — not a raw fetch wrapper&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The AI receives structured context (run status, detected issues, numbered code) rather than a generic "help me solve this puzzle" prompt. That makes hints feel like a pair programmer at Bletchley, not a spoiler bot.&lt;/p&gt;

&lt;p&gt;Set &lt;code&gt;VITE_GEMINI_API_KEY&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt; (free key from &lt;a href="https://aistudio.google.com/apikey" rel="noopener noreferrer"&gt;Google AI Studio&lt;/a&gt;) to enable live AI. Without it, static hints still work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Start (for judges who want to run it locally)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/longphanquangminh/solstice-cipher-encrypt-coding-game.git
&lt;span class="nb"&gt;cd &lt;/span&gt;solstice-cipher
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optional — enable Gemini hints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VITE_GEMINI_API_KEY=your_key_here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Tags
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;#devchallenge&lt;/code&gt; &lt;code&gt;#gamechallenge&lt;/code&gt; &lt;code&gt;#gamedev&lt;/code&gt; &lt;code&gt;#react&lt;/code&gt; &lt;code&gt;#typescript&lt;/code&gt; &lt;code&gt;#monacoeditor&lt;/code&gt; &lt;code&gt;#googleai&lt;/code&gt; &lt;code&gt;#gemini&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;Thanks for reading — and happy solstice! 🌈☀&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>gamechallenge</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Minh Long</dc:creator>
      <pubDate>Mon, 25 May 2026 11:04:20 +0000</pubDate>
      <link>https://dev.clauneck.workers.dev/minhlong2605/-3fk7</link>
      <guid>https://dev.clauneck.workers.dev/minhlong2605/-3fk7</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/interview-coach-ai-practice-mock-interviews-locally-with-gemma-4-jan-1816" class="crayons-story__hidden-navigation-link"&gt;🎙️Interview Coach AI — Practice Mock Interviews Locally with Gemma 4 + Jan&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/interview-coach-ai-practice-mock-interviews-locally-with-gemma-4-jan-1816" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Gemma 4 Challenge: Build With Gemma 4 Submission&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/minhlong2605" class="crayons-avatar  crayons-avatar--l  "&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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2947620%2Fcc910ef2-20bd-4bcb-8926-fe665ea5584d.png" alt="minhlong2605 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/minhlong2605" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Minh Long
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Minh Long
                
              
              &lt;div id="story-author-preview-content-3742181" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/minhlong2605" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2947620%2Fcc910ef2-20bd-4bcb-8926-fe665ea5584d.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Minh Long&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/interview-coach-ai-practice-mock-interviews-locally-with-gemma-4-jan-1816" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 24&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/interview-coach-ai-practice-mock-interviews-locally-with-gemma-4-jan-1816" id="article-link-3742181"&gt;
          🎙️Interview Coach AI — Practice Mock Interviews Locally with Gemma 4 + Jan
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/gemmachallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;gemmachallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/gemma"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;gemma&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/interview-coach-ai-practice-mock-interviews-locally-with-gemma-4-jan-1816" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;16&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.clauneck.workers.dev/minhlong2605/interview-coach-ai-practice-mock-interviews-locally-with-gemma-4-jan-1816#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>career</category>
      <category>gemmachallenge</category>
      <category>showdev</category>
    </item>
    <item>
      <title>🎙️Interview Coach AI — Practice Mock Interviews Locally with Gemma 4 + Jan</title>
      <dc:creator>Minh Long</dc:creator>
      <pubDate>Sun, 24 May 2026 17:32:20 +0000</pubDate>
      <link>https://dev.clauneck.workers.dev/minhlong2605/interview-coach-ai-practice-mock-interviews-locally-with-gemma-4-jan-1816</link>
      <guid>https://dev.clauneck.workers.dev/minhlong2605/interview-coach-ai-practice-mock-interviews-locally-with-gemma-4-jan-1816</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.clauneck.workers.dev/challenges/google-gemma-2026-05-06"&gt;Gemma 4 Challenge: Build with Gemma 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Interview Coach AI&lt;/strong&gt; is a local-first mock interview web app. You work through a &lt;strong&gt;10-module curriculum&lt;/strong&gt; (self-intro, behavioral, technical, capstone mock), speak or type your answers to an AI recruiter, and get a &lt;strong&gt;full performance report&lt;/strong&gt; when the session ends — radar scores, strengths, weaknesses, and written feedback.&lt;/p&gt;

&lt;p&gt;The product loop is simple on purpose:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick a lesson on the practice hub&lt;/li&gt;
&lt;li&gt;Start a &lt;strong&gt;Preparation&lt;/strong&gt; session (guided flow, live transcript, real-time scores)&lt;/li&gt;
&lt;li&gt;Review analytics and track progress in your browser&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No cloud LLM bill for the core experience. The “brain” of the app is &lt;strong&gt;Gemma 4 running on your machine&lt;/strong&gt;, wired through &lt;strong&gt;Jan’s local server&lt;/strong&gt; and its OpenAPI/Swagger docs so you can inspect and test every call before the React app ever hits it.&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.amazonaws.com%2Fuploads%2Farticles%2F7tsysvjpo0esz9zdyj1u.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.amazonaws.com%2Fuploads%2Farticles%2F7tsysvjpo0esz9zdyj1u.png" alt="Interview Coach AI — dashboard and mock interview" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Quick local demo (no deploy required):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/longphanquangminh/gemma-interview.git
&lt;span class="nb"&gt;cd &lt;/span&gt;gemma-interview
npm &lt;span class="nb"&gt;install
cp&lt;/span&gt; .env.example .env
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;1/ Open &lt;strong&gt;Jan&lt;/strong&gt; → load &lt;strong&gt;&lt;code&gt;gemma-4-E4B-it-IQ4_XS&lt;/code&gt;&lt;/strong&gt; → start the &lt;strong&gt;local API server&lt;/strong&gt; (default &lt;code&gt;http://127.0.0.1:1337&lt;/code&gt;)&lt;br&gt;
2/ Open Jan’s &lt;strong&gt;Swagger / API docs&lt;/strong&gt; in the browser — confirm &lt;code&gt;POST /v1/messages&lt;/code&gt; responds&lt;/p&gt;

&lt;p&gt;Jan app: &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.amazonaws.com%2Fuploads%2Farticles%2Fm60yw8f6k3j6zzzoxzaw.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.amazonaws.com%2Fuploads%2Farticles%2Fm60yw8f6k3j6zzzoxzaw.png" alt="Jan app" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LLM Swagger: &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.amazonaws.com%2Fuploads%2Farticles%2F93xc44gxf9hvcj7fk3b7.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.amazonaws.com%2Fuploads%2Farticles%2F93xc44gxf9hvcj7fk3b7.png" alt="Jan" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3/ Visit &lt;code&gt;http://localhost:3000&lt;/code&gt; → &lt;strong&gt;Open practice hub&lt;/strong&gt; → Module 1 → &lt;strong&gt;Preparation&lt;/strong&gt; → complete one question and open the report&lt;/p&gt;

&lt;p&gt;That’s the whole contest story: &lt;strong&gt;Gemma on Jan, in your room, in your app.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Youtube video showcasing original version of the app (Please turn up the volume to hear clearly):&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/AX8PjZ8Mb4Q"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/a5vFTzomi8s"&gt;
  &lt;/iframe&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.amazonaws.com%2Fuploads%2Farticles%2F4u6uai982wfgztymsjgc.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.amazonaws.com%2Fuploads%2Farticles%2F4u6uai982wfgztymsjgc.png" alt="Demo1" width="800" height="552"&gt;&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2Fwkh3rkqys2dtn3oj5d05.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.amazonaws.com%2Fuploads%2Farticles%2Fwkh3rkqys2dtn3oj5d05.png" alt="Demo2" width="800" height="583"&gt;&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2F5r35c82bmsxfmir3wcin.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.amazonaws.com%2Fuploads%2Farticles%2F5r35c82bmsxfmir3wcin.png" alt="Demo3" width="800" height="623"&gt;&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2Fn6mzp4dv6uvc9le74018.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.amazonaws.com%2Fuploads%2Farticles%2Fn6mzp4dv6uvc9le74018.png" alt="Demo4" width="800" height="446"&gt;&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2F5kuod447x9vpsl358yc4.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.amazonaws.com%2Fuploads%2Farticles%2F5kuod447x9vpsl358yc4.png" alt="Demo5" width="800" height="880"&gt;&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2Fbf73my99txqhmukm483t.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.amazonaws.com%2Fuploads%2Farticles%2Fbf73my99txqhmukm483t.png" alt="Demo6" width="800" height="769"&gt;&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2Fctsyea08r922hkbv770i.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.amazonaws.com%2Fuploads%2Farticles%2Fctsyea08r922hkbv770i.png" alt="Demo55" width="800" height="378"&gt;&lt;/a&gt;&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/longphanquangminh" rel="noopener noreferrer"&gt;
        longphanquangminh
      &lt;/a&gt; / &lt;a href="https://github.com/longphanquangminh/gemma-interview" rel="noopener noreferrer"&gt;
        gemma-interview
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;Interview Coach AI&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;General-purpose &lt;strong&gt;mock interview&lt;/strong&gt; practice with an AI recruiter, structured curriculum, and evidence-based reports. Built for the &lt;a href="https://dev.clauneck.workers.dev/challenges/google-gemma-2026-05-06" rel="nofollow"&gt;Gemma 4 Challenge&lt;/a&gt; on DEV — &lt;strong&gt;Gemma 4&lt;/strong&gt; (or any OpenAI-compatible model) drives planning, turn-taking, live scoring, and post-session analytics.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Highlights&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;Area&lt;/th&gt;

&lt;th&gt;Details&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;&lt;strong&gt;Curriculum&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;10 modules (self-intro → capstone mock), sequential unlock&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;&lt;strong&gt;Preparation&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;5-question flow, avatar + TTS, transcript, live scores, local LLM&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;&lt;strong&gt;Live interview&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;Full-screen Tavus video room; LLM report after end&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;&lt;strong&gt;App hub&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;Dashboard, profile, settings, session history (separate from marketing landing)&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick start&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt; Node.js 18+, a Gemma 4 (or compatible) endpoint, optional Tavus key for live video.&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install
cp .env.example .env
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; LOCAL_AI_BASE_URL + LOCAL_AI_MODEL → your Gemma / LM Studio / AI Studio proxy&lt;/span&gt;
npm run dev&lt;/pre&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Marketing site:&lt;/strong&gt; &lt;a href="http://localhost:3000" rel="nofollow noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Practice hub:&lt;/strong&gt; &lt;a href="http://localhost:3000/dashboard" rel="nofollow noopener noreferrer"&gt;http://localhost:3000/dashboard&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Environment&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;Variable&lt;/th&gt;

&lt;th&gt;Used for&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;&lt;code&gt;LOCAL_AI_BASE_URL&lt;/code&gt;&lt;/td&gt;

&lt;td&gt;OpenAI-compatible Messages API (Gemma)&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;&lt;code&gt;LOCAL_AI_MODEL&lt;/code&gt;&lt;/td&gt;

&lt;td&gt;Model id on that endpoint&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;&lt;code&gt;VITE_TAVUS_*&lt;/code&gt;&lt;/td&gt;

&lt;td&gt;Live interview mode only&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;See &lt;code&gt;.env.example&lt;/code&gt;…&lt;/p&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/longphanquangminh/gemma-interview" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/longphanquangminh/gemma-interview" rel="noopener noreferrer"&gt;github.com/longphanquangminh/gemma-interview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gemma integration lives in one place:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/services/aiService.ts   →  every prompt + parse + score calibration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app sends a single user message per request to Jan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST http://127.0.0.1:1337/v1/messages
Content-Type: application/json

{
  "model": "gemma-4-E4B-it-IQ4_XS",
  "messages": [{ "role": "user", "content": "&amp;lt;structured prompt&amp;gt;" }]
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure via &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LOCAL_AI_BASE_URL="http://127.0.0.1:1337"
LOCAL_AI_MODEL="gemma-4-E4B-it-IQ4_XS"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How I Used Gemma 4
&lt;/h2&gt;

&lt;p&gt;Gemma 4 is not decoration in this project — it &lt;strong&gt;is&lt;/strong&gt; the interviewer, the examiner, and the report writer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which model, and why
&lt;/h3&gt;

&lt;p&gt;I run &lt;strong&gt;&lt;code&gt;gemma-4-E4B-it-IQ4_XS&lt;/code&gt;&lt;/strong&gt; through Jan locally — Gemma 4’s &lt;strong&gt;E4B&lt;/strong&gt; edge variant with &lt;strong&gt;IQ4_XS&lt;/strong&gt; quantization.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gemma 4 variant&lt;/th&gt;
&lt;th&gt;Why I did / didn’t choose it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;E4B (edge, ~4B effective) — my pick&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fast enough for &lt;strong&gt;many calls per session&lt;/strong&gt; (plan → 5× turn/score → report). IQ4_XS keeps RAM/VRAM modest so anyone can rehearse interviews on a normal laptop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2B-class&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Even lighter, but I wanted a bit more headroom for strict JSON + multi-step turn format across a full mock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;31B Dense&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Best raw reasoning, overkill for this workflow and too heavy for “open Jan and practice tonight”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;26B MoE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strong middle ground, but I deliberately wanted to show the &lt;strong&gt;edge line&lt;/strong&gt; can carry a full structured agent loop when prompts + code guards are designed for it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Intentional fit:&lt;/strong&gt; Interview Coach is not open-ended chat. Every Gemma call has a &lt;strong&gt;fixed output shape&lt;/strong&gt; (JSON plan, &lt;code&gt;CLASSIFICATION&lt;/code&gt; / &lt;code&gt;ACTION&lt;/code&gt; / &lt;code&gt;SAY&lt;/code&gt; lines, score JSON). That lets E4B punch above its weight — and when the model drifts, &lt;code&gt;applyTurnGuards()&lt;/code&gt; and parsers in &lt;code&gt;aiService.ts&lt;/code&gt; keep the UX stable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IQ4_XS:&lt;/strong&gt; aggressive quant for speed and size. Trade-off is occasional sloppy JSON; I debug those cases in &lt;strong&gt;Jan Swagger&lt;/strong&gt; first, then tighten prompts. For a practice app with 10+ inference steps per session, &lt;strong&gt;latency and accessibility&lt;/strong&gt; mattered more than squeezing the last point of benchmark score from a 31B file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Jan + Swagger mattered
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://jan.ai/" rel="noopener noreferrer"&gt;Jan&lt;/a&gt; made the integration feel &lt;strong&gt;production-shaped&lt;/strong&gt; instead of hacky:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local server&lt;/strong&gt; with an OpenAI-compatible &lt;strong&gt;&lt;code&gt;/v1/messages&lt;/code&gt;&lt;/strong&gt; endpoint&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swagger UI&lt;/strong&gt; to prototype prompts, check payloads, and debug bad JSON &lt;em&gt;before&lt;/em&gt; wiring the React UI&lt;/li&gt;
&lt;li&gt;Same model id end-to-end — what works in Swagger is what the app calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That loop — &lt;strong&gt;Swagger first, app second&lt;/strong&gt; — saved hours. Gemma’s responses are only useful here because the contract is strict; Jan’s docs let me validate that contract in isolation.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Gemma does in the app (every call)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;aiService&lt;/code&gt; function&lt;/th&gt;
&lt;th&gt;Gemma’s job&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Start session&lt;/td&gt;
&lt;td&gt;&lt;code&gt;generateInterviewPlan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JSON plan: welcome + &lt;strong&gt;5 interview questions&lt;/strong&gt; (typed: intro, technical, behavioral, …)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Each answer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;processTurn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recruiter line + &lt;code&gt;CLASSIFICATION&lt;/code&gt; / &lt;code&gt;ACTION&lt;/code&gt; / &lt;code&gt;SAY&lt;/code&gt; (follow-up, next, repeat, end)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live feedback&lt;/td&gt;
&lt;td&gt;&lt;code&gt;analyzeResponse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scores: clarity, confidence, professionalism&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;End session&lt;/td&gt;
&lt;td&gt;&lt;code&gt;getSessionSummary&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full report JSON: overall + dimensions + strengths + weaknesses&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
  A[User answers] --&amp;gt; B[React app]
  B --&amp;gt; C[Jan local API]
  C --&amp;gt; D[Gemma 4 E4B]
  D --&amp;gt; C
  C --&amp;gt; B
  B --&amp;gt; E[Transcript + live scores]
  B --&amp;gt; F[Analytics report]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why Gemma shines on this workload
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Structured JSON&lt;/strong&gt; — plans and reports must parse; E4B + tight prompts + parsers made this workable locally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turn protocol&lt;/strong&gt; — line-based &lt;code&gt;SAY:&lt;/code&gt; output is easier to guard in code than free-form chat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evidence-based scoring&lt;/strong&gt; — rubric prompts plus calibration in TypeScript; Gemma supplies judgments, the app enforces fairness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy, cost, and speed&lt;/strong&gt; — everything stays on your machine; E4B + IQ4_XS keeps sessions responsive enough to actually finish a module.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’m impressed that &lt;strong&gt;Gemma 4 E4B can own a full agent loop&lt;/strong&gt; on consumer hardware — plan → dialogue → score → summarize — without sending transcripts to a hosted API. That’s the point of the edge family, and this app is built to showcase it.&lt;/p&gt;

&lt;h3&gt;
  
  
  One request from the judges
&lt;/h3&gt;

&lt;p&gt;If you try the repo, load &lt;strong&gt;&lt;code&gt;gemma-4-E4B-it-IQ4_XS&lt;/code&gt;&lt;/strong&gt; in Jan, hit &lt;strong&gt;Swagger&lt;/strong&gt; once, then run Module 1 in the app. The story is &lt;strong&gt;edge Gemma + strict contracts + Jan&lt;/strong&gt;, not a thin chat wrapper.&lt;/p&gt;




</description>
      <category>devchallenge</category>
      <category>gemmachallenge</category>
      <category>gemma</category>
    </item>
    <item>
      <title>🚀LeadPilot – Your AI Staff Engineer in the Terminal</title>
      <dc:creator>Minh Long</dc:creator>
      <pubDate>Mon, 16 Feb 2026 07:57:18 +0000</pubDate>
      <link>https://dev.clauneck.workers.dev/minhlong2605/ai-technical-lead-1o6b</link>
      <guid>https://dev.clauneck.workers.dev/minhlong2605/ai-technical-lead-1o6b</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.clauneck.workers.dev/challenges/github-2026-01-21"&gt;GitHub Copilot CLI Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tagline:&lt;/strong&gt;&lt;br&gt;
“Because not everyone has a Staff Engineer reviewing their PR at 2AM.”&lt;/p&gt;
&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;LeadPilot&lt;/strong&gt; is a tiny CLI that turns your local &lt;code&gt;git diff&lt;/code&gt; into an actionable code review using &lt;strong&gt;GitHub Copilot CLI&lt;/strong&gt;-right from your terminal.&lt;/p&gt;

&lt;p&gt;Instead of waiting for PR reviews (or context-switching to a web UI), I wanted something I can run &lt;strong&gt;immediately while coding&lt;/strong&gt;-especially for quick “sanity checks” before committing, pushing, or opening a PR.&lt;/p&gt;
&lt;h3&gt;
  
  
  What it does
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One command&lt;/strong&gt;: &lt;code&gt;leadpilot review&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two review personas&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Startup CTO Review&lt;/strong&gt; (default): pragmatic, shipping-focused, highlights the biggest risk + one improvement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FAANG Staff Engineer Review&lt;/strong&gt;: stricter, architecture/scalability oriented, includes score + approval decision&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branch-aware diffs&lt;/strong&gt;: compare against any git ref via &lt;code&gt;--branch&lt;/code&gt; (e.g. &lt;code&gt;--branch master&lt;/code&gt;, &lt;code&gt;--branch origin/main&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terminal-friendly output&lt;/strong&gt;: clean, boxed formatting that’s easy to skim&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’ve ever thought “I wish a senior engineer could look at this real quick”… LeadPilot is that, on-demand.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why I built it
&lt;/h3&gt;

&lt;p&gt;Code reviews are amazing… when you can get them.&lt;/p&gt;

&lt;p&gt;But in real life:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You might be working solo, late at night, or in a small team.&lt;/li&gt;
&lt;li&gt;Your teammate might be asleep (or in meetings) when you’re about to ship.&lt;/li&gt;
&lt;li&gt;Sometimes you don’t need a full PR discussion-you just want a quick, high-signal check.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;LeadPilot is designed for that moment: &lt;strong&gt;fast feedback, in the terminal, on the diff you’re already looking at&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  How it works (high-level)
&lt;/h3&gt;

&lt;p&gt;LeadPilot keeps the workflow intentionally simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It computes the diff you care about using &lt;code&gt;git diff &amp;lt;branch&amp;gt;&lt;/code&gt; (default &lt;code&gt;origin/main&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;It wraps that diff in a prompt tailored to the persona you chose (&lt;code&gt;startup&lt;/code&gt; or &lt;code&gt;faang&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;It asks GitHub Copilot CLI to review it via the &lt;code&gt;copilot&lt;/code&gt; command (prompt-in, review-out).&lt;/li&gt;
&lt;li&gt;It prints the result in a clean, boxed format so you can skim it quickly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach makes it easy to use in any repo without extra setup beyond having &lt;code&gt;git&lt;/code&gt; + &lt;code&gt;copilot&lt;/code&gt; available.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/longphanquangminh/leadpilot" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/leadpilot&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Quick start (global install)
&lt;/h3&gt;

&lt;p&gt;From the LeadPilot repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Suggested walkthrough
&lt;/h3&gt;

&lt;p&gt;1/ Open any git repository.&lt;br&gt;
2/ Make a small change (uncommitted is fine).&lt;br&gt;
3/ Run a pragmatic review against &lt;code&gt;master&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;leadpilot review &lt;span class="nt"&gt;--branch&lt;/span&gt; master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4/ Flip personas to get a stricter review:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;leadpilot review &lt;span class="nt"&gt;--mode&lt;/span&gt; faang &lt;span class="nt"&gt;--branch&lt;/span&gt; master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5/ Show the boxed output and discuss whether you’d “ship it” or iterate.&lt;/p&gt;

&lt;h3&gt;
  
  
  What you guys should do in your trials
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A diff that’s ~10–100 lines (enough to be interesting, small enough to review live)&lt;/li&gt;
&lt;li&gt;The Startup CTO output (biggest risk + one improvement)&lt;/li&gt;
&lt;li&gt;The FAANG output (score + approval decision)&lt;/li&gt;
&lt;li&gt;A quick branch switch (&lt;code&gt;--branch origin/main&lt;/code&gt; vs &lt;code&gt;--branch master&lt;/code&gt;) to show it’s flexible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Screenshots:&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.amazonaws.com%2Fuploads%2Farticles%2Fi6mbw5v39x2gm6g07nm3.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.amazonaws.com%2Fuploads%2Farticles%2Fi6mbw5v39x2gm6g07nm3.png" alt="Demo1" width="800" height="424"&gt;&lt;/a&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.amazonaws.com%2Fuploads%2Farticles%2Fj056b8vi2rnu4qoikx34.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.amazonaws.com%2Fuploads%2Farticles%2Fj056b8vi2rnu4qoikx34.png" alt="Demo2" width="799" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience with GitHub Copilot CLI
&lt;/h2&gt;

&lt;p&gt;GitHub Copilot CLI was my “pair reviewer” while building LeadPilot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It helped me &lt;strong&gt;iterate fast on prompts&lt;/strong&gt; so each persona produces consistent, scannable sections (instead of a wall of text).&lt;/li&gt;
&lt;li&gt;It was great for &lt;strong&gt;UX pressure-testing&lt;/strong&gt;: what output is actually actionable in a terminal (and what’s just noise).&lt;/li&gt;
&lt;li&gt;It made it easy to &lt;strong&gt;loop on edge cases&lt;/strong&gt; (no diff, wrong refs, setup issues) because everything stays in the command line.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I liked most is how natural it felt to keep everything in the terminal: edit → diff → review → refine.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I learned
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Constraints create clarity&lt;/strong&gt;: forcing the Startup CTO persona to return “ship decision + biggest risk + one improvement” makes the review immediately usable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Different personas are surprisingly helpful&lt;/strong&gt;: the strict mode is great for architecture/design issues; the startup mode is great for “what could blow up in production tomorrow”.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terminal output matters&lt;/strong&gt;: boxing + consistent headings makes it feel like a real tool, not just AI text pasted into your console.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What I’d improve next
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Async reviews&lt;/strong&gt; for very large diffs or slower machines (queue the job, stream output, or provide a progress indicator).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More modes&lt;/strong&gt; (e.g., “Security reviewer”, “Performance reviewer”, “DX reviewer”) while keeping outputs structured.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context knobs&lt;/strong&gt; (optionally include commit messages, file paths only, or a summary first).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>🚀 Copilot CLI Plugin Marketplace - AI-Powered Productivity Hub</title>
      <dc:creator>Minh Long</dc:creator>
      <pubDate>Mon, 16 Feb 2026 07:50:02 +0000</pubDate>
      <link>https://dev.clauneck.workers.dev/minhlong2605/copilot-cli-plugin-marketplace-ai-powered-productivity-hub-2am8</link>
      <guid>https://dev.clauneck.workers.dev/minhlong2605/copilot-cli-plugin-marketplace-ai-powered-productivity-hub-2am8</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.clauneck.workers.dev/challenges/github-2026-01-21"&gt;GitHub Copilot CLI Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I created a &lt;strong&gt;production-ready web application&lt;/strong&gt; that transforms GitHub Copilot CLI into an accessible, user-friendly marketplace of AI-powered plugins. Instead of running commands in the terminal, users can now click beautifully designed cards and watch plugins execute in real-time with live output streaming.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 The Problem I Solved
&lt;/h3&gt;

&lt;p&gt;GitHub Copilot CLI is incredibly powerful but requires terminal familiarity. My marketplace makes these capabilities accessible to everyone with an intuitive web interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✨ Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🎨 Beautiful Modern UI&lt;/strong&gt; - SaaS-style design with smooth animations and terminal-style output display&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⚡ Fast &amp;amp; Responsive&lt;/strong&gt; - Built with Next.js 16 and TailwindCSS 4&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🔌 4 Powerful Pre-built Plugins&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;📄 &lt;strong&gt;Generate README&lt;/strong&gt; - Create comprehensive project documentation&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;Summarize Git Commits&lt;/strong&gt; - Analyze history and generate changelogs&lt;/li&gt;
&lt;li&gt;🧪 &lt;strong&gt;Generate Test Cases&lt;/strong&gt; - Create unit and integration test suites&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Repository Review&lt;/strong&gt; - Comprehensive code review and suggestions&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;🔒 Security First&lt;/strong&gt; - No command injection vulnerabilities, whitelist validation&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;📦 Extensible&lt;/strong&gt; - Add new plugins in 2 minutes with minimal code&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;🧪 Production Ready&lt;/strong&gt; - Full TypeScript, comprehensive error handling, security hardened&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  💻 Technology Stack
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend: React 19 + TypeScript + TailwindCSS
Backend: Next.js 16 (App Router) + API Routes
Runtime: Node.js child_process
CLI: GitHub Copilot CLI
Database: None (plugins configured in code)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;h3&gt;
  
  
  🎬 Live Project
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/longphanquangminh/copilot-plugin-marketplace" rel="noopener noreferrer"&gt;GitHub - copilot-plugin-marketplace&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  📸 Screenshots
&lt;/h3&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.amazonaws.com%2Fuploads%2Farticles%2Fesntg2fezeoeesv4h45x.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.amazonaws.com%2Fuploads%2Farticles%2Fesntg2fezeoeesv4h45x.png" alt="Demo" width="800" height="623"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Homepage
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────┐
│                                                     │
│  Copilot CLI Plugin Marketplace                    │
│                                                     │
│  Supercharge your workflow with                    │
│  AI-powered productivity plugins                   │
│                                                     │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐         │
│  │📄 README │  │🔗 Commits│  │🧪 Tests  │         │
│  │Generate  │  │Summarize │  │Generate  │         │
│  │[ Run ]   │  │[ Run ]   │  │[ Run ]   │         │
│  └──────────┘  └──────────┘  └──────────┘         │
│                                                     │
│  ┌──────────┐                                       │
│  │🔍 Review │                                       │
│  │Repository│                                       │
│  │[ Run ]   │                                       │
│  └──────────┘                                       │
└─────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Plugin Execution
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1: User clicks "Run Plugin"
Step 2: Loading spinner appears
Step 3: Copilot CLI executes prompt
Step 4: Results stream in real-time
Step 5: Terminal-style output displayed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Output Display
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────────────────────────┐
│ $ Plugin Output                    │
├────────────────────────────────────┤
│ # My Project README                │
│                                    │
│ A modern web application...        │
│                                    │
│ ## Installation                    │
│ npm install                        │
│ npm run dev                        │
│                                    │
│ ## Features                        │
│ - Feature 1                        │
│ - Feature 2                        │
│                                    │
│ [Scroll for more...]               │
└────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🚀 Getting Started (2 Minutes)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone the repository&lt;/span&gt;
git clone https://github.com/longphanquangminh/copilot-plugin-marketplace.git
&lt;span class="nb"&gt;cd &lt;/span&gt;copilot-plugin-marketplace

&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Start development server&lt;/span&gt;
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open &lt;strong&gt;&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/strong&gt; and explore the marketplace!&lt;/p&gt;

&lt;h3&gt;
  
  
  📋 Requirements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 18+&lt;/li&gt;
&lt;li&gt;GitHub Copilot CLI (&lt;code&gt;copilot&lt;/code&gt; command available in PATH)&lt;/li&gt;
&lt;li&gt;npm or yarn&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  My Experience with GitHub Copilot CLI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🎯 Why I Chose Copilot CLI
&lt;/h3&gt;

&lt;p&gt;I wanted to build something that showcased the &lt;strong&gt;real power&lt;/strong&gt; of GitHub Copilot CLI in a practical, business-ready application. Instead of a simple demo, I created a production-grade platform that makes AI-powered tools accessible to non-technical users.&lt;/p&gt;

&lt;h3&gt;
  
  
  💡 How I Used Copilot CLI
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Direct Process Execution&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The marketplace executes Copilot CLI commands directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;exec&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`copilot prompt -m "&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="s2"&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;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Capture and display output in real-time&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. &lt;strong&gt;Custom Prompts for Each Plugin&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Each plugin sends tailored prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;README Plugin&lt;/strong&gt;: "Create a comprehensive README.md"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commit Summarizer&lt;/strong&gt;: "Analyze recent commits and create changelog"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Generator&lt;/strong&gt;: "Generate comprehensive test cases"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository Review&lt;/strong&gt;: "Perform detailed code review"&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. &lt;strong&gt;Real-Time Output Streaming&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Users see results appear in a terminal-style interface as Copilot CLI processes the prompt.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 Impact on Development Experience
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Dramatically Improved&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Accessibility&lt;/strong&gt;: Non-terminal users can now leverage Copilot CLI&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;User Experience&lt;/strong&gt;: Beautiful, responsive interface with real-time feedback&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Scalability&lt;/strong&gt;: Easy to add new plugins without modifying core code&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Safety&lt;/strong&gt;: Robust error handling and security validation&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Speed&lt;/strong&gt;: 2-minute startup, plugin execution in seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What Copilot CLI Enabled&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Documentation Generation&lt;/strong&gt; - Copilot creates professional README files instantly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Changelog Creation&lt;/strong&gt; - Analyzes git history and generates summaries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Case Creation&lt;/strong&gt; - Suggests comprehensive test coverage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Review&lt;/strong&gt; - Provides architectural and quality recommendations&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  🎓 Learning Journey
&lt;/h3&gt;

&lt;p&gt;Building this project taught me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to safely integrate CLI tools into web applications&lt;/li&gt;
&lt;li&gt;Best practices for process management and error handling&lt;/li&gt;
&lt;li&gt;Creating extensible plugin architectures&lt;/li&gt;
&lt;li&gt;Security hardening against command injection&lt;/li&gt;
&lt;li&gt;Next.js App Router and modern React patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⚡ Performance &amp;amp; Scale
&lt;/h3&gt;

&lt;p&gt;The marketplace is optimized for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;30-second timeout&lt;/strong&gt; on executions (prevents hanging)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;10MB output buffer&lt;/strong&gt; (handles large outputs safely)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time streaming&lt;/strong&gt; (users see progress immediately)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error resilience&lt;/strong&gt; (graceful degradation on failures)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔐 Security Considerations
&lt;/h3&gt;

&lt;p&gt;I implemented multiple layers of protection:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Whitelist Validation&lt;/strong&gt; - Only registered plugins can execute&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No User Input&lt;/strong&gt; - Prompts are hardcoded per plugin&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Process Isolation&lt;/strong&gt; - Child processes are contained&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buffer Limits&lt;/strong&gt; - Prevents memory exhaustion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Containment&lt;/strong&gt; - Safe error messages without data leakage&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  💬 Why This Matters
&lt;/h3&gt;

&lt;p&gt;GitHub Copilot CLI is a game-changer for developers, but it lives in the terminal. By creating this marketplace, I've shown that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copilot CLI can power sophisticated web applications&lt;/li&gt;
&lt;li&gt;AI tools don't need to be complex - they can be beautifully simple&lt;/li&gt;
&lt;li&gt;Teams can standardize on AI-assisted workflows&lt;/li&gt;
&lt;li&gt;Security and usability aren't mutually exclusive&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📊 Project Highlights
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Build Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;3 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dev Start&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~5 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Load&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;500ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TypeScript Coverage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security Issues&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0 vulnerabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Plugins&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4 pre-built + extensible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5 comprehensive guides&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🎯 Perfect For
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🏆 Hackathon showcase&lt;/li&gt;
&lt;li&gt;📚 Portfolio projects&lt;/li&gt;
&lt;li&gt;👥 Team productivity tools&lt;/li&gt;
&lt;li&gt;🔬 Learning modern web development&lt;/li&gt;
&lt;li&gt;💼 Enterprise tool templates&lt;/li&gt;
&lt;li&gt;🤖 AI/ML demonstrations&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/longphanquangminh/copilot-plugin-marketplace/blob/master/README.md" rel="noopener noreferrer"&gt;Full Project README&lt;/a&gt;&lt;/strong&gt; - Complete documentation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/longphanquangminh/copilot-plugin-marketplace/blob/master/QUICKSTART.md" rel="noopener noreferrer"&gt;Quick Start Guide&lt;/a&gt;&lt;/strong&gt; - Get running in 2 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/longphanquangminh/copilot-plugin-marketplace/blob/master/SETUP.md" rel="noopener noreferrer"&gt;Setup Instructions&lt;/a&gt;&lt;/strong&gt; - Detailed installation guide&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/longphanquangminh/copilot-plugin-marketplace/blob/master/EXAMPLES.md" rel="noopener noreferrer"&gt;Usage Examples&lt;/a&gt;&lt;/strong&gt; - Plugin usage scenarios&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/longphanquangminh/copilot-plugin-marketplace" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🙏 Special Thanks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/github/cli" rel="noopener noreferrer"&gt;GitHub Copilot CLI&lt;/a&gt; - The powerful backbone&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; - Modern web framework&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tailwindcss.com" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt; - Beautiful styling&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://react.dev" rel="noopener noreferrer"&gt;React 19&lt;/a&gt; - Latest React features&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎉 Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;This project demonstrates how GitHub Copilot CLI can be integrated into real-world applications to create tangible value. By combining security, usability, and powerful AI capabilities, we can build tools that help developers work smarter, not harder.&lt;/p&gt;

&lt;p&gt;The marketplace is ready to use, extend, and deploy. Whether you're a developer looking to learn Next.js or a team seeking to streamline your workflow, this project provides a solid foundation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks for checking out my submission for the GitHub Copilot CLI Challenge!&lt;/strong&gt; 🚀&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with ❤️ using Next.js, TypeScript, TailwindCSS, and GitHub Copilot CLI&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>🍔 FoodSnap Tutor – Snap a meal, get a recipe (Gemini 2.5 Flash)</title>
      <dc:creator>Minh Long</dc:creator>
      <pubDate>Mon, 15 Sep 2025 06:30:40 +0000</pubDate>
      <link>https://dev.clauneck.workers.dev/minhlong2605/foodsnap-tutor-snap-a-meal-get-a-recipe-gemini-25-flash-10lo</link>
      <guid>https://dev.clauneck.workers.dev/minhlong2605/foodsnap-tutor-snap-a-meal-get-a-recipe-gemini-25-flash-10lo</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.clauneck.workers.dev/challenges/google-ai-studio-2025-09-03"&gt;Google AI Studio Multimodal Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;FoodSnap Tutor is a frontend-only app that turns any food photo into instant cooking guidance. Upload an image and the app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detects whether the image is food&lt;/li&gt;
&lt;li&gt;Identifies the likely dish name (with alternatives when uncertain)&lt;/li&gt;
&lt;li&gt;Generates a step-by-step recipe&lt;/li&gt;
&lt;li&gt;Estimates nutrition per serving (calories, protein, carbs, fat)&lt;/li&gt;
&lt;li&gt;Suggests a healthier variation and friendly moderation tips&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tech stack: React 19, TypeScript, Vite 6, Tailwind (CDN), and &lt;strong&gt;@google/genai&lt;/strong&gt; calling Gemini 2.5 Flash. Everything runs in the browser — no backend required.&lt;/p&gt;

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

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/criJO6OhDY0"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Live demo: &lt;a href="https://foodsnap-tutor.vercel.app" rel="noopener noreferrer"&gt;https://foodsnap-tutor.vercel.app&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Youtube video demo: &lt;a href="https://youtu.be/criJO6OhDY0" rel="noopener noreferrer"&gt;https://youtu.be/criJO6OhDY0&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Github repository: &lt;a href="https://github.com/longphanquangminh/foodsnap-tutor" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/foodsnap-tutor&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Screenshots:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✨ Upload screen:&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2Fmq026e8s8rio4rgp9fvl.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.amazonaws.com%2Fuploads%2Farticles%2Fmq026e8s8rio4rgp9fvl.png" alt="Upload screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✨ Analysis screen:&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2F4f3elmz0j1yvgpia73ca.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.amazonaws.com%2Fuploads%2Farticles%2F4f3elmz0j1yvgpia73ca.png" alt="Analysis screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✨ Error screen:&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.amazonaws.com%2Fuploads%2Farticles%2Ft8fxbxjsnz4rr2uan55v.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.amazonaws.com%2Fuploads%2Farticles%2Ft8fxbxjsnz4rr2uan55v.png" alt="Error screen"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How I Used Google AI Studio
&lt;/h2&gt;

&lt;p&gt;I leveraged the &lt;strong&gt;@google/genai&lt;/strong&gt; SDK to call Gemini 2.5 Flash with:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An inline &lt;strong&gt;image&lt;/strong&gt; part (base64-encoded upload).&lt;/li&gt;
&lt;li&gt;A structured &lt;strong&gt;prompt&lt;/strong&gt; telling the model to reply in JSON.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;response schema&lt;/strong&gt; so the SDK validates the output client-side.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenAI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/genai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Strict JSON schema&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OBJECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;isFood&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BOOLEAN&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;dishName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;recipe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OBJECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;ingredients&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;required&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;ingredients&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;steps&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="na"&gt;nutrition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OBJECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;calories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;protein&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;carbs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;fat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;required&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;calories&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;protein&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;carbs&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;fat&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="na"&gt;healthierVariation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;friendlyAdvice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;required&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;isFood&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;dishName&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;recipe&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;nutrition&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;healthierVariation&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="c1"&gt;// Convert upload to an image part&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileToPart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;dataUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rej&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;r&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;FileReader&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;readAsDataURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&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="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;res&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="nx"&gt;result&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rej&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dataUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/:&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;?)&lt;/span&gt;&lt;span class="sr"&gt;;/&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="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/jpeg&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;inlineData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mimeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;analyzeFoodImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&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;ai&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;GoogleGenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="o"&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;imagePart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fileToPart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&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;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You are FoodSnap Tutor, an expert AI chef and nutritionist...&lt;/span&gt;&lt;span class="dl"&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-2.5-flash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;imagePart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;text&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="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;responseMimeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;responseSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt;
    &lt;span class="p"&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&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;Environment wiring (Vite):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite.config.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loadEnv&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&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="o"&gt;=&amp;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;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loadEnv&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="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;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="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;define&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;process.env.API_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env.local
GEMINI_API_KEY=ai-xxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multimodal Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vision input:&lt;/strong&gt; Users upload a dish photo that the SDK sends as inline image data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured output:&lt;/strong&gt; Gemini returns validated JSON (recipe, nutrition, advice) for deterministic UI rendering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single multimodal call:&lt;/strong&gt; Image + text prompt → cohesive culinary analysis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UX touches:&lt;/strong&gt; Drag-and-drop upload, instant preview, animated results, retry flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robustness:&lt;/strong&gt; UI handles blocked content or JSON parse errors gracefully with friendly messages.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Notes&lt;br&gt;
• Frontend-only: In production restrict the API key to allowed origins or proxy requests through a lightweight backend.&lt;br&gt;
• Built with React + Vite + Tailwind for fast iteration and static deployment.&lt;/p&gt;

&lt;p&gt;Thanks for reading! If you’d like to try it out or peek at the code, check the demo and repo links above. 🚀&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>ai</category>
      <category>gemini</category>
    </item>
    <item>
      <title>🔭 Nocturne – A Blockchain Explorer for Midnight Network ⛓️</title>
      <dc:creator>Minh Long</dc:creator>
      <pubDate>Mon, 08 Sep 2025 06:29:22 +0000</pubDate>
      <link>https://dev.clauneck.workers.dev/minhlong2605/nocturne-a-blockchain-explorer-for-midnight-network-3041</link>
      <guid>https://dev.clauneck.workers.dev/minhlong2605/nocturne-a-blockchain-explorer-for-midnight-network-3041</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.clauneck.workers.dev/challenges/midnight-2025-08-20"&gt;Midnight Network "Privacy First" Challenge&lt;/a&gt; - Enhance the Ecosystem prompt&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Nocturne — Midnight Explorer&lt;/strong&gt; is a privacy-first block explorer for the Midnight Network &lt;strong&gt;testnet&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It solves two problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Visibility&lt;/strong&gt; – Developers need an easy way to inspect blocks, extrinsics and events on the new privacy chain without spinning up their own node or indexer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy &amp;amp; Security&lt;/strong&gt; – Traditional explorers embed analytics and permissive CSPs. Nocturne ships with a &lt;em&gt;strict&lt;/em&gt;, developer-friendly setup that respects user privacy out-of-the-box.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Key points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live data via &lt;code&gt;@polkadot/api&lt;/code&gt; WebSocket, no 3rd-party indexer required.&lt;/li&gt;
&lt;li&gt;Built with &lt;strong&gt;Next.js 15 App Router&lt;/strong&gt; + &lt;strong&gt;TypeScript&lt;/strong&gt; + &lt;strong&gt;Tailwind&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Dark theme, responsive, zero external fonts/analytics.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/longphanquangminh/midnight-explorer" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/midnight-explorer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://midnight-explorer-sand.vercel.app" rel="noopener noreferrer"&gt;https://midnight-explorer-sand.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Screen&lt;/th&gt;
&lt;th&gt;Preview&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Home – Latest blocks &amp;amp; txs&lt;/td&gt;
&lt;td&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.amazonaws.com%2Fuploads%2Farticles%2F14t49nwyjqngt7u5blth.png" alt="Home screenshot" width="800" height="537"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block list with paging&lt;/td&gt;
&lt;td&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.amazonaws.com%2Fuploads%2Farticles%2Fjk8vt4sv6220bpnmmptd.png" alt="Blocks screenshot" width="800" height="799"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transaction detail&lt;/td&gt;
&lt;td&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.amazonaws.com%2Fuploads%2Farticles%2Fulf7dndoq2e4pizbiuyg.png" alt="Tx screenshot" width="800" height="280"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How I Used Midnight's Technology
&lt;/h2&gt;

&lt;p&gt;Midnight Explorer connects directly to the &lt;strong&gt;Midnight RPC endpoint&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
It uses methods such as:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;chain_getBlockHash&lt;/code&gt; → to get block hashes
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chain_getBlock&lt;/code&gt; → to fetch full block details
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chain_getHeader&lt;/code&gt; → to check block headers and metadata
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By calling these RPC endpoints, the explorer can dynamically list new blocks and transactions without needing a centralized backend.&lt;/p&gt;

&lt;p&gt;This demonstrates how to integrate with Midnight’s Substrate-based architecture while keeping everything privacy-first and user-friendly.&lt;/p&gt;

&lt;p&gt;As I mentioned before, Midnight is Substrate-based, so I connected directly to the &lt;strong&gt;public testnet RPC&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApiPromise&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WsProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@polkadot/api&lt;/span&gt;&lt;span class="dl"&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;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ApiPromise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;provider&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;WsProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wss://rpc.testnet-02.midnight.network&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blocks:&lt;/strong&gt; &lt;code&gt;api.rpc.chain.getBlock(hash)&lt;/code&gt; and header queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transactions:&lt;/strong&gt; Iterated extrinsics + &lt;code&gt;system.events&lt;/code&gt; to derive success / failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tip height:&lt;/strong&gt; &lt;code&gt;api.rpc.chain.getFinalizedHead()&lt;/code&gt; → header.number.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the Polkadot API loads WASM crypto that calls &lt;code&gt;WebAssembly.instantiate&lt;/code&gt;, I extended the Content-Security-Policy with &lt;code&gt;'wasm-unsafe-eval'&lt;/code&gt; to keep things locked down yet functional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Experience Improvements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No need for manual RPC calls:&lt;/strong&gt; Developers can quickly inspect blocks without using &lt;code&gt;curl&lt;/code&gt; or custom scripts.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved debugging:&lt;/strong&gt; When building dApps on Midnight, seeing live transaction details in the explorer helps troubleshoot faster.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open source &amp;amp; extendable:&lt;/strong&gt; The codebase is kept simple so other developers can fork it and add features like search, account pages, or charts.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pain Point&lt;/th&gt;
&lt;th&gt;Nocturne’s Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hard to explore live data without indexer&lt;/td&gt;
&lt;td&gt;Direct node connection, lazy loaded singleton API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSP errors with WASM&lt;/td&gt;
&lt;td&gt;Pre-configured strict CSP allowing only what Polkadot needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pagination UX&lt;/td&gt;
&lt;td&gt;“Next” &lt;strong&gt;and&lt;/strong&gt; “Previous” buttons with offset cursors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boilerplate&lt;/td&gt;
&lt;td&gt;Scaffolded project with Tailwind, linting, TypeScript, ready-to-deploy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Set Up Instructions / Tutorial
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Clone &amp;amp; install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/YOUR_GH_ORG/midnight-explorer.git
&lt;span class="nb"&gt;cd &lt;/span&gt;midnight-explorer
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Configure environment
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;.env.local&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# optional – uses public RPC if omitted
NEXT_PUBLIC_RPC_URL=wss://rpc.testnet-02.midnight.network

# reserved for future indexer
NEXT_PUBLIC_INDEXER_URL=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Run locally
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;span class="c"&gt;# http://localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch the terminal for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connecting to Midnight RPC at wss://...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Build for production
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build     &lt;span class="c"&gt;# Turbopack compile&lt;/span&gt;
npm start         &lt;span class="c"&gt;# Next.js server on port 3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Deploy to Vercel
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Import the repo → Framework preset &lt;strong&gt;Next.js&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add the env vars above.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; – done!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Future Improvements
&lt;/h2&gt;

&lt;p&gt;While Midnight Explorer already provides basic block and transaction browsing, there are many directions to expand and improve the user experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full transaction details&lt;/strong&gt;: Show event logs, method calls, gas usage, and execution status for every transaction.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal transactions&lt;/strong&gt;: Support viewing internal calls (similar to RoninChain Explorer), so developers can trace contract-to-contract interactions and hidden flows inside a block.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich search functionality&lt;/strong&gt;: Enable search by block number, transaction hash, or account address.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Account pages&lt;/strong&gt;: Display balances, recent transactions, and contract code for each account.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Charts and statistics&lt;/strong&gt;: Add dashboards with real-time metrics like block time, TPS, gas consumption, and transaction volume.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better UX for developers&lt;/strong&gt;: Include copy-to-clipboard buttons for hashes/addresses, human-readable method names, and ABI decoding for contract calls.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy-first features&lt;/strong&gt;: Integrate Midnight’s unique privacy tech so that sensitive data can be hidden while still showing useful metadata (e.g., zk-proofs, shielded transactions).
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The long-term goal is to evolve Midnight Explorer into a &lt;strong&gt;comprehensive block explorer&lt;/strong&gt;, making it as powerful as established explorers like Etherscan or RoninChain Explorer, but optimized for Midnight’s privacy-first ecosystem.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;DEV username: &lt;code&gt;@minhlong2605&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thanks for reading &amp;amp; happy hacking on Midnight! 🌑🚀&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>midnightchallenge</category>
      <category>web3</category>
      <category>blockchain</category>
    </item>
  </channel>
</rss>
