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

नमस्ते, (अनूठी) दुनिया

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

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

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

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

Stanisław Lem डूडल कोड देखें »

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

आइए, अब उन आधुनिक वेब टेक्नोलॉजी के बारे में जानते हैं जिन्हें Stanisvo Lem डूडल में अपनी जगह बनाने के बारे में पता चला और कुछ को नहीं.

DOM और कैनवस के ज़रिए ग्राफ़िक

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

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

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

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

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

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

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

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

फ़्रेम रेट

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

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

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

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

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

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

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

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

मानदंड

एक अनुमान यह भी हो सकता है कि (वास्तव में, शुरुआत में ही) यह माना जा सकता है कि जब भी कैनवस उपलब्ध होगा, वह DOM से तेज़ होगा. यह बात हमेशा सही नहीं होती. जांच करते समय, हमें पता चला कि Mac पर Opera 10.0–10.1 और Linux पर Firefox DOM एलिमेंट को मूव करते समय ज़्यादा तेज़ होते हैं.

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

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

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

सीपीयू (CPU) का संरक्षण किया जा रहा है

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

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

कब?

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

हमें कैसे पता चलेगा कि फ़िलहाल टैब पर फ़ोकस है? हम खुद को window.focus और window.blur से जोड़ते हैं. हमें कैसे पता चलता है कि टैब दिख रहा है? हम नए पेज विज़िबिलिटी एपीआई का इस्तेमाल कर रहे हैं और सही इवेंट पर प्रतिक्रिया दे रहे हैं.

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

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

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

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

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

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

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

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

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

इन सभी कामों में एक बड़ा काम होता है, जिससे पूरा काम HTML5 पहले ही ठीक से कर लेता है. हालांकि, स्थानीय तौर पर सहायता कभी-कभी काफ़ी नहीं होती. इसलिए, पहिए की दुनिया में बदलाव का समय आ जाता है.

इमेज और स्प्राइट की समस्या से निपटना

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

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

पैक-मैन डूडल
पैक-मैन डूडल ने स्प्राइट का इस्तेमाल किया है.

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

रिग किए गए प्रोग्रेस बार के साथ, ग्राफ़िक लोड होने का स्क्रीनशॉट.
रिग किए गए प्रोग्रेस बार के साथ, ग्राफ़िक लोड होने का स्क्रीनशॉट.

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

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

गेम के बीच में सेव की गई स्थिति

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

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

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

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

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

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

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

  • ?doodle-debug&doodle-first-run – दिखाएं कि आपने पहली बार दौड़ लगाई है
  • ?doodle-debug&doodle-second-run – दिखाएं कि यह दूसरी बार दौड़ रहा है
  • ?doodle-debug&doodle-old-run – दिखाएं कि यह पुराना गेम है

टच डिवाइस

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

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

सामान्य व्यस्त क्लिक किया जा सकने वाला लिंक क्लिक किया गया
काम चल रहा है
काम कर रहा सामान्य पॉइंटर
काम जारी है, व्यस्त पॉइंटर
क्लिक किया जा सकने वाला पॉइंटर काम कर रहा है
काम कर रहे पॉइंटर का क्लिक किया गया
फ़ाइनल स्कोर
फ़ाइनल नॉर्मल पॉइंटरv
फ़ाइनल व्यस्त पॉइंटर
फ़ाइनल क्लिक किया जा सकने वाला पॉइंटर
क्लिक किया गया फ़ाइनल पॉइंटर
डेवलपमेंट के दौरान माउस पॉइंटर और इसके बराबर काम.

ज़्यादातर चीज़ें बेकार हो गईं. हालांकि, हमारे टच

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

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

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

और हम यह कैसे पता लगाएं कि डूडल चलाने वाला डिवाइस टच की सुविधा देता है या नहीं? लेज़ीली. पहले टच स्टार्ट इवेंट का पता लगाने के बजाय, हमने सिर्फ़ अपने संयुक्त IQ का इस्तेमाल यह घटाने के लिए किया कि डिवाइस टच करने की सुविधा पर काम करता है या नहीं.

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

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

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

अगर ऐसा नहीं है, तो क्या? तो सवाल यह है कि डूडल में माउस पॉइंटर को सिर्फ़ अन्य अभिनेता के तौर पर क्यों नहीं बनाया जा रहा है? यह काम करता है, लेकिन इसमें कई ऐसी चेतावनियां भी शामिल हैं, मुख्य रूप से:

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

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

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

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

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

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

नतीजा

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

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

मैंने खुद इसे किया – नीचे पिछले दिनों यह लाइव था, जिसमें रूस में 23 नवंबर 2011 की शुरुआत के समय की गिनती होती रही है, जो कि Lem डूडल देखने वाला पहला समय क्षेत्र था. एक नासमझ चीज़, शायद, लेकिन डूडल की तरह, बेहद छोटी दिखने वाली चीज़ों का ज़्यादा मतलब होता है – यह काउंटर, इंजन के लिए वाकई एक अच्छा "स्ट्रेस टेस्ट" था.

लेम डूडल की इन-यूनिवर्स काउंटडाउन क्लॉक का स्क्रीनशॉट.
यूनिवर्स में मौजूद लेम डूडल की काउंटडाउन क्लॉक का स्क्रीनशॉट.

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