1 पॉइंट द्वारा GN⁺ 2024-05-09 | 1 टिप्पणियां | WhatsApp पर शेयर करें

xkcd के "Machine" डेवलपमेंट नोट्स

शुरुआती कल्पना

  • मार्च के अंत तक आइडिया पर सोचने के बाद अप्रैल की शुरुआत में तय किया गया विचार
  • "क्या Something Awful यूज़र्स द्वारा बनाए गए blueball GIF की तरह एक टाइल-आधारित विशाल डिवाइस बनाया जा सकता है? जहाँ हर कोई एक-एक छोटा चौकोर हिस्सा योगदान दे।"
  • शुरुआत में लगा कि आइडिया पूरी तरह बन चुका है, लेकिन वास्तव में बात करते हुए एहसास हुआ कि अभी बहुत सारे फैसले लेने बाकी हैं
  • गेंद कहाँ से आएगी, क्या सब एक ही मशीन देखेंगे, उद्देश्य क्या होगा, खिलाड़ी कैसे इंटरैक्ट करेंगे—ऐसे मुख्य हिस्सों पर सबकी सोच अलग थी

पिछली कोशिशों से सीखी बातें

  • यूज़र-निर्मित कंटेंट केंद्रित इंटरैक्टिव कॉमिक्स बनाने का अनुभव था
    • Lorenz: पाठक panel text लिखते थे और मज़ाक व कहानी को आगे बढ़ाते थे—एक exquisite corpse (बहुत मज़ेदार था)
    • Collector's Edition: पाठक xkcd आर्काइव में छिपे stickers ढूँढकर shared canvas पर स्थायी रूप से चिपकाने वाला गेम (मनचाहा परिणाम नहीं मिला)
      • शुरू में खाली केंद्रीय map से शुरू करने पर चीज़ें अव्यवस्थित हो जाती थीं
      • sticker placement के लिए प्रोत्साहन कम था, इसलिए व्यक्तिगत actions से plot को आगे बढ़ाना कठिन था और सिर्फ़ साधारण patterns बनते थे
      • पूरी story या goal नहीं था, और stickers के आपसी संबंध भी स्पष्ट नहीं थे
  • किसी collective canvas के सफल होने के लिए लोगों को उदाहरणों के ज़रिए सिखाना पड़ता है कि क्या बनाया जा सकता है, और साझा संदर्भ व उद्देश्य भी होना चाहिए

constraints की डिज़ाइन

  • एक बड़े marble-drop machine बनाने का फैसला करने के बाद बहुत ज़्यादा विकल्प सामने आ गए
  • इसे 100x100 grid से बनाने का निर्णय लिया गया
    • client में 10,000 tiles को real time में simulate करना जोखिमभरा लगा
    • यह भी भरोसा नहीं था कि खिलाड़ी बिना सीधे संवाद के किसी जटिल मशीन के अलग-अलग subregions बना पाएँगे और अलग tiles जुड़ने पर सही चलेंगे
  • कई thought experiments के बाद 3 मुख्य सिद्धांत तय किए गए:

1. सटीकता की कीमत पर भी player expression को अधिकतम करना

  • मशीन कितनी predictable होनी चाहिए?
    • पूरी चीज़ server पर चलाने या individual tiles को validate करने जैसे विकल्प भी सोचे गए, लेकिन prototype editor में यह दिख गया कि अव्यवस्थित marble collision patterns बहुत आसानी से बन सकते हैं
    • अगर गेंदें बिना रुकावट सीधी रेखा में नहीं चलतीं, तो unpredictable machines बनाना आसान था
  • मशीन की predictability बढ़ाना, player freedom के विपरीत जाता था
    • तंग development timeline ने भी कम prediction/simulation वाले approach को प्राथमिकता दिलाई
  • तय किया गया कि खिलाड़ियों को बहुत flexible creation freedom दी जाए, जिसमें बेहद non-deterministic या टूटी हुई machines भी शामिल हों
    • इसके लिए active moderation के ज़रिए constraints पूरी होने की जाँच और अनुचित content हटाना ज़रूरी था

2. compatible और replaceable machines को बढ़ावा देने के लिए सख्त constraints देना

  • moderation स्वीकार करने और unpredictable player machines की वजह से उल्टा और ज़्यादा व्यवस्था की ज़रूरत पड़ी
  • शुरू में input/output को पूरी तरह free-form रखने पर विचार था, लेकिन moderation के दौरान अगर शुरुआती tiles बदलने पड़ें तो बड़े पैमाने पर failure हो सकता है, यह समझ आया
  • ऐसे पर्याप्त मजबूत constraints डिज़ाइन किए गए कि एक ही tile space में कई खिलाड़ी compatible designs बना सकें
    • Robustness principle लागू किया गया: "जो डेटा भेजो उसमें conservative रहो, जो डेटा लो उसमें liberal रहो"
  • input/output constraints देने के लिए शुरुआत से पूरी machine map की ज़रूरत थी
    • map generation के ज़रिए machine की difficulty को नियंत्रित किया गया (साधारण 1-input 1-output से लेकर जटिल 4-input 4-output merges तक)
  • real-time feedback देने के लिए tiles को लगभग उसी rate पर गेंदें बाहर निकालने तक सीमित किया गया, जिस rate पर वे उन्हें प्राप्त करते हैं
    • गेंदों को निगलने या देर तक रोकने वाली machines सीमित की गईं
    • random input rates पर tiles की chaos testing की गई
  • यह सिद्धांत स्थापित किया गया: "मशीन को कुछ समय चलाकर देखो और जाँचो कि औसतन वह constraints पूरी करती है या नहीं"

3. मशीन को पहले 30 सेकंड के भीतर steady state तक पहुँच जाना चाहिए

  • सवाल उठा कि moderator को कितनी देर तक देखना चाहिए
    • पूरी मशीन की moderation में लगने वाला समय निकाला गया (10,000 tiles के हिसाब से 83.3 घंटे)
    • मनमाने तौर पर तय किया गया कि 30 सेकंड के भीतर steady state में पहुँच जाना चाहिए
  • गेंदों को 30 सेकंड बाद गायब होने के लिए सेट किया गया
    • शुरुआत में expiry time नहीं था, इसलिए जब खिलाड़ी गेम सीख रहे थे तब गेंदें जमा होकर स्क्रीन भर देती थीं
    • active rigid bodies बढ़ने से physics simulation धीमी हो जाती थी
    • मज़े के बजाय गेंदें रुकावट बनने लगी थीं
  • गेंदों की expiry से मशीन समय के साथ errors जमा नहीं करती थी
    • moderator सिर्फ़ 30 सेकंड देखकर समझ सकता था कि ज़्यादातर गेंदें कहाँ जा सकती हैं

simulation और surrealism

  • Machine architecture की दो बड़ी चुनौतियाँ:
    1. क्या ऊपर के design constraints के साथ अलग-अलग tiles को जोड़कर पूरी मशीन बनाना सचमुच काम करेगा?
      • इसे जाँचने के लिए कुछ छोटे maps generate और solve किए गए
    2. अगर इतनी बड़ी मशीन को server या client पर real time में नहीं चला सकते, तो उसे दिखाएँ कैसे?

लक्ष्य था कि scroll करते हुए एक single marble को track करना संभव लगे

  • भले पूरी मशीन simulate न हो रही हो, लेकिन खिलाड़ी के दिखाई देने वाले area के आसपास simulation होना चाहिए
  • शुरुआत में infinite map में सिर्फ़ visible area को simulate करने की testing की गई
    • यह काफ़ी अच्छा चला, लेकिन scroll करने पर tiles simulation में खाली initial state के साथ आते थे, जिससे flow में gaps बनते थे
  • खाली tiles की जगह ऐसा दिखना चाहिए था जैसे उनमें पहले से activity हो

दूसरी चुनौती: tile snapshots सिर्फ़ stable state पर पहुँचने के बाद लेना, ताकि वे scroll करके दिखने से ठीक पहले ही मौजूद लगें

  • अंतिम comic में display clipping बंद किए हुए view (CSS overflow:hidden, contain:paint disabled):
    • क्या snapshots नज़र आए? बहुत ध्यान से न देखें तो उन्हें पहचानना मुश्किल है
    • सिर्फ़ rendered tiles ही physics simulation में मौजूद होते हैं
    • display optimization: सिर्फ़ view area के अंदर की गेंदें दिखाई देती हैं, लेकिन simulation पूरे tile range में चलती है
    • मशीन के top का भ्रम देने के लिए simulation की सबसे ऊपरी row में गेंदें generate और feed की गईं (input constraints की expected rate के आधार पर)
  • moderation UI को snapshot generation से जोड़ा गया
    • moderator को tile approve करने से पहले कम-से-कम 30 सेकंड इंतज़ार करना पड़ता था
    • approve button क्लिक करते ही snapshot बनता था
    • moderator अपनी समझ से मशीन अच्छे दिखने वाले state तक पहुँचने के लिए थोड़ा और इंतज़ार कर सकता था
  • snapshot approach उम्मीद से ज़्यादा अच्छा काम कर गया
    • मशीन में जमा errors को reset करने का अच्छा प्रभाव मिला
    • scroll करते समय दिखने वाले tiles का first impression वही साफ़ और अच्छा state होता था जो moderator को पसंद आया था
    • वास्तव में लंबे समय तक देखने पर कई machines टूट सकती थीं या बिखर सकती थीं, लेकिन लगातार explore करने पर नए snapshots में प्रवेश होता रहता था, इसलिए वह दिखता नहीं था
  • comic में scroll होने वाली मशीन असली नहीं है। वह surreal है
    • पूरी मशीन एक साथ simulate नहीं होती, लेकिन उल्टा इससे नतीजा और बेहतर मिला

React और DOM के साथ हज़ारों गेंदों की rendering

  • Rapier physics engine के आधार पर बनाया गया
    • शानदार documentation, उपयोगी primitives के लिए साफ़ API, और Rust implementation (जो browser में WASM के रूप में चलता है) की वजह से प्रभावशाली performance मिली
    • शुरुआत में Rapier की determinism guarantee आकर्षक लगी, लेकिन server-side simulation नहीं किया गया
  • Rapier के ऊपर custom React context <PhysicsContext> लिखा गया
    • Rapier physics objects बनाए गए और React component lifecycle के भीतर manage किए गए
    • physics या collision surfaces वाले हर placeable object के लिए "widget" components बनाना आसान हुआ
    • React ने एक simple और थोड़ा dirty scene graph की भूमिका निभाई
    • view scroll होने पर tile loading/unloading सरल हुआ: tile unmount होने पर उसका सारा physics और DOM साफ़ हो जाता था
    • bonus के रूप में hot reloading को fast refresh से जोड़ना आसान हो गया (collision shapes tuning के लिए यह सचमुच अच्छा था)
  • React context approach का एक और फ़ायदा:
    • अगर physics hooks <PhysicsContext> के अंदर न हों, तो वे noop बन जाते हैं
    • इसे moderation UI में static tile preview rendering के लिए इस्तेमाल किया गया
  • काश Rapier objects बनाने के लिए hooks की जगह components इस्तेमाल किए होते (जैसा react-three-rapier ने किया)
    • यह React diffing के साथ बेहतर बैठता है (dependency बदलने पर useEffect पुरानी instance हटाकर नई बनाता है)
  • Machine पूरी तरह DOM का इस्तेमाल करके render की गई
    • शुरुआती development के दौरान चिंता थी कि performance के मामले में DOM rendering की सीमा तक पहुँच जाएँगे
    • उम्मीद थी कि अगर यह बहुत धीमा हुआ तो PixiJS या canvas पर जाना पड़ेगा, लेकिन देखना चाहते थे कि DOM को कितनी दूर तक ले जाया जा सकता है
  • rendering performance optimization:
    • frame loop सीधे उन widgets पर styles apply करता था जिनमें physics simulation होती थी
      • React का diff सिर्फ़ तब चलता था जब scene graph में structural changes होते थे
    • शुरुआत में गेंदों को React से

1 टिप्पणियां

 
GN⁺ 2024-05-09
Hacker News राय

कई रायों को मिलाकर देखें तो इसे मोटे तौर पर इस तरह संक्षेपित किया जा सकता है:

  • XKCD का April Fools इवेंट "The Incredible Machine" 1 अप्रैल के एक दिन तक चलने वाला एक सहयोगी puzzle game था
    • यूज़र physics engine से लागू किए गए machine elements का उपयोग करके puzzles हल कर सकते थे, और अपने खुद के puzzles बनाकर submit भी कर सकते थे
    • लेकिन ऐसा लगता है कि आगे बढ़ने के तरीके के बारे में पर्याप्त विवरण नहीं था, इसलिए कई यूज़र उलझन में थे
  • puzzle game का फ़ॉर्मेट पुराने DOS game "The Incredible Machine" जैसा है
    • सीमित machine parts का उपयोग करके एक तय लक्ष्य हासिल करने का तरीका
  • development process में Rapier physics engine का उपयोग किया गया, लेकिन recursive error की वजह से crash भी हुआ
  • इवेंट खत्म होने के बाद भी अपने बनाए हुए puzzles शेयर करने के लिए permalink feature होना अच्छा रहेगा, ऐसी राय दी गई
    • storage space की समस्या के कारण यह मुश्किल हो सकता है, इसलिए JSON को Base64 में encode करके URL parameter के रूप में भेजने का तरीका सुझाया गया
  • सिर्फ 3 हफ्तों में इतने बड़े पैमाने का प्रोजेक्ट पूरा कर लेना एक शानदार उपलब्धि माना गया
  • कुछ लोगों ने यह भी कहा कि उन्हें लगा था XKCD को Randall Munroe अकेले चलाते हैं, इसलिए कई लोगों की भागीदारी देखकर हैरानी हुई
  • इवेंट के बारे में अधिक विस्तृत जानकारी Reddit, Explain XKCD, Github repository आदि में देखी जा सकती है