BapsOS: Windows 98, ombyggt i en webbläsarflik

En Windows 98-simulator med ett skal som heter Fen98 och 27 fungerande applikationer, körd på en Patil Pentium II på 400 MHz med 128,0 MB RAM.

Kund
Nuits
År
2026
Status
Live
Roll
Ensam grundare, Produktdesign, Utveckling
Teknik
TanStack Start, React 19, Vite, Zustand, Radix UI, Framer Motion, TipTap, Lucide, use-sound, @use-gesture, Microsoft Clarity, Cloudflare
BapsOS: Windows 98, ombyggt i en webbläsarflik
27
fungerande applikationer

Bakgrund

BapsOS är en Windows 98-simulator som körs i en webbläsarflik. Den har ett namngivet skal, Fen98, en fullständig uppstartssekvens, en avstängningssekvens och 27 applikationer som faktiskt fungerar i stället för att öppna en bild av sig själva.

Dialogrutan Systemegenskaper rapporterar en Patil Pentium II på 400 MHz med 128,0 MB RAM. Ingen av den hårdvaran existerar. Dialogrutan är säker på sin sak.

Problemet

Retroskrivbord på webben är nästan alltid skärmdumpar med hovertillstånd. Du klickar på Start, en meny dyker upp, du klickar på Minröj och får en platshållare eller en länk till någon annans Minröj. Illusionen kollapsar vid andra klicket, eftersom det första klicket är det enda någon har testat.

Det som fick ett skrivbordsoperativsystem att kännas som en plats var inte bakgrundsbilden. Det var att allt levde samtidigt. Du kunde ha ett dokument öppet bakom ett spel bakom en kontrollpanel, dra ett fönster halvvägs utanför skärmen, minimera det och hitta det i aktivitetsfältet där du lämnade det. Djupet var produkten.

Så frågan var om jag kunde bygga djupet i stället för skärmdumpen, ensam, i en webbläsare.

Min roll

Ensam. Produktdesign och utveckling, alla 27 appar, skalet, fönsterhanteraren, ljuddesignen, den påhittade hårdvaruspecifikationen.

Designhalvan handlar inte om att pixelmatcha fönsterramar, även om det förekommer. Den handlar om systemdesignen under ytan: vad ett fönster är, vad en applikation är, hur skalet startar en, hur tillstånd bevaras och hur allt det där håller ihop över 27 saker byggda under flera månader. Gör du fel där blir den tjugonde appen en omskrivning av den första.

Angreppssätt

Jag byggde fönsterhanteraren innan jag byggde någon applikation, och jag vägrade skriva en app innan ett fönster kunde öppnas, fokuseras, dras, storleksändras, minimeras, maximeras, återställas och stängas korrekt. Det är oglamoröst arbete utan något att visa upp på flera veckor, och det är hela anledningen till att projektet blev klart.

När ett fönster väl är en löst primitiv är en applikation bara innehåll plus ett manifest. Minröj, Tetris, Snake, en TipTap-redigerare med formaterad text, ett kalkylblad med fungerande formler, en AI-chatt, Paint, en webbkameraapp, Aktivitetshanteraren, Kontrollpanelen och resten kopplar alla in i samma kontrakt. Den tjugosjunde tog en eftermiddag. Den första tog en månad.

Den påhittade hårdvaran och uppstartssekvensen är samma beslut som fönsterhanteraren, fast på tonläget. En simulator som startar direkt är en webbsida. En simulator som ägnar några sekunder åt att räkna inbillat minne är en maskin.

Så byggde jag det

TanStack Start med React 19, byggt av Vite, driftsatt på Cloudflare. Allt körs på klienten. Det finns ingen server, inget konto och ingen databas, vilket är det som gör att den inte kostar något att hosta och laddar snabbt från kanten av nätet.

Zustand håller hela systemtillståndet och sparar det i localStorage. Det är den biten som får det att kännas som ett operativsystem i stället för en sida. Öppna fönster, deras positioner, deras z-ordning, din Paint-duk, ditt dokument, dina inställningar i Kontrollpanelen och din bakgrundsbild överlever alla en omladdning. Stäng fliken mitt i Tetris och kom tillbaka till samma bräde. Persistenslagret är versionerat, eftersom en schemaändring annars skulle deserialiseras till skräp hos varje återvändande besökare.

Fönsterhanteraren är en enda z-ordningsstack med fokus som härlett tillstånd i stället för en flagga sparad per fönster, vilket tog bort en hel kategori av buggar där två fönster båda trodde att de var fokuserade. Dragning och storleksändring går genom @use-gesture, med pointer events i stället för mouse events så att en telefon fungerar. Framer Motion animerar fönsterövergångar, minimering och återställning. Radix UI står för menyer och dialogrutor under retroskalet, vilket är det minst tidstrogna beslutet i projektet och anledningen till att Start-menyn går att navigera med tangentbord och är begriplig för en skärmläsare. Ett gränssnitt från 1998 med tillgänglighetsprimitiver från 2026 är en avvägning jag skulle göra igen.

Applikationerna bär sin egen vikt. TipTap är redigeraren. Kalkylbladet har en riktig formeltolk med cellreferenser och beroendeordnad omräkning, för ett kalkylblad som inte räknar är en tabell. AI-chatten strömmar tokens in i en tidstrogen textruta och är hastighetsbegränsad, eftersom ett oautentiserat publikt chattfönster är en räkning som väntar på att komma. Webbkameraappen använder getUserMedia lokalt och laddar inte upp någonting. Aktivitetshanteraren rapporterar processer som motsvarar öppna fönster, så att döda en stänger det.

use-sound sköter ljudet: uppstart, avstängning, felsignaler, klick. Lucide täcker ikoner utan tidstrogen motsvarighet. Microsoft Clarity är den enda analysen, och det finns en tilltalande symmetri i att Microsoft berättar för mig hur folk använder mitt Windows 98.

Resultat

Den ligger live på os.bapspatil.com med alla 27 applikationer i drift. Folk hittar den, förlorar en timme och berättar för mig att de hade exakt den maskinen.

Den blev också det mest återanvändbara jag byggt. Fönsterhanteraren, persistenslagret och appkontraktet är delar jag återkommer till.

Vad jag skulle göra annorlunda

Jag släppte Zustand-persistensen utan migreringsväg och fick lägga till versionering efter att riktiga människor hade riktigt tillstånd. Det borde ha legat i första commiten.

Jag skulle också ha skrivit appmanifestets kontrakt som en typ innan jag byggde app nummer två, i stället för att bryta ut det runt app nummer åtta. Apparna i mitten bär fortfarande formen av den övergången.