<?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: nasir shahbaz</title>
    <description>The latest articles on DEV Community by nasir shahbaz (@nstechbytes).</description>
    <link>https://dev.to/nstechbytes</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%2F4090363%2F72ae754b-7a9c-4a6e-80ea-1d3aca17e004.png</url>
      <title>DEV Community: nasir shahbaz</title>
      <link>https://dev.to/nstechbytes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nstechbytes"/>
    <language>en</language>
    <item>
      <title>Check Your Laptop Battery Health with BatteryHealth. A Simple PowerShell Script</title>
      <dc:creator>nasir shahbaz</dc:creator>
      <pubDate>Fri, 04 Sep 2026 15:30:06 +0000</pubDate>
      <link>https://dev.to/nstechbytes/check-your-laptop-battery-health-with-batteryhealth-a-simple-powershell-script-5do1</link>
      <guid>https://dev.to/nstechbytes/check-your-laptop-battery-health-with-batteryhealth-a-simple-powershell-script-5do1</guid>
      <description>&lt;p&gt;Worried about your laptop battery degradation? &lt;strong&gt;BatteryHealth&lt;/strong&gt; is a lightweight PowerShell script that instantly reports your battery's actual health percentage, cycle count, and estimated runtime all by parsing Windows' built-in battery report.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repo:&lt;/strong&gt; &lt;a href="https://github.com/NSTechBytes/BatteryHealth" rel="noopener noreferrer"&gt;https://github.com/NSTechBytes/BatteryHealth&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Over time, laptop batteries degrade. But how do you know &lt;em&gt;how much&lt;/em&gt; your battery has degraded? You could dig through Windows settings, install third-party battery apps, or pay for specialized tools. Or... you could use this simple script that leverages Windows' own battery diagnostics.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;BatteryHealth&lt;/strong&gt; is a lightweight PowerShell script that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Generates Windows' official battery report (&lt;code&gt;powercfg /batteryreport&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;✅ Parses the HTML report to extract key metrics&lt;/li&gt;
&lt;li&gt;✅ Calculates &lt;strong&gt;battery health %&lt;/strong&gt; (Full Charge Capacity ÷ Design Capacity)&lt;/li&gt;
&lt;li&gt;✅ Displays cycle count and estimated battery life&lt;/li&gt;
&lt;li&gt;✅ Color-codes the results (green for healthy, yellow for fair, red for degraded)&lt;/li&gt;
&lt;li&gt;✅ Opens the full HTML report for detailed analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  No admin rights required. No external dependencies. Pure PowerShell.
&lt;/h3&gt;




&lt;h2&gt;
  
  
  What You'll See
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;===== Battery Health Report =====
Design Capacity:      64000 mWh
Full Charge Capacity: 58800 mWh
Cycle Count:          187
Battery Health:       91.9%

Estimated battery life (since OS install):
  At full charge:    8:30:22 (h:mm:ss)
  At design capacity: 9:15:45 (h:mm:ss)

Full HTML report saved at: C:\Users\YourName\AppData\Local\Temp\battery-report.html
Opening report in default browser...

Press any key to exit...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Download or clone the script:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://github.com/NSTechBytes/BatteryHealth.git&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BatteryHealth&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run it:&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;\BatteryHealth.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;View the results&lt;/strong&gt; in your console and the full HTML report in your browser.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Why This Script?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trustworthy:&lt;/strong&gt; Uses Microsoft's own recommended battery diagnostics tool (&lt;code&gt;powercfg&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast:&lt;/strong&gt; Runs in seconds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No bloat:&lt;/strong&gt; ~150 lines of well-commented PowerShell&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works everywhere:&lt;/strong&gt; Windows 10, Windows 11, any laptop with a battery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open source:&lt;/strong&gt; MIT licensed, fully transparent&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Battery Health Percentage
&lt;/h3&gt;

&lt;p&gt;Instantly know if your battery is still healthy (80%+), fair (50-79%), or degraded (&amp;lt;50%).&lt;/p&gt;

&lt;h3&gt;
  
  
  Robust HTML Parsing
&lt;/h3&gt;

&lt;p&gt;The script handles tricky edge cases like newlines inside HTML cells that could break naive regex patterns.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cycle Count Tracking
&lt;/h3&gt;

&lt;p&gt;See how many charge/discharge cycles your battery has gone through.&lt;/p&gt;

&lt;h3&gt;
  
  
  Estimated Runtime
&lt;/h3&gt;

&lt;p&gt;Get a realistic estimate of how long your laptop will run on battery since the OS was installed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beautiful Output
&lt;/h3&gt;

&lt;p&gt;Color-coded console output makes it easy to spot issues at a glance.&lt;/p&gt;




&lt;h2&gt;
  
  
  Use Cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;📊 &lt;strong&gt;Device health checks&lt;/strong&gt; before buying a used laptop&lt;/li&gt;
&lt;li&gt;🔋 &lt;strong&gt;Warranty claims&lt;/strong&gt; — get hard numbers to back them up&lt;/li&gt;
&lt;li&gt;💼 &lt;strong&gt;Corporate IT&lt;/strong&gt; — audit fleet battery health&lt;/li&gt;
&lt;li&gt;🛠️ &lt;strong&gt;Troubleshooting&lt;/strong&gt; — determine if slowdowns are battery-related&lt;/li&gt;
&lt;li&gt;📈 &lt;strong&gt;Personal tracking&lt;/strong&gt; — monitor your battery degradation over time&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Technical Details
&lt;/h2&gt;

&lt;p&gt;The script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calls &lt;code&gt;powercfg /batteryreport&lt;/code&gt; to generate an official Windows battery report&lt;/li&gt;
&lt;li&gt;Parses the HTML using regex to extract Design Capacity, Full Charge Capacity, and Cycle Count&lt;/li&gt;
&lt;li&gt;Calculates health percentage = (Full Charge ÷ Design Capacity) × 100&lt;/li&gt;
&lt;li&gt;Displays results with intelligent color-coding&lt;/li&gt;
&lt;li&gt;Opens the full report in your default browser for deep dives&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Star the repo&lt;/strong&gt; and give it a try:&lt;br&gt;
👉 &lt;a href="https://github.com/NSTechBytes/BatteryHealth" rel="noopener noreferrer"&gt;https://github.com/NSTechBytes/BatteryHealth&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Questions? Issues? PRs welcome!&lt;/p&gt;




&lt;h3&gt;
  
  
  About the Author
&lt;/h3&gt;

&lt;p&gt;Created by &lt;a href="https://github.com/NSTechBytes" rel="noopener noreferrer"&gt;nstechbytes&lt;/a&gt; a developer who believes in simple, practical tools.&lt;/p&gt;

&lt;h1&gt;
  
  
  powershell #windows #battery #scripting #devtools #opensoure
&lt;/h1&gt;

</description>
      <category>powershell</category>
      <category>windows</category>
      <category>scripting</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Built a Native Windows App That Writes Your Git Commit Messages With AI Here's How</title>
      <dc:creator>nasir shahbaz</dc:creator>
      <pubDate>Fri, 28 Aug 2026 12:46:57 +0000</pubDate>
      <link>https://dev.to/nstechbytes/i-built-a-native-windows-app-that-writes-your-git-commit-messages-with-ai-heres-how-45l4</link>
      <guid>https://dev.to/nstechbytes/i-built-a-native-windows-app-that-writes-your-git-commit-messages-with-ai-heres-how-45l4</guid>
      <description>&lt;h2&gt;
  
  
  AI Commit Generator: A Native Windows Desktop App That Writes Your Git Commits With AI
&lt;/h2&gt;

&lt;p&gt;You know that moment you've spent two hours debugging, the fix is finally in, and now you have to write a commit message. &lt;em&gt;Ugh.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;AI Commit Generator&lt;/strong&gt; to solve exactly that. It's a native Windows desktop app that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Grabs your &lt;code&gt;git diff&lt;/code&gt; (staged or unstaged)&lt;/li&gt;
&lt;li&gt;Sends it to an AI model (via OpenRouter or Google AI Studio)&lt;/li&gt;
&lt;li&gt;Returns a clean, conventional commit message&lt;/li&gt;
&lt;li&gt;Lets you copy it, edit it, regenerate it, or just &lt;strong&gt;commit and push&lt;/strong&gt; right there&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All in a 550×600 pixel window that lives in your system tray.&lt;/p&gt;

&lt;p&gt;Here's a breakdown of the architecture and the interesting technical decisions along the way.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tech Stack: C++ + WebView2
&lt;/h2&gt;

&lt;p&gt;The app is written in &lt;strong&gt;C++17&lt;/strong&gt; using &lt;strong&gt;Win32 APIs&lt;/strong&gt; and &lt;strong&gt;Microsoft Edge WebView2&lt;/strong&gt; for the UI. Yes, really C++ and web technologies coexisting in the same binary.&lt;/p&gt;

&lt;p&gt;The core idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;C++ handles the heavy lifting&lt;/strong&gt;: spawning &lt;code&gt;git&lt;/code&gt; processes, managing the system tray, reading/writing config, HTTP requests to GitHub for update checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebView2 handles the UI&lt;/strong&gt;: the entire interface is HTML/CSS/JS rendered inside an embedded Edge WebView2 control.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't a framework — it's raw Win32 &lt;code&gt;CreateWindowExW&lt;/code&gt;, a message loop, and &lt;code&gt;ICoreWebView2Controller&lt;/code&gt;. No Electron, no Tauri, no extra runtime dependencies beyond the Edge WebView2 runtime that ships with Windows 10/11.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why WebView2 and not a full web framework?
&lt;/h3&gt;

&lt;p&gt;I wanted a &lt;strong&gt;small, native-feeling Windows app&lt;/strong&gt;. Electron bundles Chromium (~150MB+). WebView2 uses the Edge runtime already installed on the user's machine. The result is a tiny installer (~2MB compressed).&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bridge Pattern: C++ ↔ JavaScript IPC
&lt;/h2&gt;

&lt;p&gt;The most interesting architectural piece is the &lt;strong&gt;Bridge&lt;/strong&gt; a C++ class that handles bidirectional communication between the WebView2 frontend and the native backend.&lt;/p&gt;

&lt;p&gt;Here's how it works:&lt;/p&gt;

&lt;h3&gt;
  
  
  JS → C++ (frontend calls native code)
&lt;/h3&gt;

&lt;p&gt;The JavaScript frontend calls &lt;code&gt;window.chrome.webview.postMessage()&lt;/code&gt; with a JSON-RPC-style message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"getGitDiff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"repoPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;projects&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;my-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"staged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The C++ &lt;code&gt;Bridge&lt;/code&gt; class receives this via &lt;code&gt;ICoreWebView2WebMessageReceivedEventHandler&lt;/code&gt;, parses the method name, dispatches to the appropriate handler, and sends a response back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;diff --git a/file.js b/file.js&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;n...&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Available RPC Methods
&lt;/h3&gt;

&lt;p&gt;The bridge exposes these native operations to the frontend:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getConfig&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read settings from &lt;code&gt;%APPDATA%\AiCommitGen\settings.json&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;setConfig&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write a config key-value pair&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;selectDirectory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open a native Win32 folder picker dialog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getGitDiff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run &lt;code&gt;git diff&lt;/code&gt; or &lt;code&gt;git diff --cached&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getGitLog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run &lt;code&gt;git log --oneline -10&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;commitAndPush&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run &lt;code&gt;git add -A&lt;/code&gt;, &lt;code&gt;git commit -m "..."&lt;/code&gt;, then &lt;code&gt;git push&lt;/code&gt; with retry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;checkForUpdates&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hit the GitHub Releases API for the latest version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;downloadUpdate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Download the installer exe and launch it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This RPC pattern means the JavaScript never directly executes shell commands — everything goes through the bridge, which validates inputs and handles errors cleanly.&lt;/p&gt;




&lt;h2&gt;
  
  
  The AI Integration: Two Providers, One Prompt
&lt;/h2&gt;

&lt;p&gt;The app supports two AI providers:&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenRouter
&lt;/h3&gt;

&lt;p&gt;Uses the standard OpenAI-compatible chat completions API. Supports models like GPT-4o, Claude 3.5 Haiku, Gemini Flash, and Llama 3.3.&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;res&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://openrouter.ai/api/v1/chat/completions&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&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="s1"&gt;Authorization&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="s1"&gt;Bearer &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&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="s1"&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HTTP-Referer&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="s1"&gt;https://github.com/ai-commit-generator&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;body&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="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&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;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;systemPrompt&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Recent commits:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s1"&gt;Git diff:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;...&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;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&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;h3&gt;
  
  
  Google AI Studio (Gemini)
&lt;/h3&gt;

&lt;p&gt;Uses the Gemini REST API directly, with special handling for thinking models:&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;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;maxOutputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&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;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thinkingConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;thinkingBudget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gemini-3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thinkingConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;thinkingLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MINIMAL&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;p&gt;I learned the hard way that Gemini 2.5 Flash with thinking enabled will eat your entire token budget on chain-of-thought before producing the actual commit message. Disabling thinking (&lt;code&gt;thinkingBudget: 0&lt;/code&gt;) for commit messages is a must.&lt;/p&gt;

&lt;h3&gt;
  
  
  The System Prompt
&lt;/h3&gt;

&lt;p&gt;The prompt that actually generates the commit message follows &lt;strong&gt;conventional commits&lt;/strong&gt; format:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are an expert at writing clear, concise git commit messages.&lt;br&gt;
Given a git diff and recent commit history, generate a fitting commit message.&lt;/p&gt;

&lt;p&gt;Rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use conventional commits format: type(scope): description&lt;/li&gt;
&lt;li&gt;Types: feat, fix, chore, docs, style, refactor, perf, test, ci, build, revert&lt;/li&gt;
&lt;li&gt;Keep the subject line under 72 characters&lt;/li&gt;
&lt;li&gt;Focus on WHAT and WHY, not HOW&lt;/li&gt;
&lt;li&gt;Match the style of recent commits shown in the log&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The key insight: &lt;strong&gt;sending the last 10 commits as context&lt;/strong&gt; helps the AI match the existing commit style of the project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Smart Git Operations
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;commitAndPush&lt;/code&gt; handler does more than just run commands — it has real-world resilience built in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Push with retry for transient server errors&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&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="kt"&gt;int&lt;/span&gt; &lt;span class="n"&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="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&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="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;pushRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RunCmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;L"git push"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repoPath&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="n"&gt;pushRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exitCode&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="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Retry on 500/502/503 errors&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pushRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;L"500"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;wstring&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;npos&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="n"&gt;pushRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;L"502"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;wstring&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;npos&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="n"&gt;pushRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;L"503"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;wstring&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;npos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&gt;// Exponential backoff&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;break&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;It also detects "nothing to commit" gracefully, handles "Everything up-to-date", and distinguishes between commit failures and push failures so you know exactly what went wrong.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Window Plumbing
&lt;/h2&gt;

&lt;p&gt;Setting up a Win32 window with WebView2 is surprisingly involved. Here's the rough lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;WINAPI&lt;/span&gt; &lt;span class="nf"&gt;WinMain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HINSTANCE&lt;/span&gt; &lt;span class="n"&gt;hInstance&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="c1"&gt;// 1. Register window class with dark background&lt;/span&gt;
    &lt;span class="n"&gt;wc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hbrBackground&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CreateSolidBrush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RGB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;RegisterClassExW&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Create fixed-size window (no resize)&lt;/span&gt;
    &lt;span class="n"&gt;g_hWnd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CreateWindowExW&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="s"&gt;L"AiCommitGen"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...,&lt;/span&gt;
        &lt;span class="n"&gt;WS_OVERLAPPEDWINDOW&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;WS_MAXIMIZEBOX&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;WS_THICKFRAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Initialize system tray icon&lt;/span&gt;
    &lt;span class="n"&gt;InitTrayIcon&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. Create WebView2 with custom user data directory&lt;/span&gt;
    &lt;span class="n"&gt;CreateCoreWebView2EnvironmentWithOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userDataDir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;envOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;

    &lt;span class="c1"&gt;// 5. Use virtual host mapping to serve local files&lt;/span&gt;
    &lt;span class="n"&gt;webview3&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;SetVirtualHostNameToFolderMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;L"app.commitgen"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exeDir&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;L"&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;web"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND_DENY_CORS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;g_webview&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;L"https://app.commitgen/index.html"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 6. Message loop&lt;/span&gt;
    &lt;span class="n"&gt;MSG&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetMessageW&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;nullptr&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;TranslateMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;DispatchMessageW&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;msg&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;p&gt;One subtle detail: &lt;strong&gt;virtual host mapping&lt;/strong&gt; (&lt;code&gt;SetVirtualHostNameToFolderMapping&lt;/code&gt;) is used instead of navigating to &lt;code&gt;file://&lt;/code&gt; directly. This avoids the &lt;code&gt;file://&lt;/code&gt; origin restrictions in WebView2 and gives the frontend a proper &lt;code&gt;https://&lt;/code&gt; origin for CORS and security features.&lt;/p&gt;




&lt;h2&gt;
  
  
  System Tray: The Unsung UX
&lt;/h2&gt;

&lt;p&gt;The close button doesn't actually close the app — it hides to the system tray. This is intentional: commit messages are most useful when the app is always one double-click away.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;WM_CLOSE&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="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;g_isQuitting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;g_webviewController&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;put_IsVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ShowWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hWnd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SW_HIDE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Don't destroy — just hide&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tray icon supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Double-click&lt;/strong&gt; to restore&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Right-click&lt;/strong&gt; menu with Open and Exit options&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Start hidden in tray"&lt;/strong&gt; option for power users who want it always available but never visible&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Auto-Update System
&lt;/h2&gt;

&lt;p&gt;The app checks GitHub Releases on startup. The update flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;C++ sends a WinHTTP request to &lt;code&gt;github.com/NSTechBytes/ai-commit-generator/releases/latest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Parses the redirect to extract the tag name&lt;/li&gt;
&lt;li&gt;Compares versions in JavaScript using a semver comparison&lt;/li&gt;
&lt;li&gt;If a newer version exists, downloads the installer exe and launches it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The version is embedded in the Windows executable's &lt;code&gt;VS_FIXEDFILEINFO&lt;/code&gt; resource and read at runtime:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;wstring&lt;/span&gt; &lt;span class="nf"&gt;GetApplicationVersion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... reads VS_FIXEDFILEINFO from the running .exe&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;L"1.1.0"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AiCommitGen.sln              # Visual Studio solution
AiCommitGen/
  main.cpp                   # Win32 entry point + WebView2 init
  bridge.h / bridge.cpp      # C++ ↔ JS RPC bridge
  web/
    index.html               # UI (single-page, all CSS inline)
    index.js                 # Frontend logic (~400 lines)
    assets/                  # Icons, images
installer/
  setup.nsi                  # NSIS installer script
  setup.ps1                  # Release build + installer pipeline
Build.ps1                    # Debug/Release build script
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows 10/11&lt;/li&gt;
&lt;li&gt;Visual Studio 2022 (Desktop development with C++)&lt;/li&gt;
&lt;li&gt;WebView2 Runtime (comes with Windows)&lt;/li&gt;
&lt;li&gt;NSIS (for building the installer)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Build:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Debug build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;/Build.ps1&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Release + Installer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;/setup.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Configuration:&lt;/strong&gt; API keys and settings are stored in &lt;code&gt;%APPDATA%\AiCommitGen\settings.json&lt;/code&gt;.&lt;/p&gt;




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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WebView2 is surprisingly capable.&lt;/strong&gt; It's basically a modern IE/Edge control that renders Chromium content. The virtual host mapping feature alone makes it viable for local-file apps.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;JSON parsing in C++ without libraries is tedious.&lt;/strong&gt; I wrote a custom &lt;code&gt;JsonGetString&lt;/code&gt; / &lt;code&gt;ParseFlatStringObject&lt;/code&gt; implementation. It works for flat config files, but I wouldn't recommend it for nested JSON.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Git commands through &lt;code&gt;CreateProcessW&lt;/code&gt; need careful pipe management.&lt;/strong&gt; Redirecting stdout/stderr through Win32 pipes, then reading from the read end until EOF, is a pattern that looks simple but has subtle gotchas around handle inheritance and buffer sizes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conventional commits + recent commit history = better AI output.&lt;/strong&gt; Sending the last 10 commits as context makes the AI match the project's actual style, not just a generic format.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;The app is open source on GitHub: &lt;strong&gt;&lt;a href="https://github.com/NSTechBytes/ai-commit-generator" rel="noopener noreferrer"&gt;NSTechBytes/ai-commit-generator&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Install the latest release, paste your OpenRouter or Google AI Studio API key, select a repo, and hit Generate. It's the fastest way I've found to go from "I have no idea what to call this commit" to a clean push.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with C++17, Win32, WebView2, and a healthy impatience for writing commit messages.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>windows</category>
      <category>ai</category>
      <category>git</category>
      <category>cpp</category>
    </item>
    <item>
      <title>Novadesk: Build Desktop Widgets with JavaScript and C++ Power</title>
      <dc:creator>nasir shahbaz</dc:creator>
      <pubDate>Wed, 26 Aug 2026 04:17:15 +0000</pubDate>
      <link>https://dev.to/nstechbytes/novadesk-build-desktop-widgets-with-javascript-and-c-power-3631</link>
      <guid>https://dev.to/nstechbytes/novadesk-build-desktop-widgets-with-javascript-and-c-power-3631</guid>
      <description>&lt;h2&gt;
  
  
  Novadesk: Build Desktop Widgets with JavaScript and C++ Power
&lt;/h2&gt;

&lt;p&gt;Hey dev community! 👋&lt;/p&gt;

&lt;p&gt;I'm excited to share &lt;strong&gt;Novadesk&lt;/strong&gt; - an open-source desktop widget platform that combines C++ performance with JavaScript simplicity.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Novadesk?
&lt;/h2&gt;

&lt;p&gt;Novadesk lets you create custom desktop widgets, system monitors, and desktop enhancements using familiar JavaScript syntax, while leveraging a powerful C++ rendering engine underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  Default Widget
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;I've always been fascinated by desktop customization, but existing solutions felt limited. Rainmeter required learning a custom language, Electron widgets were too heavy, and most options lacked proper system integration.&lt;/p&gt;

&lt;p&gt;I wanted something different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance matters.&lt;/strong&gt; Desktop widgets run 24/7. I didn't want something eating RAM and CPU in the background. C++ with Direct2D gives us native speed with smooth animations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;JavaScript should be enough.&lt;/strong&gt; Why force developers to learn a new language? If you know JS, you should be able to build a widget. QuickJS made this possible without the overhead of Node.js.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;System access shouldn't be painful.&lt;/strong&gt; Getting CPU usage, battery stats, or disk info shouldn't require hacks. I built native APIs so widgets can access system data cleanly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Open source wins.&lt;/strong&gt; The desktop customization community thrives on sharing. I wanted a platform where anyone could contribute widgets, improvements, and new features.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building Novadesk taught me more about C++, Windows APIs, and software architecture than any course ever could. It started as a personal project to monitor my system stats, and grew into something the community can use and extend.&lt;/p&gt;

&lt;p&gt;If you've ever wanted to build desktop tools but felt limited by existing options, give Novadesk a try. I'd love to see what you create.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Dual-Language Architecture:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;C++ Core:&lt;/strong&gt; High-performance rendering with Direct2D, window management, and system APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript Widgets:&lt;/strong&gt; Easy-to-write widget logic using QuickJS engine&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seamless Bridge:&lt;/strong&gt; Native bindings for UI manipulation, animations, and system access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rich UI Elements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text, Images, Buttons, Bitmaps&lt;/li&gt;
&lt;li&gt;Data visualization: Bars, Histograms, Area Graphs, Rotators&lt;/li&gt;
&lt;li&gt;Shape primitives: Rectangles, Ellipses, Lines, Arcs, Paths, Curves&lt;/li&gt;
&lt;li&gt;Layout system with borders, shadows, and scrollable containers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Powerful APIs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System monitoring: CPU, Memory, Battery, Disk&lt;/li&gt;
&lt;li&gt;File system operations&lt;/li&gt;
&lt;li&gt;Clipboard access&lt;/li&gt;
&lt;li&gt;Web fetching&lt;/li&gt;
&lt;li&gt;Registry operations&lt;/li&gt;
&lt;li&gt;Environment variables&lt;/li&gt;
&lt;li&gt;Command execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Animation System:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smooth easing functions&lt;/li&gt;
&lt;li&gt;Keyframe animations&lt;/li&gt;
&lt;li&gt;Property interpolation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Developer Tools:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nwm&lt;/code&gt; CLI for project initialization, running, and building&lt;/li&gt;
&lt;li&gt;Widget packaging (&lt;code&gt;.ndpkg&lt;/code&gt; format)&lt;/li&gt;
&lt;li&gt;Built-in widget manager GUI&lt;/li&gt;
&lt;li&gt;Comprehensive test suite&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Example
&lt;/h2&gt;

&lt;p&gt;Creating a widget is as simple as:&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;// index.js&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;widgetWindow&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;novadesk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;myWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;widgetWindow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;myWindow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ui/script.ui.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ffffffff&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ui/script.ui.js&lt;/span&gt;
&lt;span class="nx"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addText&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello_Text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;200&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fontColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fontWeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fontFace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Arial&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;centercenter&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;h2&gt;
  
  
  Architecture Highlights
&lt;/h2&gt;

&lt;p&gt;The project uses a layered architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scripting Layer:&lt;/strong&gt; QuickJS engine with custom modules for widget UI, system access, and file operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain Layer:&lt;/strong&gt; Widget management, desktop integration, animation engine&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render Layer:&lt;/strong&gt; Direct2D-powered rendering with element hierarchy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared Layer:&lt;/strong&gt; Settings, logging, utilities, and system APIs&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows OS&lt;/li&gt;
&lt;li&gt;Visual Studio 2022 with C++ Desktop Development&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Setup:&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/Official-Novadesk/Novadesk.git
&lt;span class="nb"&gt;cd &lt;/span&gt;Novadesk
.&lt;span class="se"&gt;\S&lt;/span&gt;etup.ps1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Novadesk?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; C++ core ensures smooth 60fps animations and low resource usage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer Experience:&lt;/strong&gt; JavaScript syntax makes widget development accessible&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensible:&lt;/strong&gt; Easy to add new UI elements and APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Well-Tested:&lt;/strong&gt; 75+ integration tests covering all major features&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open Source:&lt;/strong&gt; GPLv3 licensed, community contributions welcome&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Official-Novadesk/novadesk" rel="noopener noreferrer"&gt;Official-Novadesk/novadesk&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://novadesk.pages.dev" rel="noopener noreferrer"&gt;novadesk.pages.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation:&lt;/strong&gt; &lt;a href="https://novadesk-docs.pages.dev" rel="noopener noreferrer"&gt;novadesk-docs.pages.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Patreon:&lt;/strong&gt; &lt;a href="https://www.patreon.com/c/officialnovadesk" rel="noopener noreferrer"&gt;Support the project&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Would love to hear your thoughts! What kind of widgets would you build with this? Any features you'd like to see added?&lt;/p&gt;

&lt;h1&gt;
  
  
  opensource #cpp #javascript #desktop #widgets #productivity #windows
&lt;/h1&gt;

</description>
      <category>opensource</category>
      <category>cpp</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I built a free open-source app that adds mechanical keyboard sounds system-wide on Windows</title>
      <dc:creator>nasir shahbaz</dc:creator>
      <pubDate>Sun, 23 Aug 2026 08:58:24 +0000</pubDate>
      <link>https://dev.to/nstechbytes/i-built-a-free-open-source-app-that-adds-mechanical-keyboard-sounds-system-wide-on-windows-2no1</link>
      <guid>https://dev.to/nstechbytes/i-built-a-free-open-source-app-that-adds-mechanical-keyboard-sounds-system-wide-on-windows-2no1</guid>
      <description>&lt;p&gt;Hey DEV community! 👋&lt;/p&gt;

&lt;p&gt;I just released &lt;strong&gt;MonkeySounds&lt;/strong&gt; a free, open-source Windows app that plays&lt;br&gt;
satisfying mechanical keyboard and mouse click sounds system-wide, for every&lt;br&gt;
application on your PC.&lt;/p&gt;

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



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

&lt;p&gt;I loved the browser extension that adds keyboard sounds while typing, but I&lt;br&gt;
wanted it everywhere not just in the browser. So I built a native Windows&lt;br&gt;
app in C++ that hooks directly into the input system.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🎹 Plays realistic mechanical switch sounds on every keystroke&lt;/li&gt;
&lt;li&gt;🖱️ Plays click sounds on every mouse button press&lt;/li&gt;
&lt;li&gt;🔇 Independent mute and volume control for keyboard and mouse&lt;/li&gt;
&lt;li&gt;🎨 Ships with 16 built-in profiles (Cherry MX Blue/Brown/Black,
Holy Panda, Alpaca, Typewriter, and more)&lt;/li&gt;
&lt;li&gt;🛠️ Create your own profiles from any audio files with the built-in wizard&lt;/li&gt;
&lt;li&gt;📦 Portable or installed your choice&lt;/li&gt;
&lt;li&gt;⚡ Zero performance impact runs silently in the system tray&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tech stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;C++ / Win32 API&lt;/li&gt;
&lt;li&gt;miniaudio (WASAPI backend)&lt;/li&gt;
&lt;li&gt;NSIS installer&lt;/li&gt;
&lt;li&gt;GitHub Actions for CI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🐙 GitHub: &lt;a href="https://github.com/NSTechBytes/MonkeySounds" rel="noopener noreferrer"&gt;https://github.com/NSTechBytes/MonkeySounds&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 Discord: &lt;a href="https://discord.gg/fZejMxtMhf" rel="noopener noreferrer"&gt;https://discord.gg/fZejMxtMhf&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;❤️ Patreon: &lt;a href="https://www.patreon.com/c/nstechbytes" rel="noopener noreferrer"&gt;https://www.patreon.com/c/nstechbytes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Would love to hear your feedback! What switch profile should I add next?&lt;/p&gt;

</description>
      <category>windows</category>
      <category>opensource</category>
      <category>cpp</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
