1 puan yazan GN⁺ 2024-05-09 | 1 yorum | WhatsApp'ta paylaş
  • xkcd'nin Machine'i, okurların yaptığı karo tabanlı düzeneklerin birbirine eklenmesiyle oluşan dev bir Rube Goldberg tarzı bilye makinesi oyunu; fikir 3 haftada gerçek bir etkileşimli çizgi romana dönüştürüldü
  • Önceki kullanıcı katılımlı proje deneyimleri, paylaşılan bir tuvalin iyi çalışması için ortak bağlam ve amaç gerektiği yönünde bir tasarım ölçütüne dönüştü
  • Oyuncuların ifade gücünü korurken karo uyumluluğu için giriş/çıkış kısıtları güçlü tutuldu ve her düzeneğin 30 saniye içinde kararlı duruma ulaşması sınır olarak belirlendi
  • Tüm makine gerçek zamanlı olarak simüle edilmedi; yalnızca görünen alan Rapier ile çalıştırıldı ve onay anındaki anlık görüntülerle düzenekler zaten çalışıyormuş gibi gösterildi
  • Gönderilerin onay ve dağıtım akışı React ve DOM rendering, Haskell backend, Redis, OpenAPI, TanStack Query ve moderasyon arayüzü birleştirilerek işletildi

Machine'in çıkış noktası

  • xkcd, Machine'i 5 Nisan'da yayımladı
  • Machine, klasik oyun The Incredible Machine tarzında dev bir Rube Goldberg machine oluşturucusudur
  • Makinenin tamamı, tek tek xkcd okurlarının yaptığı küçük düzenek karolarının birbirine eklenmesiyle oluşur
  • Ekip Machine'i 3 hafta içinde yaptı; fikir, 2005 tarihli iş birlikçi GIF Blue Ball Machine'den doğdu
  • İlk beyin fırtınasının ana soruları bilyelerin nereden geleceği, herkesin aynı makineyi görüp görmeyeceği, makinenin amacı, oyuncu etkileşimi ve katılım motivasyonuydu

Kullanıcı katılımlı xkcd'lerden çıkarılan dersler

  • Kullanıcı üretimi içeriğin merkezde olduğu önceki xkcd etkileşimli çizgi romanlarından Lorenz, okurların panel metinleri yazarak şakaları ve hikâyeleri geliştirdiği bir yapıdaydı ve iyi bir deneyim olarak kaldı
  • 2020'deki Collector’s Edition, oyuncuların xkcd arşivinden çıkartmalar bulup küresel paylaşımlı bir tuvale birer kez yapıştırdığı bir yapıdaydı; ancak beklendiği kadar iyi çalışmadı
    • Tüm oyuncular boş bir haritanın merkezinde başladı ve kısa süre içinde kaotik bir ekran ilk izlenim hâline geldi
    • Çıkartma konumunu dikkatle seçmek için yeterli teşvik yoktu ve tekil eylemlerle hikâyeyi ilerletmek zordu
    • Paylaşılan bir hikâye veya hedef olmadığından, her çıkartmanın sayfadaki diğer öğelerle nasıl bağlandığı net değildi
  • Kolektif bir tuvalin iyi çalışması için kullanıcıların ne yapmanın etkileyici olacağını örneklerden öğrenebilmesi gerekir
  • Yaratıcı sonuçları tek bir yöne toplamak için ne yapılacağını senkronize eden paylaşılan bağlam ve amaç gerekir

Kısıt tasarımı: ifade gücü, uyumluluk, 30 saniyelik kararlı durum

  • Büyük bir iş birlikçi bilye düşürme düzeneği yapmaya karar verildikten sonra bile makinenin toplam boyutu, simülasyon biçimi ve karoların bütünleştirilme yöntemi sorun olarak kaldı
  • 100x100 boyutunda bir makine varsayıldığında, istemcide 10.000 karoyu gerçek zamanlı çalıştırıp her karoda onlarca bilyeyi işleme hedefi riskli görüldü
  • İfade gücünü doğruluğun önüne koymak

    • Tüm makineyi sunucuda çalıştırma veya tek tek karoları simüle ederek doğrulama seçenekleri değerlendirildi
    • Prototip editörde kaotik bilye çarpışma desenleri kolayca oluşturulunca, öngörülebilir bir makine istemenin oyuncuların özgürlüğünü azaltacağı sonucuna varıldı
    • Nihai tasarım, çok deterministik olmayan veya bozuk düzeneklerin bile yapılabilmesini sağlayan oyuncu esnekliğine öncelik verdi
    • Bu tercih nedeniyle karoların kısıtları karşılayıp karşılamadığını kontrol etmek ve saldırgan içerikleri kaldırmak için aktif moderasyon gerekti
  • Karolar arası uyumluluk için giriş/çıkış kısıtları

    • Başta, bir sonraki oyuncunun önceki karonun çıkış konumuna göre özgürce genişlettiği bir yöntem düşünüldü
    • Ancak erken yerleştirilen bir karonun daha sonra değiştirilmesi gerekirse, o karoya bağlı büyük bir alan bozulabilirdi
    • Bu yüzden aynı karo alanında birden fazla oyuncunun uyumlu tasarımlar üretebilmesi için giriş/çıkış kısıtları güçlü tutuldu
    • Bu yaklaşım, Robustness principle'daki “gönderirken tutucu, alırken cömert ol” ilkesiyle örtüşür
    • Kevin'in map generator'ı basit 1 girişli 1 çıkışlı bulmacalardan başlayıp ortalarda 4 girişli 4 çıkışlı birleşmelerle karmaşıklaşacak, sonunda ise karo başına 2 çıkışa dönecek şekilde yapılandırıldı
    • Editör, oyuncular karo yaparken gerçek zamanlı geri bildirim verir
      • Karolar ortalama olarak aldıkları bilyelere benzer hızda bilye çıkarmalıdır
      • Bilyeleri yutan veya büyük gecikme yaratan düzenekler azaltılmaya çalışıldı
      • Yukarı akıştaki giriş değişkenliğini yansıtmak için editöre gelen bilye hızı rastgeleleştirilerek chaos testing uygulandı
  • 30 saniye içinde kararlı duruma ulaşma zorunluluğu

    • Moderatörlerin ne kadar süre izlemesi gerektiğini azaltmak için, düzeneğin 30 saniye içinde kararlı duruma girmesi gerektiği şeklinde keyfi bir ölçüt kondu
    • 10.000 karoyu 30'ar saniye izlemek, toplam moderasyon süresini yaklaşık 83,3 saat yapacağı hesabı bu ölçüte temel oldu
    • Bilyeler de 30 saniye sonra sona erecek şekilde değiştirildi
      • Süre sonu olmadığında acemi oyuncuların ilk deneyimi, ekranda bilyelerin biriktiği bir durum oluyordu
      • Aktif rigid body sayısı arttığından fizik simülasyonu da yavaşlıyordu
    • Bilye süre sonu, hataların zamanla birikmesini önler; 30 saniyelik gözlemle çoğu bilyenin varış konumunu görmeyi sağlayarak moderasyonu basitleştirir

Tüm makineyi gerçek zamanlı çalıştırmama yöntemi

  • Machine mimarisinin ilk büyük varsayımı, yukarıdaki kısıtlar korunursa farklı karoların birbirine eklenip tek bir bütün makine gibi gösterilebileceğiydi
  • Birkaç küçük harita oluşturulup çözülerek bu varsayım doğrulandı
  • Tüm makine sunucuda veya istemcide gerçek zamanlı çalıştırılamayacağı için, kullanıcının gördüğü alanın çevresini simüle eden bir yöntem gerekiyordu
  • Amaç, tek bir bilyeyi makinenin üstünden altına kadar takip etmeyi mümkün kılmaktı
  • Yalnızca görünen alanın var olduğu fizik dünyası

    • İlk harita görüntüleyici yalnızca görünen alanı simüle ediyordu; ancak kaydırma sırasında yeni gelen karolar boş durumda başladığından akışta boşluklar görünüyordu
    • Boş karolar yerine zaten etkin durumdaymış gibi görünmeleri için, kararlı duruma ulaşmış karoların anlık görüntülerini kaydedip ekrana girmeden hemen önce yükleme yöntemi seçildi
    • Nihai çizgi romanda gerçek fizik simülasyonunda yalnızca render edilen karolar vardır
    • Ekranın üstünde daha fazla makine varmış gibi görünmesi için, simülasyonun üst satırındaki karolara giriş kısıtlarının beklenen hızına uygun bilyeler üretilip verilir
  • Onay anı anlık görüntüsü

    • Anlık görüntü oluşturma moderasyon arayüzüne bağlandı
    • Moderatör, bir karoyu onaylamadan önce en az 30 saniye beklemek zorundadır; onay düğmesine basıldığı andaki durum anlık görüntü olarak kaydedilir
    • Moderatörün, düzeneğin görsel olarak daha iyi bir hâle gelmesi için biraz daha bekleme takdiri de vardır
    • Anlık görüntü yöntemi birikmiş hataları sıfırlama etkisi yaratır; kullanıcı kaydırıp yeni bir karoyu ilk kez gördüğünde moderatörün iyi bulduğu temiz durumu görür
    • Uzun süre izlenirse birçok düzenek durabilir veya bozuk hâle gelebilir; ancak keşfetmeye devam edildikçe yeni anlık görüntülerle karşılaşılır
    • Tüm makine tamamen simüle edilmez; sonuç olarak yapı hyperreality'ye yakın hâle gelir

React, DOM ve Rapier rendering yapısı

  • Machine, Rapier fizik motoru üzerine inşa edildi
  • Rapier; belgeleri, API'si, kullanışlı temel öğeleri ve Rust uygulaması üzerinden WASM tarayıcı performansı nedeniyle avantajlıydı
  • Başta Rapier'in deterministiklik garantisi de ilgi çekiciydi; ancak nihayetinde sunucu tarafı simülasyon yapılmadı
  • Rapier'in üzerine özel bir React context'i olan <PhysicsContext> yazıldı
    • React bileşeni yaşam döngüsü içinde Rapier fizik nesneleri oluşturulup yönetilir
    • Yerleştirilebilir her nesne ve çarpışma yüzeyini “widget” bileşeni olarak geliştirmek kolaylaştı
    • React hızlı ve kaba bir scene graph gibi çalışır
    • Bir karo unmount edildiğinde ilgili fizik nesneleri ve DOM temizlenir
    • Fast refresh ile hot reloading, çarpışma şekillerini ayarlamayı kolaylaştırdı
  • Fizik hook'ları, <PhysicsContext> içinde değilse çalışmayacak şekilde yapıldı; bu da moderasyon arayüzündeki statik önizlemelerde kullanıldı
  • Daha sonra Rapier nesnelerini hook yerine bileşen olarak oluşturmanın daha iyi olacağı düşünüldü
    • react-three-rapier bu yöntemi kullanır ve React diffing'e daha iyi uyar
    • useEffect tabanlı yöntem, bağımlılıklar değiştiğinde önceki instance'ı yok edip yenisini oluşturur
  • Yalnızca DOM ile rendering

    • Machine tamamen DOM ile render edilir
    • Başta performans sınırına gelinirse PixiJS veya canvas'a taşınabileceği düşünüldü; ancak inşa edilecek şeyi azaltan DOM yaklaşımı olabildiğince zorlandı
    • Rendering performansı için frame loop, fizik simülasyonundaki widget'ların stillerini doğrudan uygular
    • React diff yalnızca scene graph'ın yapısı değiştiğinde çalışır
    • Başta bilyeler de React ile render ediliyordu; ancak sık oluşturma/silme diff maliyetini artırdığı için ayrı bir optimized renderer yapıldı
    • Ekran dışındaki bilyelere ve widget'lara draw culling uygulandı
    • Bu yöntem, simülasyondaki 4.000 bilye ve ekrandaki yüzlerce bilyeyle iyi çalıştı; böylece yalnızca DOM ile rendering kesinleşti

API, moderasyon ve gönderi operasyonları

  • Backend, davean ve Kevin tarafından Haskell ile yazıldı; depolama için Redis kullanıldı
  • Kod tabanları arasında tip paylaşımı için OpenAPI ve OpenAPI fetch kullanıldı
    • Haskell tipleriyle uyum sağlama konusunda başta bazı pürüzler vardı
    • Son dakika API değişikliklerini koordine etmeye yardımcı oldu
  • TanStack Query, sunucu push'u olmadan caching ve otomatik yenilemeyi yönetmekte faydalı oldu
  • Moderasyon arayüzü ve önceliklendirme

    • Ed White'ın tasarladığı moderasyon arayüzü, tüm gönderilerin yayımlanmadan önce geçtiği darboğazdı
    • Moderatörler belirli bir karo için yüzlerce aday tasarım arasından seçim yapmak zorunda kalabilirdi
    • Kuyruk önceliği, widget türüne göre interestingness score belirleyip her instance'ı sayarak aday karoları sıralama yöntemiyle belirlendi
    • Bu yöntem çok öğe içeren çözümlere eğilim gösterir; ancak moderatörler listenin ortalarını inceleyerek daha minimal çözümleri tamamlar
    • Gönderilen tasarım sayısı ile gerçek makinede yayımlanan tasarım sayısı arasındaki büyük dengesizlik, üzücü bir nokta olarak kaldı
    • Lansmandan önce daha fazla backlog'u yayımlamanın yolları arandı; ancak moderasyon süresi kısıtları içinde iyi bir uzlaşma bulunamadı
    • Canlı gönderimler bittikten sonra gönderi veri kümesini daha fazla paylaşmanın yollarını bulmak istiyorlar
  • Onay bekleme süresi ve hız ayarı

    • Karo anlık görüntülerinin kalitesi önemli olduğu için moderatör onay düğmesi, simülasyon en az 30 saniye çalıştırılmadan etkinleşmez
    • Bu bekleme süresi, kararlı durum anlık görüntüsü oluşturmayı ve çıkışın beklenen hızda bilye alıp almadığını doğrulamayı sağlar
    • Başta moderatörler için can sıkıcı olacağı düşünüldü; ancak acele kararları engellediği için olumlu karşılandı
    • Lansmandan sonra moderatörlerin simülasyonu gerçek zamandan çok daha hızlı çalıştırabilmesini sağlayan bir slider eklendi
    • Bu özellik sayesinde gönderilerin ilk 30 saniyesi 5 saniyeden kısa sürede izlenebilir oldu ve daha uzun süreli davranışları incelemek de kolaylaştı

Amaçlanmamış karo etkileşimleri

  • Jamslunt Interfoggle”, yayımlanmasından sonraki ilk birkaç saat içinde eklenen ve fanın dar aralığından yararlanan bir düzenektir
  • Bu düzenek mavi bilyeleri bir kanalda toplar; ağırlık yeterli olduğunda iki yana dökülmelerini sağlar
  • Üste yerleştirilen “Bouncy”, bilyeleri üç kollu kesişen yollara fırlatan kaos motorudur
  • Bouncy bazen yeşil bilyeleri yanlış çıkışa gönderir; bu bilyeler de tıkanmış mavi bilye yığınını bozarak Interfoggle'da zincirleme bir akış yaratır
  • Editörde girişleri anlaşılır kılmak için yalnızca doğru renkler sağlandığından, Interfoggle bu yeşil bilye davranışı düşünülerek tasarlanmış olamazdı
  • Bu tür amaçlanmamış kombinasyonlar, insanların paylaşımlı tuvalde araçları yaratıcı biçimde kullanma şekliyle projenin en büyük keyiflerinden biri oldu

Kod ve kalan deneyler

  • Machine'in kaynak kodu GitHub deposunda görülebilir
  • Tüm makineyi küresel olarak eksiksiz simüle eden bir uygulama, ilginç bir hackleme görevi olarak kalıyor
  • Machine'e doğrudan tasarım ekleme bağlantısı xkcd 2916'dadır

1 yorum

 
GN⁺ 2024-05-09
Hacker News yorumları
  • Bu yazıyı okuyunca güldüm; o sırada böyle bir şeyin olup bittiğinden hiç haberim yoktu.
    Durumun ne olduğuna dair bir açıklama da yok gibiydi, bunun herkesin birlikte yaşadığı bir deneyim olduğunu da bilmiyordum; sadece rastgele bir sürü şeyin karmaşık biçimde yaşandığını hissettim.
    Birkaç karoyu tamamlayıp gönderdim; bunun “sonraki aşamaya” geçmenin yolu olduğunu sanıp “test 1b” gibi aptalca adlar verdim. Çünkü bunun tek oyunculu olduğunu sanıyor, adları yalnızca benim göreceğimi düşünüyordum.
    Birkaç tane yaptıktan sonra sıkıldım; etrafta dolaşırken karmaşık şeyler gördüm ama bunların gönderilmiş işler olduğunu bilmiyordum, yalnızca seviyeyi çözmek için başlangıç noktaları sanmıştım. Sonuçta 1 Nisan şakasına kanmış oldum.

    • Etkileşimli olduğunu bile bilmiyordum; sadece bakıp “güzelmiş” diye düşündüm.
    • En baştan düzenlenebilir bir örnek göstermeleri ya da önce nihai sonucu gösterip boş yuvalara odaklanarak bir eylem yönlendirmesi yapmaları gerekirdi.
    • Bu arada hâlâ gönderi kabul ediyor.
    • Bende durum çok daha kötüydü. Yaklaşık 2 dakika kurcaladım, neler olduğunu hiç anlamayıp vazgeçtim.
      Belki de esinlenilen o orijinal makine oyununu hiç oynamadığım içindir :-)
    • Bir dahakine, herkese açmadan önce bir açıklama yazısı yayımlasalar iyi olur.
  • Çok fazla “bonk” öğesi eklerken sanırım rapier’ı öldürdüm.
    Uncaught Error: recursive use of an object detected which would lead to unsafe aliasing in rust
    at jt (rapier_wasm2d_bg.js:4836:11)
    at 4ea5626ea4b1e4145572.module.wasm:0xf061c
    at 4ea5626ea4b1e4145572.module.wasm:0xf0638
    at 4ea5626ea4b1e4145572.module.wasm:0xb5e7b
    at H.remove (rapier_wasm2d_bg.js:1051:14)
    at l.remove (collider_set.js:87:18)
    at y.removeCollider (world.js:343:28)
    at PhysicsContext.tsx:258:15
    Yine de gerçekten çok eğlenceli; canlı olarak açıkken haberdar olmadığıma üzüldüm. İnsanların yaptığı tekil makineler için de kalıcı bağlantılar oluşturulabilse harika olurdu.
    Depolama alanı sorunu olabileceğini anlıyorum ama JSON’u base64 ile kodlayıp URL parametresine koymak gibi bir yöntem olmaz mı? Tuhaf haritalar yapıp insanlarla paylaşmak istiyorum.

    • Hâlâ açık. https://xkcd.com/2916/
      Herkese açık nihai sürüme giren makineler için kalıcı bağlantı mümkün, ancak moderasyon kuyruğundan seçilmeyen tekil üretimler için kalıcı bağlantı yok.
      Çizgi roman alan adında denetlenmemiş kullanıcı üretimi içeriği barındırmanın risklerinden kaçınmak için bu bilerek alınmış bir karar.
  • Bu arada HN’de bu konu 6 Nisan’da da açılmıştı ve 14 yorum vardı.
    https://news.ycombinator.com/item?id=39953514

  • “Çıkartmaları nereye koyacağını dikkatle düşünmek için bir teşvik yoktu. Oyuncunun tekil eylemlerle olay örgüsünü ilerletmek için yeterli inisiyatifi yoktu. Bu yüzden yaratıcılık, benzer çıkartmaları karo gibi tekrarlamak ya da çizgi oluşturmak gibi basit desenlerle sınırlı kaldı.”
    Ah, oyun büyük şirkette çalışma hayatına dönüşmüş.

  • Yayına açıldığında katılmıştım. Doğru topun doğru çıkışa mümkün olduğunca güvenilir şekilde gitmesini sağlamak için sanırım yaklaşık bir saat harcadım.
    Gönderdikten sonra sayfayı yenileyince aynı yerde başka birinin düzeneği vardı. Kabul etmek gerekirse daha güzeldi ama güvenilirliği daha düşüktü.
    İşleyişin böyle olduğunu biraz daha baştan söyleseler iyi olurdu. Ayrıca yapı blokları listesinin kaydırılabilir olduğunu bilmeyen tek kişi ben değilmişim gibi görünüyor.

    • Az önce iki tane gönderdim; listenin kaydırılabildiğinden hiç haberim yoktu.
      Şimdi geri dönüp kontrol edecek hâlim yok :(
  • Vay canına, ben ve bir arkadaşım da 2014’te aynı fikri düşünüp Ludum Dare için hayata geçirmiştik. https://nickfa.ro/wiki/CoinSlot
    O fikrin daha cilalanmış ve iyi çalışan bir biçimde ortaya çıktığını görmek güzel.

  • Gençken oynadığım şunu hatırlattı. Gerçekten çok fazla zamanı büyük keyifle boşa harcamıştım.
    https://www.myabandonware.com/game/the-incredible-machine-1m...

    • Yazıda da bu projenin ondan esinlendiği belirtiliyor.
  • Sanırım bir şeyi kaçırdım: Bazı öğeler makinenin içinde neden yalnızca belirli renk topları etkiliyor gibi görünüyor?
    Renklerin tamamen birbirine karışmasını önlemek için bir mekanizma olduğunu tahmin ediyorum ama bu yazıda açıklanmamış gibi.

    • Her topa farklı fiziksel özellikler verilmiş.
      Sarı top hafif ve hava direnci yüksek, yeşil top ağır, kırmızı top ise çok iyi sekiyor.
      Böylece fiziksel ayırıcılar tasarlayabiliyorsunuz.
  • Yaptığım makinelerden herhangi birinin nihai sürüme girip girmediğini kolayca kontrol etmenin bir yolu olsaydı keşke.
    Bir sonraki tasarımda önceki gönderilerin başlıklarını local storage gibi bir yerde saklayıp bildirim gösterebilmek fena olmazdı.