240 tarayıcı sekmesinde çalışan Pong
(eieio.games)- Kapatılmamış sekme çubuğundaki boş alanı ekran gibi kullanarak, 240 Chrome sekmesinin favicon’larını piksel olarak kullanan bir Pong deneyi gerçekleştirildi
- 8×30 sekme ızgarası AppleScript ile oluşturuldu; her sekme URL sorgusundaki
windowIndexvetabIndexile kendi konumunu hesaplıyor - Arka plan sekmelerindeki
setIntervalyaklaşık 1 saniyelik aralıklara yavaşladı, ancak zamanlayıcı Web Worker’a taşınınca favicon güncellemeleri yeterince hızlandı - Sunucu WebSocket’i yerine, aynı domain’deki sekmeleri senkronize etmek için Broadcast Channel API kullanıldı; tüm sekmelerin kaydı tamamlandıktan sonra main sekme animasyonu başlatıyor
- En büyük darboğaz, her karede yüzlerce favicon’ı yeniden üretmekti; yalnızca gerçekten değişen sekmeler güncellenince animasyon çok daha akıcı hale geldi
240 sekmeyi tek bir ekran gibi kullanma yöntemi
- Proje, kapatılmamış tarayıcı sekmelerinin kapladığı alanı kullanarak Pong çalıştıran bir deney
- Ekran, 8 Chrome penceresi ve her pencerede 30 sekmeden oluşan 8×30 sekme ızgarasından meydana geliyor
- Top ve raketler, öndeki pencerenin HTML canvas’ı ile üstteki sekme çubuğunun favicon alanı arasında kesintisiz şekilde hareket ediyor
- Kod GitHub’daki faviconic deposunda yayımlanmış; prototip durumunda “awful” kod olduğu notu düşülmüş
Fikir Flappy Favi’den doğdu
- İlham, Tru’nun favicon içinde çalışan Flappy Bird sürümü Flappy Favi’den geldi
- Favicon, tarayıcı sekme çubuğunda gösterilen küçük bir görseldir; ancak tek başına bakılması zor olacak kadar küçüktür
- Görseli birden fazla sekmeye yayarak çizmek için önce üç sorunun çözülmesi gerekiyordu
- Sekmeleri iyi görünen bir ızgara şeklinde yerleştirme yöntemi
- Arka plan sekmelerinde de favicon’ı hızlı güncelleme yöntemi
- Birden çok sekmenin ekranını birbiriyle senkronize etme yöntemi
AppleScript ile Chrome sekme ızgarası oluşturma
- Başta, Chrome’un yeni sekme düğmesine tekrar tekrar basarak sekmeleri küçültme ve ikinci pencereyi hizalayıp ikinci satırı oluşturma yöntemiyle fikrin mümkün olduğu doğrulandı
- Büyük bir ızgarayı elle oluşturmak zahmetli olduğu için süreç AppleScript ile otomatikleştirildi
- Script, 8 Chrome penceresi açıyor, her pencerede 30 sekme oluşturuyor ve pencereleri birbirinin üzerine yığılacak şekilde konumlandırıyor
- Chrome’un kapatılmış sekmeleri yeniden açmaya çalışması gibi bir sorun olduğu için script başında bunun temizlenmesi gerekti
- Her sekme URL’sinde
windowIndexvetabIndexbulunuyor- Son açılan sekmeye
isMain=true,numWindows,numTabs,fullWidthgibi ek parametreler ekleniyor
- Son açılan sekmeye
Arka plan sekmelerinde favicon’ı hızlı yenileme
- Tarayıcı varsayılan favicon URL’sini arar; ancak HTML
headiçine favicon konumunu gösteren bir öğe ekleyip bunu güncellerseniz ikon değiştirilebilir - Chrome’un favicon güncellemesi hissedilir düzeyde saniyede yaklaşık 4 kez gerçekleşiyor
- Arka plan sekmelerinde kaynak kullanımı kısıtlandığı için, favicon’ı 250 ms’de bir değiştiren küçük bir döngü bile yaklaşık saniyede yalnızca bir kez çalışıyor
- Web Audio API’nin arka plan ses callback’lerini bir dolambaçlı yol olarak kullanmayı denediler, ancak düzgün çalıştıramadılar
- Daha sonra zamanlayıcı Web Worker’a taşınıp worker’ın main document’a mesaj göndererek favicon’ı güncellemesi sağlanınca sorun çözüldü
- Örnek yapı, worker’ın emoji’yi
OffscreenCanvasüzerine çizipdata URL’ye dönüştürdükten sonra main document’a göndermesi şeklinde- main document,
link rel="shortcut icon"öğesininhrefdeğerini değiştirerek gerçek favicon’ı güncelliyor
- main document,
Broadcast Channel ile sekme kaydı ve senkronizasyonu işleme
- Sekmeler arası iletişimde iki zorluk vardı
- Her sekmenin kaçıncı pencerenin kaçıncı sekmesi olduğunu bilmesi gerekiyordu
- Sekme güncellemelerinin hangi iletişim kanalıyla iletileceğine karar verilmeliydi
- Konum belirleme, AppleScript’in eklediği URL sorgu parametrelerinden
windowIndexvetabIndexokunarak çözüldü - İlk proof of concept, her sekmenin bir WebSocket sunucusuna bağlandığı ve sunucunun görsel gönderdiği bir yapıdaydı
- WebSocket yaklaşımı projenin hedefiyle pek örtüşmüyordu
- Sunucusuz olarak dünyanın her yerindeki tarayıcı sekmelerinde dağıtmak isteme yönündeki estetik amaçla çelişiyordu
- Her sekmenin bağlantı zamanı farklı olduğundan güncellemeler senkronize olmuyordu
- Daha sonra aynı domain’deki birden çok sekmeye bilgi aktaran Broadcast Channel API’ye geçildi
- Arka plan sekmeleri, kendi sekme/pencere indekslerini içeren
registrationmesajını broadcast channel üzerinden gönderiyor; main sekme bunu alıpackdöndürüyor - Main sekme, tüm arka plan sekmelerinin kaydını aldıktan sonra animasyonu başlatıyor
Canvas ve favicon hizalamasını ayarlama
- Öndeki pencerede çizilen nesnenin sekme çubuğunun içine “giriyormuş” gibi görünmesi için gerçek canvas ile üstteki favicon’lar tek bir genişletilmiş canvas gibi ele alındı
- Uygulama için Chrome penceresinin gerçek boyutlarını elle ölçmek gerekti
- Chrome penceresinin solundan ilk favicon’a kadar 92 piksel
- Favicon’ın altından gerçek pencerenin üstüne kadar 58 piksel
- Favicon boyutu 16×16
- Bu ölçümler ve sekme/pencere sayıları kullanılarak üç değer hesaplandı
- Favicon’larla hizalanacak şekilde gösterilecek canvas’ın genişliği
- Her sekmenin genişliği
- Favicon satırı, URL çubuğu ve gerçek canvas’ı içeren toplam “canvas” genişliği ve yüksekliği
- Dikdörtgen URL çubuğunun altındaysa gerçek canvas’a çiziliyor; URL çubuğunun üstündeyse ilgili alan bilgisi diğer sekmelere broadcast ediliyor
- Her sekme kendi piksel koordinatlarını hesapladıktan sonra favicon’ını beyaz/siyah piksel olarak güncelliyor
Darboğaz veri aktarımı değil favicon üretimiydi
- İlk uygulama çalışıyordu, ancak canvas animasyonu takılıyordu ve
requestAnimationFrameiçinde çizilse bile akıcı değildi - Başta, main thread’in tüm favicon piksel durumlarını hesaplayıp broadcast channel’a koyduğu ve yüzlerce sekmenin bunu okuduğu yapının çok fazla veri kopyaladığından şüphelenildi
- Yalnızca dikdörtgenin konumu broadcast edilecek ve her sekme kesişme olup olmadığını kendisi hesaplayacak şekilde değişiklik yapıldı, ancak performans iyileşmedi
- Asıl sorun, her sekmenin her karede 4×4 siyah-beyaz favicon görselini yeniden oluşturup
toDataURL("image/png")ile URL üretmesiydi - Sonuç canvas değişmese bile yüzlerce sekme saniyede birkaç kez küçük beyaz favicon’ı sürekli yeniden üretiyordu
- Favicon yalnızca gerçekten değiştiğinde güncellenecek şekilde düzeltilince performans ciddi biçimde iyileşti
- Yine de diğer sekmelerdeki işin öndeki sekme animasyonunu neden bu kadar yavaşlattığı tam olarak anlaşılamamış durumda kaldı
Snake yerine Pong’un seçilme nedeni
- Dikdörtgen hareketi denemesinden sonra küçük “engine” toparlandı ve onun üzerinde yapılacak oyun seçildi
- İlk aday, blok tabanlı olduğu için favicon’lara iyi uyacak gibi görünen Snake idi
- Ancak Snake’in fazla blok tabanlı olması nedeniyle, öndeki canvas’taki sürekli hareketin sekme çubuğunda ayrık piksellere dönüşme etkisinin yeterince ortaya çıkmayacağı düşünüldü
- Sonunda Pong seçildi
- Top ve raketlerin canvas ile sekme çubuğu arasında sık sık gidip gelmesi gerekiyor
- Bu hareket, projenin görsel etkisiyle iyi örtüşüyor
Pong uygulama notları
- Favicon çizim API’si hazır olduktan sonra Pong uygulamasının kendisi nispeten basitti
- Sağdaki bilgisayar oyuncusu raketin merkezini her zaman topun merkezine hizalamaya çalışıyor
- Top raketten sektiğinde oluşan açı, raket merkeziyle göreli konumu kullanan basit trigonometrik hesapla bulunuyor
- Bu yöntem gerçekçi değil, ancak topun her zaman aynı açıyı koruması sorununu engelliyor
- Çarpışma tespitinde iki dikdörtgenin kesişip kesişmediğini kontrol eden bir fonksiyon kullanılıyor
- Top ve raketlerin favicon’a akıcı biçimde girme etkisini vurgulamak için topa trail eklendi
Recurse Center’da yapılan dördüncü oyun
- Proje, Recurse Center batch’i sırasında yazıldı
- Recurse Center, programlama için ücretsiz bir writer’s retreat benzeri yer olarak tanıtılıyor
- Bu proje, yaklaşık 40 gün içinde yapılan 4. oyun
- İlgilenen okurlara Recurse Center’a başvurmayı düşünmeleri öneriliyor
1 yorum
Hacker News yorumları
Merhaba! Bunu ben yaptım. HN okurlarında karşılık bulup bulmayacağını merak etmiştim :)
Sorularınız varsa yanıtlarım. Dağınık birkaç düşüncemi yazarsam, animasyonlu favicon kullansam nasıl görüneceğini gerçekten merak ediyorum. Firefox animasyonlu favicon’ları destekliyor; örneğin topun gelecekteki konumunu tahmin edip animasyonlu bir SVG oluşturursam çok daha iyi bir kare hızı elde edebilirim gibi geliyor.
Bir arkadaşım çevrimdışıyken söyledi: canvas rasterleştirmesi genelde GPU’da işlendiği için, takılan animasyonu görüp edindiğim performans sezgisi pek de doğru değilmiş.
Chrome’un favicon güncellemelerini saniyede 4 kezle sınırladığından yalnızca belli ölçüde eminim. Favicon’u güncellemenin birkaç yolu olduğu için gözden kaçırdığım bir şey olabilir
[0] https://jakesgordon.com/writing/javascript-pong/part1/
1 Million Checkboxes’tan sonra bunu, global cap locks’u, bad apple regex’ini, uuid’yi vb. yapmış olmanız etkileyici bir ivme
Nolen’ın yakın tarihli Recurse sunumunu izledim; bu tamamen çılgınca ama temelde komik ve havalı tek seferlik oyunlar gerçekten çok keyifli.
Eski interneti hatırlatıyor. İnsanların sırf silly ve eğlenceli olsun diye bir şeyler yaptığı zamanları. Dün gece onun paylaştıklarından ilham alarak, BEAM decompile ve birkaç numarayla sayfanın kendi kaynak kodunu çıktıladığı çok komik bir quine benzeri şey yaptım.
Benim de bunları ardı ardına çıkaracak zamanım olmasını isterdim; insanların bu şekilde ilginç şeyler üretmeye devam ettiğini bilmek bile beni güldürüyor.
Gülmek isteyenler için o sort-of quine kısmı burada: https://github.com/notactuallytreyanastasio/blog/blob/main/l...
Nolen’ın yaptığı her şey güzel. Bana eski internetin nasıl bir şey olduğuna dair nostalji yaşatan tek amaçlı uygulama/site sweet spot’unu tam tutturuyor gibi görünüyor
Matthew Rayfield’ın sekme favicon’ları yerine adres çubuğunu kullandığı benzer bir deney de var: https://www.youtube.com/watch?v=q7GtCLwTmV4
Bunu yaparken onun URL çalışmasını kesinlikle aklımda tutuyordum, ama blogunu okuyalı ya da videolarını izleyeli epey olmuştu. Projenin ortasında tekrar bakıp onun da “pencereleri üst üste koyup 2B oluşturma” yönüne gittiğini hatırlamak gerçekten eğlenceliydi
Bunu akla getiriyor:
“Show HN: I saw this mind-blowing experiment, so I made a simple version of it” (25.11.2023) https://news.ycombinator.com/item?id=38413660
“Synchronize a 3D scene across multiple windows using Three.js and localStorage” (27.11.2023) https://news.ycombinator.com/item?id=38437773
Kesin söylüyorum, sırada Doom var
Ayrıca her karede ekranın daha büyük bir bölümünün değişme ihtimali yüksek, bu yüzden favicon’u güncellemek için çok daha fazla “canvas’ı veri URL’sine çevirme” gerekiyor. Mevcut uygulamada bu pahalı. Gerçi OffscreenCanvas’tan haberim yoktu; bu yardımcı olabilir
Firefox’ta sekmelerin daha fazla daralması sorunuysa, hâlâ Firefox tarayıcısının kendisini inceleyip minimum sekme genişliği stil kuralını bulabilir ve userChrome.css içine koyabilirsiniz.
Bununla ilgili birkaç rehber var; sekme genişliği için de muhtemelen biri önceden derlemiştir.
Yine de bu hile sayılabilir.
browser.tabs.tabMinWidthde var ama hatırladığım kadarıyla hâlâ bir minimum değeri zorunlu kılıyorOk Go grubu bir zamanlar Google Chrome ile birlikte bir müzik videosu yapmıştı; tarayıcı pencereleri ve dansçılar gerçekten çok iyi senkronize oluyordu, kaleydoskop benzeri efektler de vardı. Bunu görünce o aklıma geldi
https://www.youtube.com/watch?v=ISL1GfXwr-o