केस स्टडी - Stanisław Lem Google डूडल का निर्माण करना

नमस्ते, (strange) world

Google के होम पेज पर कोडिंग करना एक दिलचस्प अनुभव है. इसमें कई तरह की पाबंदियां होती हैं: स्पीड और इंतज़ार के समय पर खास ध्यान देना, सभी तरह के ब्राउज़र पर काम करना, और अलग-अलग स्थितियों में काम करना. साथ ही, उपयोगकर्ताओं को सरप्राइज़ और खुशी देना.

हम Google डूडल के बारे में बात कर रहे हैं. ये खास इलस्ट्रेशन हैं, जो कभी-कभी हमारे लोगो की जगह लेते हैं. हालांकि, पेन और ब्रश के साथ मेरा संबंध लंबे समय से है, लेकिन इंटरैक्टिव आर्ट में भी मेरी दिलचस्पी है.

मैंने जिन इंटरैक्टिव डूडल (Pac-Man, Jules Verne, World’s Fair) को कोड किया है और जिनमें मदद की है वे सभी एक ही तरह से फ़्यूचरिस्टिक और पुराने हैं: वेब की नई सुविधाओं को लागू करने के लिए बेहतरीन अवसर… और अलग-अलग ब्राउज़र के साथ काम करने की सुविधा के लिए ज़रूरी समझदारी.

हम हर इंटरैक्टिव डूडल से बहुत कुछ सीखते हैं. हाल ही में लॉन्च किया गया स्टैनिस्लाव लेम का मिनी-गेम भी ऐसा ही था. इसमें 17,000 लाइनों का JavaScript कोड इस्तेमाल किया गया था. डूडल के इतिहास में पहली बार, कई चीज़ों को आज़माया गया था. आज, मैं उस कोड को आपके साथ शेयर करना चाहता हूं – शायद आपको उसमें कुछ दिलचस्प मिले या मेरी गलतियां दिखें – और इसके बारे में थोड़ी बातचीत की जाए.

स्टैनिस्लाव लैम के डूडल का कोड देखें »

ध्यान रखें कि Google के होम पेज पर, टेक्नोलॉजी के डेमो नहीं दिखाए जाते. हम अपने डूडल से कुछ खास लोगों और इवेंट का जश्न मनाना चाहते हैं. इसके लिए, हम सबसे बेहतर आर्ट और टेक्नोलॉजी का इस्तेमाल करते हैं. हालांकि, हम टेक्नोलॉजी के लिए टेक्नोलॉजी का इस्तेमाल नहीं करते. इसका मतलब है कि हम HTML5 के उस हिस्से को ध्यान से देखते हैं जो आम तौर पर समझा जा सकता है. साथ ही, यह भी देखते हैं कि क्या इससे हमें डूडल को बेहतर बनाने में मदद मिलती है. ऐसा डूडल के ध्यान भटकाए बिना या उसे छिपाए बिना किया जाता है.

आइए, स्टैनिस्लाव लेम के डूडल में शामिल कुछ आधुनिक वेब टेक्नोलॉजी के बारे में जानें. साथ ही, उन टेक्नोलॉजी के बारे में भी जानें जो इसमें शामिल नहीं हैं.

डीओएम और कैनवस की मदद से ग्राफ़िक्स

Canvas एक बेहतरीन टूल है. इसे इस तरह से बनाया गया है कि हम इसकी मदद से, इस डूडल में अपनी पसंद के मुताबिक बदलाव कर सकें. हालांकि, कुछ पुराने ब्राउज़र पर यह सुविधा काम नहीं करती थी. भले ही, मैं उस व्यक्ति के साथ एक ही ऑफ़िस में काम करता हूं जिसने excanvas को बेहतरीन तरीके से बनाया है, लेकिन मैंने कोई दूसरा तरीका अपनाने का फ़ैसला लिया.

मैंने एक ऐसा ग्राफ़िक इंजन बनाया है जो “रेक्ट” नाम के ग्राफ़िक प्राइमिटिव को अलग करता है. इसके बाद, कैनवस या DOM का इस्तेमाल करके उन्हें रेंडर करता है. हालांकि, कैनवस उपलब्ध न होने पर, DOM का इस्तेमाल किया जाता है.

इस तरीके में कुछ दिलचस्प चुनौतियां आती हैं – उदाहरण के लिए, DOM में किसी ऑब्जेक्ट को एक जगह से दूसरी जगह ले जाने या उसमें बदलाव करने पर, तुरंत असर पड़ता है. वहीं, कैनवस के लिए एक खास समय होता है, जब सब कुछ एक साथ ड्रॉ किया जाता है. मैंने सिर्फ़ एक कैनवस बनाने का फ़ैसला लिया और हर फ़्रेम के लिए, उसे साफ़ करके फिर से ड्रॉ किया. एक तरफ़, ज़्यादा से ज़्यादा गतिशील हिस्से – और दूसरी तरफ़, ज़रूरत के मुताबिक जटिलता नहीं है, ताकि कई ओवरलैप होने वाले कैनवस में बांटा जा सके और उन्हें चुनिंदा तौर पर अपडेट किया जा सके.)

माफ़ करें, कैनवस पर स्विच करना उतना आसान नहीं है जितना कि drawImage() की मदद से सीएसएस बैकग्राउंड को डुप्लीकेट करना: डीओएम की मदद से चीज़ों को एक साथ जोड़ने पर, आपको कई चीज़ें मुफ़्त में मिलती हैं – सबसे ज़रूरी है z-index और माउस इवेंट के साथ लेयरिंग.

मैंने “प्लेन” नाम के कॉन्सेप्ट की मदद से, पहले ही z-index को हटा दिया था. डूडल में कई तरह के प्लेन तय किए गए थे – आसमान से लेकर, हर चीज़ के सामने मौजूद माउस पॉइंटर तक – और डूडल में मौजूद हर ऐक्टर को यह तय करना था कि वह किस प्लेन से जुड़ा है. planeCorrection का इस्तेमाल करके, किसी प्लेन में छोटे-मोटे प्लस/माइनस सुधार किए जा सकते थे.

डीओएम की मदद से रेंडर करने पर, प्लेन को आसानी से z-index में बदल दिया जाता है. हालांकि, अगर कैनवस की मदद से रेंडर किया जाता है, तो हमें रेक्टीफ़िकेट को खींचने से पहले, उनके प्लैन के आधार पर क्रम से लगाना होगा. हर बार ऐसा करना महंगा होता है. इसलिए, ऑर्डर का फिर से हिसाब सिर्फ़ तब लगाया जाता है, जब कोई ऐक्टर जोड़ा जाता है या वह किसी दूसरे प्लेन पर जाता है.

मैंने माउस इवेंट के लिए भी ऐसा ही किया है. डीओएम और कैनवस, दोनों के लिए मैंने ज़्यादा z-index वाले, पूरी तरह से पारदर्शी फ़्लोटिंग डीओएम एलिमेंट का इस्तेमाल किया है. इनका फ़ंक्शन सिर्फ़ माउस को घुमाने/हटाने, क्लिक करने, और टैप करने पर प्रतिक्रिया देना है.

इस डूडल में, हमने चौथे दीवार को तोड़ने की कोशिश की है. ऊपर दिए गए इंजन की मदद से, हम कैनवस पर काम करने वाले ऐक्टर को डीओएम पर काम करने वाले ऐक्टर के साथ जोड़ सकते हैं. उदाहरण के लिए, फ़ाइनल में होने वाले विस्फोट, कैनवस में मौजूद ब्रह्मांड के ऑब्जेक्ट के लिए और Google होम पेज के बाकी हिस्से के लिए, डीओएम में मौजूद होते हैं. आम तौर पर, यह पक्षी इधर-उधर उड़ता रहता है और किसी भी दूसरे कलाकार की तरह, हमारे काटे-छटे मास्क से कट जाता है. शूटिंग के दौरान, यह पक्षी परेशानी से बचने के लिए, 'मुझे लकी फ़ील हो रहा है' बटन पर बैठ जाता है. इसे इस तरह से बनाया गया है कि पक्षी कैनवस से निकलकर डीओएम एलिमेंट बन जाए और बाद में फिर से कैनवस पर वापस आ जाए. मुझे उम्मीद है कि यह हमारे वेबसाइट पर आने वाले लोगों को पूरी तरह से समझ आएगा.

फ़्रेम रेट

फ़्रेम रेट की मौजूदा स्थिति जानना और जब यह बहुत धीमा (और बहुत तेज़!) हो, तब उस पर कार्रवाई करना, हमारे इंजन का एक अहम हिस्सा था. ब्राउज़र, फ़्रेम रेट की जानकारी नहीं देते. इसलिए, हमें इसका हिसाब खुद लगाना पड़ता है.

मैंने requestAnimationFrame का इस्तेमाल शुरू किया. अगर यह उपलब्ध नहीं था, तो मैंने पुराने setTimeout का इस्तेमाल किया. requestAnimationFrame कुछ स्थितियों में सीपीयू को चालाकी से बचाता है. हालांकि, हम कुछ ऐसा खुद भी कर रहे हैं, जैसा कि नीचे बताया जाएगा. साथ ही, यह हमें setTimeout की तुलना में ज़्यादा फ़्रेम रेट भी देता है.

मौजूदा फ़्रेम रेट का हिसाब लगाना आसान है, लेकिन इसमें काफ़ी बदलाव हो सकते हैं. उदाहरण के लिए, जब कोई दूसरा ऐप्लिकेशन कुछ समय के लिए कंप्यूटर का इस्तेमाल करता है, तो फ़्रेम रेट तेज़ी से गिर सकता है. इसलिए, हम सिर्फ़ हर 100 फ़िज़िकल टिक के लिए, “रोलिंग” (औसत) फ़्रेम रेट का हिसाब लगाते हैं और उसी के आधार पर फ़ैसले लेते हैं.

किस तरह के फ़ैसले?

  • अगर फ़्रेम रेट 60 एफ़पीएस से ज़्यादा है, तो हम उसे कम कर देते हैं. फ़िलहाल, Firefox के कुछ वर्शन में requestAnimationFrame के लिए फ़्रेम रेट की कोई ऊपरी सीमा नहीं है. साथ ही, सीपीयू को बर्बाद करने का कोई मतलब नहीं है. ध्यान दें कि हम फ़्रेम रेट को 65 एफ़पीएस तक सीमित रखते हैं. ऐसा इसलिए, क्योंकि राउंडिंग की गड़बड़ियों की वजह से, दूसरे ब्राउज़र पर फ़्रेम रेट 60 एफ़पीएस से थोड़ा ज़्यादा हो जाता है. हम नहीं चाहते कि गलती से फ़्रेम रेट को कम कर दिया जाए.

  • अगर फ़्रेम रेट 10fps से कम है, तो हम फ़्रेम छोड़ने के बजाय, इंजन को धीमा कर देते हैं. यह एक ऐसा विकल्प है जिसमें दोनों ही पक्षों को नुकसान होता है. हालांकि, मुझे लगता है कि ज़्यादा फ़्रेम स्किप करने से, गेम धीमा (लेकिन फिर भी समझ में आने वाला) होने की तुलना में ज़्यादा भ्रम की स्थिति पैदा होगी. इसका एक और अच्छा असर भी है – अगर सिस्टम कुछ समय के लिए धीमा हो जाता है, तो उपयोगकर्ता को अचानक से कोई असर नहीं पड़ेगा, क्योंकि इंजन तेज़ी से काम कर रहा होगा. (मैंने Pac-Man के लिए इसे थोड़ा अलग तरीके से किया था, लेकिन कम से कम फ़्रेम रेट एक बेहतर तरीका है.)

  • आखिर में, जब फ़्रेम रेट खतरनाक रूप से कम हो जाता है, तो हम ग्राफ़िक को आसान बनाने के बारे में सोच सकते हैं. हम लेम के डूडल के लिए ऐसा नहीं कर रहे हैं. हालांकि, माउस पॉइंटर के लिए ऐसा किया जा रहा है. इस बारे में नीचे ज़्यादा जानकारी दी गई है. हालांकि, हम कुछ अतिरिक्त ऐनिमेशन हटा सकते हैं, ताकि धीमे कंप्यूटर पर भी डूडल आसानी से चल सके.

हमारे पास फ़िज़िकल टिक और लॉजिकल टिक का भी कॉन्सेप्ट है. पहला अनुपात, requestAnimationFrame/setTimeout से मिलता है. सामान्य गेमप्ले में अनुपात 1:1 होता है, लेकिन फ़ास्ट-फ़ॉरवर्ड करने के लिए, हम हर फ़िज़िकल टिक के हिसाब से ज़्यादा लॉजिकल टिक जोड़ते हैं. यह अनुपात 1:5 तक हो सकता है. इससे हम हर लॉजिकल टिक के लिए सभी ज़रूरी गणनाएं कर सकते हैं. हालांकि, स्क्रीन पर चीज़ों को अपडेट करने के लिए, सिर्फ़ आखिरी टिक को चुना जाता है.

मानदंड

यह अनुमान लगाया जा सकता है कि कैनवस, DOM की तुलना में ज़्यादा तेज़ होगा. शुरुआत में ऐसा ही था. ऐसा हमेशा नहीं होता. जांच के दौरान, हमें पता चला कि Mac पर Opera 10.0–10.1 और Linux पर Firefox, डीओएम एलिमेंट को मूव करते समय असल में तेज़ काम करते हैं.

अगर सब कुछ सही तरीके से हो, तो डूडल में अलग-अलग ग्राफ़िक तकनीकों का इस्तेमाल किया जा सकता है. जैसे, style.left और style.top का इस्तेमाल करके डीओएम एलिमेंट को मूव करना, कैनवस पर ड्रॉ करना, और शायद सीएसएस3 ट्रांसफ़ॉर्म का इस्तेमाल करके डीओएम एलिमेंट को मूव करना

– इसके बाद, उस पर स्विच करें जिसकी फ़्रेम रेट सबसे ज़्यादा है. मैंने इसके लिए कोड लिखना शुरू किया, लेकिन मुझे पता चला कि कम से कम, मेरे बेंचमार्किंग का तरीका काफ़ी भरोसेमंद नहीं था और इसमें काफ़ी समय लगता था. यह वह समय है जो हमारे पास अपने होम पेज पर नहीं है – हम स्पीड को बहुत अहमियत देते हैं. इसलिए, हम चाहते हैं कि डूडल तुरंत दिखे और क्लिक या टैप करने के तुरंत बाद गेमप्ले शुरू हो जाए.

आखिर में, वेब डेवलपमेंट में कभी-कभी आपको वही करना पड़ता है जो करना ज़रूरी है. मैंने पीछे मुड़कर देखा कि कोई देख तो नहीं रहा है. इसके बाद, मैंने कैनवस से Opera 10 और Firefox को हार्ड कोड कर दिया. अगले जन्म में, मैं <marquee> टैग के तौर पर वापस आऊंगा.

सीपीयू का इस्तेमाल कम करना

क्या आपको वह दोस्त याद है जो आपके घर आता है, ब्रेकिंग बैड का सीज़न फ़ाइनल देखता है, आपको उसका ख़ुलासा कर देता है, और फिर उसे आपके डीवीआर से मिटा देता है? आपको ऐसा नहीं करना है, है ना?

इसलिए, हां, यह अब तक का सबसे खराब उदाहरण है. हालांकि, हम नहीं चाहते कि हमारा डूडल भी ऐसा हो – किसी के ब्राउज़र टैब में दिखने की अनुमति पाना एक विशेषाधिकार है. सीपीयू साइकल को रोकने या उपयोगकर्ता का ध्यान भटकाने से, हम एक अप्रिय मेहमान बन जाएंगे. इसलिए, अगर कोई व्यक्ति डूडल से नहीं खेल रहा है (न टैप, न माउस क्लिक, न माउस मूवमेंट, न ही बटन दबाना), तो हम चाहते हैं कि वह डूडल स्लीप मोड में चला जाए.

कब?

  • होम पेज पर 18 सेकंड के बाद (आर्केड गेम में इसे अट्रैक्ट मोड कहा जाता है)
  • अगर टैब पर फ़ोकस है, तो 180 सेकंड बाद
  • 30 सेकंड के बाद, अगर टैब पर फ़ोकस नहीं है (उदाहरण के लिए, उपयोगकर्ता किसी दूसरी विंडो पर स्विच कर गया है, लेकिन हो सकता है कि वह अब भी इनऐक्टिव टैब में डूडल देख रहा हो)
  • टैब के अदृश्य होने पर तुरंत (उदाहरण के लिए, जब उपयोगकर्ता उसी विंडो में किसी दूसरे टैब पर स्विच करता है – अगर हम दिख नहीं रहे हैं, तो साइकल बर्बाद करने का कोई मतलब नहीं है)

हमें कैसे पता चलेगा कि फ़िलहाल टैब पर फ़ोकस है? हम window.focus और window.blur से अटैच हैं. हमें कैसे पता चलेगा कि टैब दिख रहा है? हम नए Page Visibility API का इस्तेमाल कर रहे हैं और सही इवेंट पर प्रतिक्रिया दे रहे हैं.

ऊपर बताए गए टाइम आउट, हमारे लिए सामान्य से ज़्यादा माफ़ किए जा सकते हैं. मैंने उन्हें इस डूडल में इस्तेमाल किया है. इसमें कई ऐंबियंट ऐनिमेशन (मुख्य रूप से आसमान और पक्षी) हैं. आम तौर पर, टाइम आउट गेम में इंटरैक्शन के आधार पर तय किए जाते हैं.उदाहरण के लिए, लैंडिंग के तुरंत बाद, पक्षी, डूडल को बता सकता है कि वह अब सो सकता है. हालांकि, मैंने आखिर में ऐसा नहीं किया.

आसमान हमेशा गतिशील रहता है. इसलिए, नींद आने और जागने पर डूडल न तो रुकता है और न ही शुरू होता है. डूडल रुकने से पहले धीमा हो जाता है और फिर से शुरू होने पर, ज़रूरत के हिसाब से हर फ़िज़िकल टिक के हिसाब से लॉजिकल टिक की संख्या बढ़ा या घटा देता है.

ट्रांज़िशन, ट्रांसफ़ॉर्म, इवेंट

एचटीएमएल की एक खास बात यह है कि इसे खुद बेहतर बनाया जा सकता है: अगर एचटीएमएल और सीएसएस के सामान्य पोर्टफ़ोलियो में कोई चीज़ ठीक से काम नहीं कर रही है, तो JavaScript की मदद से उसे बेहतर बनाया जा सकता है. माफ़ करें, अक्सर ऐसा होता है कि आपको फिर से शुरू करना पड़ता है. सीएसएस3 ट्रांज़िशन बेहतरीन होते हैं, लेकिन इनमें नया ट्रांज़िशन टाइप नहीं जोड़ा जा सकता. साथ ही, एलिमेंट को स्टाइल करने के अलावा, इनका इस्तेमाल किसी और काम के लिए नहीं किया जा सकता. एक और उदाहरण: सीएसएस3 ट्रांसफ़ॉर्म, डीओएम के लिए बहुत अच्छे हैं. हालांकि, कैनवस पर जाने पर, आपको खुद ही काम करना पड़ता है.

इन और दूसरी समस्याओं की वजह से, Lem doodle का अपना ट्रांज़िशन और ट्रांसफ़ॉर्म इंजन है. हां, मुझे पता है कि साल 2000 में, वगैरह – मैंने जो सुविधाएं बनाई हैं वे CSS3 के मुकाबले काफ़ी कमज़ोर हैं. हालांकि, इंजन जो भी करता है वह लगातार करता है और हमें ज़्यादा कंट्रोल देता है.

मैंने एक आसान ऐक्शन (इवेंट) सिस्टम से शुरुआत की – एक टाइमलाइन जो setTimeout का इस्तेमाल किए बिना, आने वाले समय में इवेंट ट्रिगर करती है. ऐसा इसलिए, क्योंकि किसी भी समय डूडल का समय, असल समय से अलग हो सकता है. ऐसा इसलिए होता है, क्योंकि डूडल का समय तेज़ी से आगे बढ़ता है (फास्ट फ़ॉरवर्ड), धीमा होता है (सीपीयू को बचाने के लिए फ़्रेम रेट कम हो जाता है या डूडल बंद हो जाता है) या पूरी तरह से रुक जाता है (इमेज लोड होने का इंतज़ार करते समय).

ट्रांज़िशन, ऐक्शन का एक और टाइप है. हम इमेज को सिर्फ़ एक दिशा में घुमाने और आगे-पीछे करने के साथ-साथ, इमेज को एक से दूसरी जगह ले जाने की सुविधा भी देते हैं. जैसे, किसी इमेज को दाईं ओर 10 पिक्सल ले जाना. इसके अलावा, हम इमेज को कंपन्न कराने जैसी कस्टम सुविधाएं भी देते हैं. साथ ही, इमेज के ऐनिमेशन के लिए, कीफ़्रेम की सुविधा भी देते हैं.

मैंने रोटेशन के बारे में बताया था. ये भी मैन्युअल तरीके से किए जाते हैं: जिन ऑब्जेक्ट को घुमाना है उनके लिए हमारे पास अलग-अलग ऐंगल के स्प्राइट होते हैं. इसकी मुख्य वजह यह है कि CSS3 और कैनवस, दोनों के रोटेशन में ऐसे विज़ुअल आर्टफ़ैक्ट दिख रहे थे जो हमें स्वीकार नहीं थे. साथ ही, ये आर्टफ़ैक्ट हर प्लैटफ़ॉर्म के हिसाब से अलग-अलग थे.

यह देखते हुए कि घूमने वाले कुछ ऑब्जेक्ट, घूमने वाले अन्य ऑब्जेक्ट से जुड़े होते हैं – एक उदाहरण के लिए, रोबोट का हाथ, जो निचली बांह से जुड़ा होता है और वह खुद घूमने वाली ऊपरी बांह से जुड़ी होती है – इसका मतलब है कि मुझे पिवट के तौर पर, ट्रांसफ़ॉर्म-ऑरिजिन भी बनाना पड़ा.

यह काफ़ी काम है, जो एचटीएमएल 5 के ज़रिए पहले से ही किया जा रहा है – हालांकि, कभी-कभी नेटिव सपोर्ट काफ़ी अच्छा नहीं होता और तब फिर से पहिया बनाने की ज़रूरत पड़ती है.

इमेज और स्प्राइट का इस्तेमाल करना

इंजन का इस्तेमाल सिर्फ़ डूडल चलाने के लिए नहीं किया जाता, बल्कि उस पर काम करने के लिए भी किया जाता है. मैंने ऊपर कुछ डीबग पैरामीटर शेयर किए हैं: बाकी पैरामीटर आपको engine.readDebugParams में मिल सकते हैं.

स्प्रिटिंग एक ऐसी तकनीक है जिसका इस्तेमाल हम डूडल बनाने के लिए करते हैं. इससे हमें बाइट बचाने और लोड होने में लगने वाले समय को कम करने में मदद मिलती है. साथ ही, इससे प्री-लोडिंग आसान हो जाती है. हालांकि, इससे डेवलपमेंट भी मुश्किल हो जाता है – इमेज में किए गए हर बदलाव के लिए, फिर से स्पिरिट बनाने की ज़रूरत होती है. हालांकि, यह काम ज़्यादातर ऑटोमेटेड होता है, लेकिन फिर भी मुश्किल होता है. इसलिए, इंजन को डेवलपमेंट के लिए रॉ इमेज के साथ-साथ, engine.useSprites की मदद से प्रोडक्शन के लिए स्प्राइट पर भी चलाया जा सकता है. दोनों को सोर्स कोड में शामिल किया जाता है.

Pac-Man डूडल
पैक-मैन डूडल में इस्तेमाल किए गए स्प्राइट.

हम इमेज को पहले से लोड करने की सुविधा भी देते हैं. साथ ही, अगर इमेज समय पर लोड नहीं होती हैं, तो हम डूडल को रोक देते हैं. इसके लिए, हम एक फ़र्ज़ी प्रोग्रेस बार का इस्तेमाल करते हैं! (यह गलत है, क्योंकि माफ़ करें, HTML5 भी हमें यह नहीं बता सकता कि इमेज फ़ाइल का कितना हिस्सा पहले से लोड हो चुका है.)

नकली प्रोग्रेस बार के साथ लोड होने वाले ग्राफ़िक का स्क्रीनशॉट.
लोड होने वाले ग्राफ़िक का स्क्रीनशॉट, जिसमें प्रोग्रेस बार में गड़बड़ी की गई है.

कुछ सीन के लिए, हम एक से ज़्यादा स्प्राइट का इस्तेमाल करते हैं. ऐसा, पैरलल कनेक्शन का इस्तेमाल करके लोडिंग की स्पीड बढ़ाने के लिए नहीं, बल्कि सिर्फ़ इसलिए किया जाता है, क्योंकि iOS पर इमेज के लिए 3/50 लाख पिक्सल की सीमा है.

इन सबमें HTML5 का क्या रोल है? ऊपर इस बारे में ज़्यादा जानकारी नहीं दी गई है, लेकिन स्प्रिटिंग/काट-छांट करने के लिए मैंने जो टूल लिखा था वह पूरी तरह से नई वेब टेक्नोलॉजी पर आधारित था: कैनवस, ब्लॉब, और a[download]. एचटीएमएल की एक दिलचस्प बात यह है कि यह धीरे-धीरे उन चीज़ों को शामिल कर लेता है जिन्हें पहले ब्राउज़र के बाहर करना पड़ता था. हमें सिर्फ़ PNG फ़ाइलों को ऑप्टिमाइज़ करना था.

गेम के बीच में गेम की स्थिति सेव करना

लेम की दुनिया हमेशा बड़ी, जीवंत, और असल लगती थी. उनकी कहानियां आम तौर पर, बहुत ज़्यादा जानकारी के बिना शुरू होती थीं. पहला पेज, बीच में से शुरू होता था. इसमें पाठक को खुद ही आगे बढ़ना होता था.

साइबरिएड भी इसी तरह का एक उपन्यास है. इसलिए, हमने डूडल में भी उसी तरह की भावना को दिखाने की कोशिश की है. हम कहानी को ज़्यादा विस्तार से नहीं बताते. एक और बड़ा हिस्सा, रैंडमाइज़ेशन है. हमें लगता है कि यह किताब के यूनिवर्स की मैकेनिकल प्रकृति के हिसाब से सही है. हमारे पास रैंडमाइज़ेशन से जुड़ी कई सहायक फ़ंक्शन हैं, जिनका इस्तेमाल हम कई जगहों पर करते हैं.

हम गेम को दोबारा खेलने की सुविधा को और बेहतर बनाना चाहते थे. इसके लिए, हमें यह जानना था कि पहले कितनी बार डूडल पूरा हो चुका है. इसके लिए, कुकी एक सही टेक्नोलॉजी है. हालांकि, यह Google के होम पेज के लिए काम नहीं करती. हर कुकी से हर पेज का पेलोड बढ़ता है. साथ ही, हम स्पीड और इंतज़ार के समय को लेकर काफ़ी ज़्यादा ध्यान रखते हैं.

सौभाग्य से, HTML5 में वेब स्टोरेज की सुविधा मिलती है. इसका इस्तेमाल करना आसान है. इसकी मदद से, वीडियो के सामान्य तौर पर चलने की संख्या और उपयोगकर्ता के आखिरी में देखे गए सीन को सेव और याद किया जा सकता है. यह सुविधा, कुकी की तुलना में ज़्यादा बेहतर है.

हम इस जानकारी का क्या करते हैं?

  • हम वीडियो को तेज़ी से आगे बढ़ाने का बटन दिखाते हैं. इससे उपयोगकर्ता, पहले से देखे गए वीडियो के बीच के सीन को तेज़ी से देख सकता है
  • फ़ाइनल के दौरान, हम अलग-अलग N आइटम दिखाते हैं
  • हम शूटिंग लेवल की कठिनाई को थोड़ा बढ़ा देते हैं
  • तीसरे और उसके बाद के गेम में, हम आपको किसी दूसरी कहानी से जुड़ा ईस्टर एग ड्रैगन दिखाते हैं

इसे कंट्रोल करने के लिए कई डीबग पैरामीटर हैं:

  • ?doodle-debug&doodle-first-run – मानो कि यह पहली बार चलाया जा रहा है
  • ?doodle-debug&doodle-second-run – मान लें कि यह दूसरा रन है
  • ?doodle-debug&doodle-old-run – मान लें कि यह पुराना रन है

टच डिवाइस

हम चाहते थे कि टच डिवाइसों पर यह डूडल आसानी से चल सके. सबसे आधुनिक डिवाइसों पर यह डूडल बहुत अच्छी तरह से चलता है. साथ ही, क्लिक करने के मुकाबले टैप करके गेम खेलने में ज़्यादा मज़ा आता है.

उपयोगकर्ता अनुभव को बेहतर बनाने के लिए, कुछ बदलाव किए जाने की ज़रूरत है. मूल रूप से, हमारे माउस पॉइंटर से ही यह पता चलता था कि कोई कट्सीन/गैर-इंटरैक्टिव हिस्सा चल रहा है. बाद में, हमने सबसे नीचे दाएं कोने में एक छोटा इंडिकेटर जोड़ा, ताकि हमें सिर्फ़ माउस पॉइंटर पर निर्भर न रहना पड़े. ऐसा इसलिए किया गया, क्योंकि टच डिवाइसों पर माउस पॉइंटर नहीं होता.

सामान्य व्यस्त क्लिक किया जा सकने वाला लिंक क्लिक किया गया
इस पर काम जारी है
प्रोसेस जारी है वाला सामान्य पॉइंटर
&#39;कार्रवाई जारी है&#39; वाला व्यस्त पॉइंटर
&#39;कार्रवाई जारी है&#39; वाला क्लिक किया जा सकने वाला पॉइंटर
जिस पर काम चल रहा है उस पर क्लिक किया गया पॉइंटर
फ़ाइनल
फ़ाइनल सामान्य पॉइंटरv
फ़ाइनल व्यस्त पॉइंटर
क्लिक किया जा सकने वाला फ़ाइनल पॉइंटर
आखिरी क्लिक किया गया पॉइंटर
डेवलपमेंट के दौरान माउस पॉइंटर और फ़ाइनल वर्शन.

ज़्यादातर चीज़ें बिना किसी रुकावट के काम करती हैं. हालांकि, टच अनुभव के इस्तेमाल से जुड़े अचानक किए गए टेस्ट में दो समस्याएं मिलीं: कुछ टारगेट को दबाना बहुत मुश्किल था और तेज़ टैप को अनदेखा कर दिया गया था, क्योंकि हमने सिर्फ़ माउस क्लिक इवेंट को बदल दिया था.

अलग-अलग क्लिक किए जा सकने वाले पारदर्शी DOM एलिमेंट का इस्तेमाल करने से, मुझे काफ़ी मदद मिली. ऐसा इसलिए, क्योंकि मैं विज़ुअल से अलग उनके साइज़ में बदलाव कर सकता था. मैंने टच डिवाइसों के लिए, 15 पिक्सल का अतिरिक्त पैडिंग जोड़ा. साथ ही, क्लिक किए जा सकने वाले एलिमेंट बनाते समय इसका इस्तेमाल किया. (मैंने माउस एनवायरमेंट के लिए भी 5 पिक्सल पैडिंग जोड़ी है, ताकि श्री फ़िट्स खुश रहें.)

दूसरी समस्या के लिए, मैंने माउस क्लिक पर भरोसा करने के बजाय, टच शुरू और खत्म करने के लिए सही हैंडलर अटैच किए और उनकी जांच की.

हम ज़्यादा आधुनिक स्टाइल वाली प्रॉपर्टी का भी इस्तेमाल कर रहे हैं, ताकि वे टच स्क्रीन की कुछ सुविधाएं हटा सकें जो वेबविक ब्राउज़र डिफ़ॉल्ट रूप से जोड़ते हैं. जैसे, टैप हाइलाइट, टैप कॉलआउट.

हम यह कैसे पता लगाते हैं कि डूडल चलाने वाले किसी डिवाइस पर टच की सुविधा काम करती है या नहीं? धीरे-धीरे. हमने पहले से यह पता लगाने के बजाय, डिवाइस पर टच की सुविधा काम करती है या नहीं, यह पता लगाने के लिए अपने आईक्यू का इस्तेमाल किया. हमने यह पता लगाने के लिए, टच शुरू होने का पहला इवेंट ट्रिगर होने के बाद ही ऐसा किया.

माउस पॉइंटर को पसंद के मुताबिक बनाना

हालांकि, हर चीज़ टच-आधारित नहीं होती. हमारे दिशा-निर्देशों में से एक यह था कि डूडल में ज़्यादा से ज़्यादा चीज़ें शामिल की जाएं. साइडबार का छोटा यूज़र इंटरफ़ेस (फास्ट-फ़ॉरवर्ड, सवाल का निशान), टूलटिप, और हां, माउस पॉइंटर.

माउस पॉइंटर को पसंद के मुताबिक कैसे बनाएं? कुछ ब्राउज़र, पसंद के मुताबिक बनाई गई इमेज फ़ाइल से लिंक करके, माउस कर्सर को बदलने की अनुमति देते हैं. हालांकि, यह सुविधा ठीक से काम नहीं करती और इसमें कुछ पाबंदियां भी हैं.

अगर ऐसा नहीं है, तो क्या है? माउस पॉइंटर को डूडल में एक और ऐक्टर क्यों नहीं बनाया जाता? यह तरीका काम करता है, लेकिन इसमें कई समस्याएं आ सकती हैं. इनमें ये मुख्य हैं:

  • आपको नेटिव माउस पॉइंटर हटाना होगा
  • आपको अपने माउस पॉइंटर को “असल” पॉइंटर के साथ सिंक रखने में काफ़ी अच्छा होना चाहिए

पहला तरीका मुश्किल है. सीएसएस3 में cursor: none का इस्तेमाल किया जा सकता है. हालांकि, यह भी कुछ ब्राउज़र में काम नहीं करता. हमें कुछ तरकीबें अपनानी पड़ीं: फ़ॉलबैक के तौर पर खाली .cur फ़ाइल का इस्तेमाल करना, कुछ ब्राउज़र के लिए खास व्यवहार तय करना, और कुछ ब्राउज़र को इस अनुभव से पूरी तरह हटाना.

दूसरी समस्या, दिखने में मामूली है. हालांकि, माउस पॉइंटर, डूडल के यूनिवर्स का एक हिस्सा है. इसलिए, उसमें डूडल की सभी समस्याएं भी होंगी. सबसे बड़ा? अगर डूडल का फ़्रेम रेट कम है, तो माउस पॉइंटर का फ़्रेम रेट भी कम होगा. इससे गंभीर समस्याएं हो सकती हैं, क्योंकि माउस पॉइंटर आपके हाथ का एक हिस्सा होता है और उसे किसी भी स्थिति में रिस्पॉन्सिव होना चाहिए. (ऐसे लोग जो पहले Commodore Amiga का इस्तेमाल करते थे, अब वे ज़ोर से सिर हिला रहे हैं.)

इस समस्या का एक मुश्किल समाधान यह है कि माउस पॉइंटर को सामान्य अपडेट लूप से अलग कर दिया जाए. हमने ठीक यही किया – एक वैकल्पिक दुनिया में, जहां मुझे नींद लेने की ज़रूरत नहीं है. क्या इस समस्या का कोई आसान समाधान है? अगर रोलिंग फ़्रेम रेट 20 एफ़पीएस (फ़्रेम प्रति सेकंड) से कम हो जाता है, तो नेटिव माउस पॉइंटर पर वापस जाएं. (यहां रोलिंग फ़्रेम रेट काम आता है. अगर हम मौजूदा फ़्रेम रेट पर प्रतिक्रिया देते हैं और अगर यह 20fps के आस-पास उतार-चढ़ाव करता है, तो उपयोगकर्ता को कस्टम माउस पॉइंटर हमेशा छिपता और दिखता रहेगा.) इससे हमें ये जानकारी मिलती है:

फ़्रेम रेट की रेंज व्यवहार
10 फ़्रेम प्रति सेकंड से ज़्यादा गेम की स्पीड कम करें, ताकि ज़्यादा फ़्रेम न छूटें.
10 से 20 एफ़पीएस कस्टम माउस पॉइंटर के बजाय, नेटिव माउस पॉइंटर का इस्तेमाल करें.
20 से 60 एफ़पीएस सामान्य ऑपरेशन.
60 एफ़पीएस (फ़्रेम प्रति सेकंड) से ज़्यादा फ़्रेम रेट को इस वैल्यू से ज़्यादा न होने दें.
फ़्रेम रेट पर निर्भर होने वाले व्यवहार की खास जानकारी.

इसके अलावा, हमारा माउस पॉइंटर Mac पर काला है, लेकिन पीसी पर सफ़ेद है. उसने आपको कैसे प्रेरित किया? क्योंकि प्लैटफ़ॉर्म वॉर के लिए, काल्पनिक दुनिया में भी ईंधन की ज़रूरत होती है.

नतीजा

यह एक बेहतरीन इंजन नहीं है, लेकिन यह ऐसा होने की कोशिश भी नहीं करता. इसे लेम के डूडल के साथ ही तैयार किया गया था और यह उसी के लिए खास तौर पर है. यह ठीक है. जैसा कि डॉन नुथ ने कहा था, “समय से पहले ऑप्टिमाइज़ेशन करना, सभी बुराइयों की जड़ है.” मुझे नहीं लगता कि पहले इंजन को अलग से लिखना और बाद में उसे लागू करना सही है. असल में, प्रैक्टिस से थ्योरी को उतना ही फ़ायदा होता है जितना थ्योरी से प्रैक्टिस को. मेरे मामले में, कोड को फेंक दिया गया था, कई हिस्सों को बार-बार फिर से लिखा गया था, और कई सामान्य हिस्सों को ऐन्टी फैक्टम के बजाय पोस्ट के बाद देखा गया था. आखिर में, हमने अपनी पसंद के मुताबिक काम किया – स्टैनिस्लाव लेम के करियर और डेनियल म्रोज़ के ड्रॉइंग को सबसे अच्छे तरीके से दिखाया.

हमें उम्मीद है कि ऊपर दी गई जानकारी से, आपको डिज़ाइन के कुछ विकल्पों और उनसे जुड़े फ़ायदों और नुकसानों के बारे में पता चला होगा. साथ ही, यह भी पता चला होगा कि हमने असल ज़िंदगी के किसी खास मामले में, एचटीएमएल5 का इस्तेमाल कैसे किया. अब, सोर्स कोड को आज़माएं और हमें बताएं कि आपको यह कैसा लगा.

मैंने खुद ऐसा किया था – यह नीचे दिया गया डूडल, रूस में 23 नवंबर, 2011 की सुबह तक काउंटडाउन कर रहा था. यह पहला टाइम ज़ोन था जहां लेम का डूडल दिखाया गया था. शायद यह एक मज़ेदार चीज़ है, लेकिन डूडल की तरह ही, कभी-कभी ऐसी चीज़ों का गहरा मतलब होता है जो मामूली लगती हैं – यह काउंटर, इंजन के लिए एक अच्छा “स्ट्रेस टेस्ट” था.

लेम डूडल में मौजूद काउंटडाउन वाली घड़ी का स्क्रीनशॉट.
Lem doodle in-universe countdown clock का स्क्रीनशॉट.

Google डूडल के जीवन को देखने का यह एक तरीका है – महीनों की मेहनत, हफ़्तों की टेस्टिंग, 48 घंटे की प्रोसेस, और यह सब कुछ सिर्फ़ इसलिए कि लोग पांच मिनट के लिए इसे खेलें. उन हज़ारों JavaScript लाइनों में से हर एक को उम्मीद है कि वे पांच मिनट, काम के होंगे. आनंद लें.