<?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: Sriharsha Reddy Maddula</title>
    <description>The latest articles on DEV Community by Sriharsha Reddy Maddula (@sriharsha_reddy).</description>
    <link>https://dev.to/sriharsha_reddy</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%2F4158087%2Fe1e6676e-49cb-4a47-98ee-1ef3aab96d58.png</url>
      <title>DEV Community: Sriharsha Reddy Maddula</title>
      <link>https://dev.to/sriharsha_reddy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sriharsha_reddy"/>
    <language>en</language>
    <item>
      <title>I built my own operating system that runs in the browser (NebulaOS)</title>
      <dc:creator>Sriharsha Reddy Maddula</dc:creator>
      <pubDate>Fri, 02 Oct 2026 16:58:57 +0000</pubDate>
      <link>https://dev.to/sriharsha_reddy/i-built-my-own-operating-system-that-runs-in-the-browser-nebulaos-2b3f</link>
      <guid>https://dev.to/sriharsha_reddy/i-built-my-own-operating-system-that-runs-in-the-browser-nebulaos-2b3f</guid>
      <description>&lt;p&gt;Most portfolios are a scroll of sections. Mine is an operating system.&lt;/p&gt;

&lt;p&gt;For Hack Club's WebOS 1 workshop I built NebulaOS, a personal OS that runs entirely in your browser. You boot it, open apps, drag windows around, lock the screen, and even type commands into a terminal to learn about me.&lt;/p&gt;

&lt;p&gt;👉 Try it: &lt;a href="https://maddulasriharsha.github.io/webos/" rel="noopener noreferrer"&gt;https://maddulasriharsha.github.io/webos/&lt;/a&gt; (no sign-in, no password) 👉 Code: &lt;a href="https://github.com/maddulasriharsha/webos" rel="noopener noreferrer"&gt;https://github.com/maddulasriharsha/webos&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8w9274oxu1q0madm2ogu.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%2F8w9274oxu1q0madm2ogu.png" alt=" " width="800" height="478"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqh06oq7dzgqyboft9ulr.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%2Fqh06oq7dzgqyboft9ulr.png" alt=" " width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What it can do&lt;br&gt;
Window manager: drag, resize, minimize, maximize, and snap to screen edges (drag to the left/right edge to half-tile, to the top to maximize). Open windows even survive a page refresh.&lt;br&gt;
Apps: About Me, Files, Terminal, Paint, Notes, Calculator, Snake, Settings.&lt;br&gt;
A shared virtual file system: browse it in the Files app, or use ls, cd, cat and tree in the Terminal. Both read the same data.&lt;br&gt;
Personalisation: 4 themes plus a wallpaper picker, including your own uploaded image.&lt;br&gt;
OS touches: boot sequence, lock screen, power menu (lock / restart / shut down), Spotlight search on Ctrl+Space, a right-click desktop menu, and toast notifications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdzc1ppokkub0vh7gq7l9.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%2Fdzc1ppokkub0vh7gq7l9.png" alt=" " width="800" height="478"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faya8m3taaeap81l2niyd.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%2Faya8m3taaeap81l2niyd.png" alt=" " width="800" height="478"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F337ls375vzdw76ut53xc.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%2F337ls375vzdw76ut53xc.png" alt=" " width="800" height="478"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdmzghkpnqgis6sho2280.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%2Fdmzghkpnqgis6sho2280.png" alt=" " width="800" height="478"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fefi5djrn18ify3ad1zq1.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%2Fefi5djrn18ify3ad1zq1.png" alt=" " width="800" height="478"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu0rwkt6fsq9lnddjgkx1.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%2Fu0rwkt6fsq9lnddjgkx1.png" alt=" " width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How it's built&lt;br&gt;
React, TypeScript and Vite, with no UI library. The core is small:&lt;/p&gt;

&lt;p&gt;Each open window is an object in state: { id, x, y, w, h, z, minimized }. Focusing a window just bumps its z.&lt;br&gt;
Dragging uses pointer events with setPointerCapture, so the drag keeps working even if the cursor moves faster than the window.&lt;br&gt;
Apps are plain React components registered in one list, so adding an app is one entry plus a component.&lt;br&gt;
Bugs that taught me something&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The whole OS went blank when I opened the Terminal. I'd written useEffect(() =&amp;gt; ref.current?.scrollIntoView(), [lines]). An arrow function without braces returns its value, and React treats a returned value as a cleanup function. In some browsers scrollIntoView returns something, and React crashed with "destroy is not a function". The fix was adding braces so the effect returns nothing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Snake's high score was always 0. The game loop lives in a useEffect that only re-runs on a new round, so the score state it read was a stale closure. I switched to a plain local counter inside the effect for the game logic and kept state only for display.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My window-snap preview refused to position correctly. I rendered the preview inside the window, but windows use backdrop-filter, which makes them the containing block for position: fixed children. The fix was lifting the preview into the app root.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Windows opened off-screen on phones. They started at a fixed x position wider than a 375px screen. Clamping new and restored windows to the viewport fixed it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What I'd add next&lt;br&gt;
A music player, a mini browser app, and real multi-desktop workspaces.&lt;/p&gt;

&lt;p&gt;Deploying it&lt;br&gt;
A small GitHub Actions workflow builds the Vite app and publishes it to GitHub Pages on every push. The one gotcha: the first run fails until you set Settings → Pages → Source to GitHub Actions, which is a settings switch rather than a code problem. I also set Vite's base to "./" so the site works from a subpath.&lt;/p&gt;

&lt;p&gt;Try it and tell me what to build next&lt;br&gt;
If you build your own, the WebOS workshop guide is at &lt;a href="https://jams.hackclub.com/batch/webOS" rel="noopener noreferrer"&gt;https://jams.hackclub.com/batch/webOS&lt;/a&gt;. I'd love to see yours, so drop a link in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>beginners</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
