Ubuntu 24.04, tarayıcıda
Terminal, Files ve Text Editor'ün aynı sanal dosya sistemini paylaştığı bir GNOME 46 masaüstü.
Ubuntu 24.04 LTS masaüstünün (GNOME 46, Yaru, Ubuntu Dock) tarayıcıda çalışan bir kopyası. Terminal'de oluşturduğun dosya anında Files'ta beliriyor; çift tıklayınca Text Editor'de açılıyor, kaydedince de `cat` yeni içeriği gösteriyor.

- Durum
- Tamamlandı
- Kategori
- Tarayıcıda OS
- Güncelleme
- 5 Ekim 2026
- Yığın
- ReactTypeScriptBunZustandCodeMirror 6xterm.js
- Bağlantılar
- Kaynak kod
Ubuntu 24.04 LTS masaüstünün (GNOME 46, Yaru teması, Ubuntu Dock) tarayıcıda çalışan bir kopyası. En hoşuma giden yanı, bütün uygulamaların aynı sanal dosya sistemini paylaşması: Terminal'de oluşturduğun dosya Files'ta anında beliriyor, çift tıklayınca Text Editor'de açılıyor, kaydettikten sonra da cat yeni içeriği gösteriyor. Arka uç yok; her şey tarayıcıda çalışıyor ve localStorage'a kaydediliyor. Giriş ekranında istediğin parolayı yazabilirsin, hepsi kabul ediliyor.
Masaüstünde Files, Terminal, sekmeli Text Editor, Firefox, Calculator, Image Viewer, 12 panelli Settings, System Monitor, Clocks ve Mines var. Aramalı App Grid, alt menülü Quick Settings ve açık pencereleri gösteren Etkinlikler görünümü de çalışıyor. GNOME'un küçük davranışlarını da çalışır hale getirdim: sıcak köşe, Screen Blank ile otomatik kilit, kaçırılan bildirimleri sayan kilit ekranı, Always on Top ve Move to Workspace içeren pencere menüsü, yüzen dock modu, sürükle-bırak destekli Çöp ve ses ile parlaklık tuşları için ekran göstergesi. Tarayıcın destekliyorsa pil durumu Battery Status API'den okunuyor. İkonları da Yaru ikon temasının tarzında çizdim.
Her şey bir listeden okunuyor
Uygulamalar, dock, App Grid, arama, "Open With" menüsü ve MIME yönlendirmesi apps/registry.ts içindeki tek bir APPS listesinden besleniyor. Yeni bir uygulama eklemek için bu listeye bir kayıt ve bir bileşen dosyası yetiyor. Kısayollar da tek bir tabloda (os/keyboard.ts) duruyor; sağ tık menüleri ise tek bir ContextMenu bileşenine verilen düz diziler. Uygulamalar header bar yuvaları, diyaloglar, sekme şeritleri ve segmentli seçiciler gibi ortak parçaları shell/chrome.tsx içinden alıyor. Her uygulamanın etrafında bir hata sınırı var: çöken bir uygulama masaüstünü de beraberinde götürmüyor, yalnızca bir "has stopped" ekranı gösteriyor.
Mantığı da arayüzden ayırdım. VFS, bash benzeri kabuk, shunting-yard hesap makinesi, pencere geometrisi, Overview yerleşimi, Files'taki seçim ve sıralama, URL normalleştirme ve Mines oyunu düz fonksiyonlar halinde duruyor. Arayüz yalnızca bunları çağırıp sonucu store'a yazıyor.
Durumun tamamı os/store.ts içindeki tek bir zustand store'unda (VFS, ayarlar, bildirimler, oturum, menüler); pencere yöneticisi de os/windows.ts dilimi. Bunlardan yalnızca VFS, ayarlar, terminal geçmişi ve masaüstü ikon konumları kalıcı, onlar da version ve migrate ile. Depolama adaptörü kalıcı bir şey değişmediyse hiç yazmıyor, 5 MB sınırına yaklaşınca da uyarıyor. IndexedDB'ye geçmek istersem yalnızca os/storage.ts dosyasını değiştirmem yetecek.
Pencereler ve sürükleme
Pencere taşıma ve boyutlandırma, ikon sürükleme ve dikdörtgen seçim, os/useDragResize.ts içindeki aynı track() fonksiyonunu kullanıyor. İşaretçiyi ancak sürükleme eşiği aşılınca yakalıyorum. Bu sayede düz tıklamalar başlık çubuğundaki düğmelere ulaşabiliyor; yakalandıktan sonra da hareket, iframe'lerin ve terminallerin üzerinden geçerken kopmuyor. Sürükleme boyunca yalnızca CSS transform değişiyor, store'a ancak pointerup anında yazılıyor.
Her pencerenin rect alanı her zaman normal geometriyi tutuyor; büyütülmüş ve kenara yaslanmış haller bundan türetiliyor. Küçültülen pencereler mount'lu kalıyor, bu yüzden ne terminal geçmişi ne de editörün geri alma geçmişi kayboluyor. Masaüstü ikonları sütun öncelikli bir ızgaraya diziliyor. Tıklayarak, Ctrl+tıklayarak ya da dikdörtgen çizerek seçtiğin ikonları topluca boş hücrelere, Çöp'e ya da bir klasöre sürükleyebilirsin. İlk sürüklemede bütün ikonların hücresi kaydediliyor, böylece hiçbiri yerinden kaymıyor.
Ağır parçaları sonraya bırakmak
Her uygulama lazy() ile yükleniyor. CodeMirror 6 (yaklaşık 670 KB) ve xterm.js (yaklaşık 490 KB) ancak Text Editor ya da Terminal açıldığında iniyor. Terminalde xterm'in WebGL eklentisini kullanıyorum, çünkü DOM renderer Ubuntu Mono karakterlerini yanlış ölçüp sütunları kaydırıyordu; bu, neofetch çıktısında açıkça göze batıyordu. WebGL her karakteri kendi hücresine çiziyor; desteklenmiyorsa DOM'a geri dönülüyor.
Bun'ın CSS bundler'ı her url()'i base64 olarak gömüyor. Bu yüzden build betiği woff2 fontları yeniden ayrı dosyalara çıkarıyor; tarayıcı da unicode-range sayesinde yalnızca sayfanın kullandığı alt kümeleri indiriyor. Dosyalar build sırasında gzip'leniyor, istemci kabul ediyorsa .gz kopyası gönderiliyor. Hash'li dosyalar bir yıl boyunca immutable olarak önbellekte kalıyor, index.html ise her yüklemede yeniden doğrulanıyor. Kodlanmış .. içeren yollar 400 dönüyor; source map'ler de imaja girmiyor.
Tarayıcının izin vermediği yerler
Bazı sınırları tarayıcı koyuyor. Google, GitHub, MDN ve ubuntu.com gibi birçok site X-Frame-Options ya da CSP frame-ancestors gönderdiği için Firefox penceresindeki iframe'de açılmıyor; onlar için "Open in New Tab" seçeneği olan bir hata sayfası çıkıyor. Ana sayfaya ve yer imlerine de bu yüzden yalnızca gömülmeye izin verdiği doğrulanmış siteleri (Wikipedia, OpenStreetMap, Internet Archive, Hacker News gibi) koydum. Super, Alt+Tab ve Alt+F4 gibi tuşları da işletim sistemi ya da tarayıcı yakalayabiliyor. Tam ekranda Chromium'un Keyboard Lock API'si bu tuşları sayfaya iletiyor; ayrıca her kısayolun çakışmayan bir alternatifi Settings › Keyboard'da listeleniyor.
Birkaç küçük sınır daha var. localStorage yaklaşık 5 MB olduğu için data URL olarak saklanan büyük görseller alanı çabuk dolduruyor. Terminalin satır editörü, komutun tek satıra sığdığını varsayıyor. Dolu bir hücreye bıraktığın ikon da olduğu yerde kalıyor; Ubuntu'nun masaüstü ikonları (DING) olsa onu bir sonraki boş hücreye iterdi.