1 puan yazan GN⁺ 2026-03-29 | 1 yorum | WhatsApp'ta paylaş
  • Yalnızca CSS ile 3D DOOM render eden bir deney; tüm duvarlar ve nesneler <div> ile ve 3D dönüşümler (transform) kullanılarak oluşturulmuş bir proje
  • Oyun mantığını JavaScript üstleniyor, ancak render işlemi tamamen CSS tarafından yapılıyor; böylece tarayıcıların ve modern CSS'in sınırları araştırılıyor
  • Trigonometrik fonksiyonlar, clip-path, @property, SVG filtreleri, anchor positioning gibi modern CSS özellikleri kullanılarak duvarlar, zemin, ışıklandırma, sprite'lar ve patlama efektleri bile uygulanmış
  • CSS'te kamera kavramı olmadığından, bakış açısı oyuncu yerine dünyanın hareket ettirilmesi yöntemiyle işleniyor ve tüm hareketler özel özellik güncellemeleriyle kontrol ediliyor
  • WebGL düzeyinde performans sunmasa da, CSS'in ifade gücü ve hesaplama yeteneğinin genişletilebileceğini gösteren bir örnek

CSS ile 3D DOOM render etme

  • DOOM'u yalnızca CSS ile render eden deneysel bir proje; tüm duvarlar, zeminler ve nesneler <div> ile oluşturuluyor ve 3D dönüşümler (transform) ile yerleştiriliyor
    • Oyun mantığı JavaScript'te çalışıyor, ancak render işlemi tamamen CSS tarafından yapılıyor
    • Projenin amacı tarayıcıların ve modern CSS'in sınırlarını keşfetmek

Lise matematiğine geri dönmek

  • Orijinal DOOM'un WAD dosyası verileri (vertices, linedefs, sidedefs, sectors) çıkarılarak binlerce <div> ile statik sahne oluşturuluyor
  • Her duvarın başlangıç-bitiş koordinatları ile zemin-tavan yükseklikleri CSS özel özellikleri üzerinden aktarılıyor
  • hypot() ve atan2() CSS fonksiyonlarıyla duvar uzunluğu ve dönüş açısı hesaplanıyor
  • JavaScript ham veriyi iletiyor, CSS ise trigonometrik hesaplamaları yaparak render işlemini gerçekleştiriyor
  • Oyun döngüsü ile render edici ayrılmış durumda; JS yalnızca durum yönetimi ve koordinat güncellemesiyle ilgileniyor

Koordinat sistemi dönüşüm sorunu

  • DOOM, Y ekseninin kuzeye doğru arttığı bir 2D koordinat sistemi kullanırken, CSS 3D'de Y yukarıyı, Z ise izleyici yönünü gösteriyor
  • Dönüşüm sırasında koordinatları eşleştirmek için translate3d(x,-z,-y) biçimi kullanılıyor
  • rotateY(atan2(var(--delta-y), var(--delta-x))) hesabının ek dönüşüm olmadan çalışması dikkat çekiyor

Kamera yerine dünyayı hareket ettirmek

  • CSS'te kamera kavramı olmadığı için, oyuncu yerine dünyanın ters yönde hareket ettirilmesi yöntemi kullanılıyor
  • JS tarafında yalnızca --player-x/y/z/angle olmak üzere dört özel özellik güncelleniyor
  • translate: 0 0 var(--perspective) ile bakış düzeltmesi yapılıyor; rotateY ve translate3d ile görüş dönüşü ve konum hareketi uygulanıyor
  • Tüm hareketler yalnızca özellik güncellemeleriyle işleniyor

Zemin, yatırılmış bir div

  • Varsayılan DOM öğeleri dikey düzlem olduğu için, zemin rotateX(90deg) ile yatırılarak yatay yerleştiriliyor
  • clip-path, polygon(), path() ile karmaşık çokgen alanlar ve delikler ifade ediliyor
  • Modern CSS'in shape() fonksiyonu sayesinde yüzde tabanlı yollar ve evenodd kuralı birlikte kullanılabiliyor

Doku hizalama

  • Bitişik sektörler arasında doku kopmaması için dünya koordinatı tabanlı background-position kullanılıyor
  • Tüm sektörler aynı doku ızgarasını paylaştığından sınırlar pürüzsüz biçimde birleşiyor

Kapılar, liftler ve @property animasyonu

  • Kapı açılması, sektör tavanının yükseltilmesiyle yapılıyor; kapsayıcı <div> öğesinin transform değeri CSS transition ile işleniyor
  • Liftlerde oyuncu da birlikte hareket ettiğinden, JS tarafında --player-z senkronize ediliyor
  • @property ile özel özellikler sayısal türde kaydedilerek yumuşak düşme ve hareket efektleri elde ediliyor

Sprite'lar ve aynalama

  • Düşman sprite'ları, her zaman kameraya bakan billboard yöntemiyle gösteriliyor
  • 8 yönün yalnızca 5 seti gerçek görsel; kalanları yatay yansıtma (scaleX) ile işleniyor
  • steps() animasyonu ile yürüme, saldırı ve ölüm kareleri arasında geçiş yapılıyor
  • Tüm düşmanların aynı anda yürümesi sorunu, JS tarafındaki rastgele animation-delay ile çözülüyor

Mermiler, patlamalar ve silah efektleri

  • Roketler ve ateş topları gibi nesneler, CSS animasyonlarıyla A→B hareketini otomatik olarak gerçekleştiriyor
  • JS yalnızca başlangıç-bitiş koordinatlarını ve süreyi ayarlıyor; çarpışma olduğunda öğe kaldırılıyor ve patlama sprite'ı oluşturuluyor
  • Patlama ve mermi dumanı, steps() tabanlı 3 karelik animasyonun ardından otomatik siliniyor

Işıklandırma ve filtreler

  • Sektör bazlı parlaklık değeri --light özelliğiyle tanımlanıyor, iç öğeler bunu filter: brightness() ile devralıyor
  • Yanıp sönen ışıklar için @keyframes ile --light değeri periyodik olarak değiştiriliyor
  • Saydam düşman (Spectre), SVG filtreleri (feColorMatrix, feTurbulence, feDisplacementMap) ile bozulmuş bir silüet olarak gösteriliyor

Duyarlı arayüz ve anchor positioning

  • Oyun mobil uyumlu; HUD, flex-wrap ile satır kırabiliyor
  • Silah sprite'ları, HUD yüksekliğine göre anchor-name / position-anchor ile otomatik konumlandırılıyor
  • Dokunmatik kontrol düğmeleri de aynı anchor yöntemiyle yerleştiriliyor

İzleyici modu

  • Haritanın tamamını görme ve üçüncü şahıs takip kamerası destekleniyor
  • CSS'in sin() ve cos() fonksiyonlarıyla oyuncunun arkasındaki kamera konumu hesaplanıyor
  • rotate ve translate özellikleri ayrıştırılarak yumuşak bakış açısı geçişleri sağlanıyor
  • JS yalnızca konum ve açı bilgilerini güncelliyor; kamera matematiğini CSS üstleniyor

Culling ve performans

  • Binlerce 3D öğe nedeniyle tarayıcı compositor yükü oluşuyor
  • JS tabanlı culling: görüş alanı dışındaki öğeler hidden yapılıyor
  • CSS tabanlı culling deneyi: hesaplanan değerlerle visibility kontrol ediliyor, type grinding hilesi kullanılıyor
  • if() fonksiyonu standartlaşırsa bunun yerini daha sade koşul ifadeleri alabilir

Derinlik sıralaması

  • Tarayıcı derinlik sıralamasını (z-order) otomatik olarak yapıyor
  • Aynı düzlemdeki nesnelere çok küçük ofsetler verilerek titreme önleniyor

DOOM'un “hileleri” ve gökyüzü işleme

  • Orijinal DOOM, gökyüzünü 2D doku olarak “duvarın” üstüne çizen bir projeksiyon hilesi kullanıyor
  • CSS render edicisi gökyüzünü gerçek 3D uzaya yerleştirmek zorunda olduğundan, bazı sahnelerde haritanın arkası görünür hale geliyor
  • Çözüm olarak culling aşamasında gökyüzü duvarlarının arkasındaki öğeler render dışında bırakılıyor

Sonuç — CSS'in sınırları ve olanakları

  • Tüm oyun döngüsü JS ile, render işlemi ise saf CSS tabanlı olarak ayrılmış
  • Trigonometrik fonksiyonlar, @property, clip-path, SVG filtreleri, anchor positioning gibi modern CSS özellikleri sonuna kadar kullanılmış
  • WebGL düzeyinde performans vermese de, CSS'in ifade gücünün genişletilebileceğini kanıtlıyor
  • Safari ve Chrome'da 3D ile ilgili çok sayıda hata ve performans sorunu bulunmuş
  • Nihai sonuç: “CSS ile DOOM çalıştırılabilir mi?” → Evet, mümkün. Yes, it can.

1 yorum

 
GN⁺ 2026-03-29
Hacker News yorumları
  • "Bunu DOOM çalıştırır mı?" türü insanlar bence devletin uzay itki sistemleri departmanında işe alınmalı
    Onlar parmaklarını oynatmak için fazla sıradışı görevler gerektiren insanlar

    • Ama sonunda yaptıkları itki sistemini bile DOOM çalıştırabilir hale getirecekler gibi duruyor
  • Bu, "yapabildiğimiz için yapıyoruz" türü bir proje gibi görünüyor
    CSS başlangıçta bildirimsel bir stil diliydi ama artık koşullar, matematik fonksiyonları ve render hileleri eklenince giderek programlanabilir bir sisteme dönüşüyor
    Asıl mesele "CSS ile DOOM çalıştırılabilir mi" değil, başlangıçta bunun için tasarlanmamış bir katmana ne kadar mantık ittiğimiz

    • Bu, tipik bir soyutlama tersine çevrilmesi (abstraction inversion) örneği
      CSS, programlama dili olma arzusunu saklıyor ama sonunda tamamen yanlış bir soyutlamaya dönüşmüş durumda
    • Esas nokta, sunumun (CSS) ve etkileşimin (JavaScript) sınırının nereye kadar uzandığı
      Eskiden açılır menüler, tooltip'ler ve yerleşim için JS gerekirdi ama artık anchor konumlandırma ya da koşullar (if()) bile CSS özellikleriyle belirtilebiliyor
      Animasyonlar, detay aç/kapat davranışları ve erişilebilirlikle ilgili efektler bile artık CSS ile yapılabiliyor
  • CSS ile 3D sahneler oluşturmak zaten uzun zamandır mümkündü ama etkileşim için JS gerekiyordu
    Artık x86CSS projesi gibi örneklerle JS olmadan da bir CPU'yu yalnızca CSS ile emüle etmek mümkün
    Bu yüzden DOOM'un da saf CSS ile gerçek zamanlı olarak uygulanıp uygulanamayacağını merak ediyorum

    • Ama CSS x86 CPU'nun oyun döngüsünü işleyecek kadar hızlı olmadığı söyleniyor. Sonuçta yine JS gerekiyor
    • CSS'in bu evrimi kaçınılmaz bir sonuçtu; HTML tarafının en baştan DSSSL'yi benimsemesi gerektiğini düşünenler de var
  • Bu örnek, insanların neden TypeScript tabanlı CSS istemeye başladığını gayet iyi gösteriyor
    Sadece Chrome'da çalışan if() gibi özellikler yüzünden geliştiriciler böyle hilelere başvuruyor
    Örneğin, animation-delay ve @keyframes kullanarak görünürlük aç/kapa davranışını taklit eden numaralar yapılıyor
    CSS if() standartlaşırsa bu tür hack'ler olmadan temiz koşul işlemleri mümkün olacak

  • DOOM hile kodları IDDQD ve IDKFA ne yazık ki çalışmadı

  • Eskiden bir div'e yuvarlatılmış köşe yapmak için dört GIF gerektiği günleri hatırlatıyor

    • Div mi? Ondan da önce her şeyin table layout ile yapıldığı zamanlar vardı
  • Gerçekten etkileyici! Tek bir div'i silerek bile duvarların içinden geçme (wall hack) mümkün

    • Hatta .wall için sadece opacity: 0.7 verirseniz eski usul şeffaf duvar hilesi hissini birebir yakalayabiliyorsunuz
  • "Bunu nerede bizzat deneyebilirim?" diye düşündüm; cssdoom.wtf üzerinden mümkün

    • Telefonda açar açmaz cihaz ısınmaya başladı
    • Mobilde DOOM'u ilk kez bu kadar akıcı çalışırken gördüm
    • Safari'de de kusursuz çalışıyor — bu neredeyse hiç olmaz
    • Firefox'ta iyi çalıştı ama Alt tuşu eşlemesi menüyü açıp kapattığı için rahatsız ediciydi
      Chromium'da ise daha da takılıyordu ve strafing tuşlarını bulamadım
      Yine de genel olarak şaşırtıcı bir uygulama
  • CSS, komite tasarımının sınırlarını gösteren en tipik spesifikasyonlardan biri
    SVG ile birlikte "en çirkin görünen spesifikasyon" yarışına giriyor

    • Hatta buna karşılık, belki de sadece başlığı okuyup yorum yaptığını söyleyenler de vardı
  • Bu harika uygulamaya dair bir ek not:
    Aslında hareket eden oyuncu değil, dünyanın kendisi
    Kamera ise yalnızca görüş açısını (frustum) hesaplamak için kullanılan kavramsal bir araç