دراسة حالة - إنشاء رسم شعار مبتكر لـ "ستانيسواف لم في Google"

مرحبًا، (عالم) غريب

تُعدّ الصفحة الرئيسية في Google بيئة رائعة لكتابة الرموز البرمجية. وتأتي هذه الميزة مصحوبةً بالعديد من القيود الصعبة: التركيز بشكل خاص على السرعة ووقت الاستجابة، والتعامل مع جميع أنواع المتصفّحات والعمل في ظل ظروف مختلفة، و… نعم، المفاجآت والسعادة.

أقصد رسومات شعار Google المبتكرة، وهي الرسومات التوضيحية الخاصة التي تحلّ أحيانًا محل شعارنا. على الرغم من أنّ علاقتي بالأقلام والفرشاة كانت منذ فترة طويلة تتسم بتلك الصفة المميزة لأمر تقييد، إلا أنّني غالبًا ما أساهم في استخدامها لإنشاء أعمال تفاعلية.

كل رسم شعار Google تفاعلي كتبت رموزه (Pac-Man وجول فيرن وWorld’s Fair) والكثير من الرسومات التي ساعدت في إنشائها كانت مستقبلية وعتيقة في الوقت نفسه، ما يوفر فرصًا رائعة لاستخدام ميزات الويب المتطوّرة في تطبيقات غير واقعية، بالإضافة إلى تطبيقات عملية للغاية متوافقة مع جميع المتصفحات.

نتعلم الكثير من كل رسم متحرك تفاعلي، ولم تكن لعبة Stanisław Lem المصغرة الأخيرة استثناءً، إذ تتضمّن 17,000 سطر من رمز JavaScript وتحاول تنفيذ العديد من الإجراءات لأول مرة في تاريخ رسوم Google المتحركة. أريد اليوم مشاركة هذا الرمز معك، وربما تعثر على شيء مثير للاهتمام فيه أو تشير إلى أخطائي، وسأتحدث قليلاً عن هذا الرمز.

عرض رمز رسم Stanisław Lem »

تجدر الإشارة إلى أنّ الصفحة الرئيسية في Google ليست مخصّصة لعرض العروض التوضيحية للتكنولوجيا. من خلال رسوماتك المميّزة، نريد الاحتفال بأشخاص معيّنين وبأحداث معيّنة، ونريد أن نفعل ذلك باستخدام أفضل الفنون وأفضل التقنيات التي يمكننا استخدامها، ولكن لا نحتفل أبدًا بالتكنولوجيا من أجل التكنولوجيا. ويعني ذلك أنّنا ننظر بعناية إلى أي جزء من HTML5 المفهومة على نطاق واسع متاح، وما إذا كان يساعدنا في تحسين الرسم بدون تشتيت الانتباه عنه أو حجبه.

لنطّلِع على بعض تكنولوجيات الويب الحديثة التي تم تضمينها في رسم Google Doodle الخاص بستانيسلاف ليم، وبعض التكنولوجيات التي لم يتم تضمينها.

الرسومات من خلال نموذج DOM ولوحة الرسم

إنّ تطبيق Canvas هو أداة قوية تم إنشاؤها لتنفيذ النوع الدقيق من الإجراءات التي أردنا تنفيذها في هذا الرسم. ومع ذلك، لم يكن excanvas الذي أعدّه بشكل ممتاز، قررت اختيار طريقة مختلفة.

لقد جمعتُ محركًا للرسومات يزيل المكوّنات الأساسية للرسومات ويُطلق عليها اسم "مستطيلات"، ثم يعرضها باستخدام إما لوحة الرسم أو DOM إذا لم تكن لوحة الرسم متاحة.

يواجه هذا النهج بعض التحديات المثيرة للاهتمام، على سبيل المثال، يؤدي نقل أو تغيير عنصر في DOM إلى عواقب فورية، في حين يكون هناك لحظة محدّدة في اللوحة يتم فيها رسم كل شيء في الوقت نفسه. (قرّرت استخدام لوحة واحدة فقط، ومحو كل ما فيها والرسم من الصفر مع كل لقطة. هناك عدد كبير جدًا من الأجزاء المتحركة من جهة، ومن جهة أخرى، لا تتضمّن الصورة تعقيدًا كافيًا لتبرير تقسيمها إلى عدة لوحات متداخلة وتعديلها بشكل انتقائي.)

للأسف، لا يكون التبديل إلى "لوحة الرسم" بسيطًا مثل مجرد عكس خلفيات CSS باستخدام drawImage(): ستفقد عددًا من الأشياء التي تأتي مجانًا عند تجميع العناصر من خلال DOM، وأهمها الطبقات باستخدام الفواصل z وأحداث الماوس.

لقد أزلنا مؤشر z-index باستخدام مفهوم يُعرف باسم "المستويات". وحدّد الرسم المتحرّك عددًا من المستويات، بدءًا من السماء في الخلف إلى مؤشر الماوس أمام كل شيء، وكان على كل عنصر في الرسم المتحرّك تحديد المستوى الذي ينتمي إليه (كان من الممكن إجراء تصحيحات صغيرة موجبة/سالبة ضمن مستوى باستخدام planeCorrection).

من خلال العرض من خلال نموذج DOM، يتم تحويل المستويات ببساطة إلى z-index. ولكن إذا أردنا عرضها من خلال اللوحة، علينا ترتيب المستطيلات استنادًا إلى مستوياتها قبل رسمها. وبما أنّه يتطلب ذلك تكاليف باهظة في كل مرة، لا تتم إعادة احتساب الطلب إلا عند إضافة عنصر أو عند نقله إلى مستوى آخر.

بالنسبة إلى أحداث الماوس، اختصرت ذلك أيضًا… نوعًا ما. بالنسبة إلى كلّ من DOM واللوحة، استخدَمت عناصر DOM إضافية عائمة وشفافة تمامًا بمؤشر z-index مرتفع، ووظيفتها هي التفاعل فقط مع تمرير الماوس فوق العنصر أو خارجه والنقرات والنقرات.

من بين الأشياء التي أردنا تجربتها في هذه الصورة المصمّمة هي كسر الحاجز الرابع. سمح لنا المحرّك أعلاه بدمج العناصر المستندة إلى مساحة الرسم مع العناصر المستندة إلى DOM. على سبيل المثال، تظهر الانفجارات في المشهد النهائي في اللوحة للعناصر داخل الكون وفي DOM لبقية الصفحة الرئيسية في Google. يقرر الطائر، الذي يطير عادةً حوله ويظهر في لقطات قصيرة من خلال القناع المُسنّد مثل أي ممثل آخر، تجنُّب المشاكل أثناء مرحلة التصوير، ويجلس على الزر "أشعر بالحظ". تتم عملية الربط من خلال مغادرة الطائر للوحة وتحويله إلى عنصر DOM (والعكس صحيح لاحقًا)، ما نأمل أن يكون واضحًا تمامًا للزائرين.

عدد اللقطات في الثانية

كان معرفة معدّل عرض اللقطات الحالي والتصرّف عند بطء معدّل عرض اللقطات (أو عند ازدياد سرعته) جزءًا مهمًا من محرّكنا. بما أنّ المتصفّحات لا تُبلغ عن معدل عرض اللقطات، علينا احتسابه بأنفسنا.

لقد بدأت باستخدام requestAnimationFrame، وكنت أعود إلى استخدام setTimeout القديمة إذا لم تكن الأولى متاحة. يحافظ requestAnimationFrame بذكاء على وحدة المعالجة المركزية في بعض الحالات، على الرغم من أنّنا ننفّذ بعضًا من ذلك بأنفسنا، كما سيتم توضيحه أدناه، ولكنه يسمح لنا أيضًا ببساطة بتحقيق معدّل عرض صور أعلى مقارنةًsetTimeout.

إنّ احتساب معدّل عرض اللقطات الحالي أمر بسيط، ولكنه يتعرض لتغييرات كبيرة. على سبيل المثال، يمكن أن ينخفض بسرعة عندما يستولي تطبيق آخر على الكمبيوتر لفترة من الوقت. لذلك، نحسب عدد اللقطات في الثانية "المتسلسل" (المتوسط) فقط لكل 100 علامة زمنية حقيقية، ونستند إلى ذلك في اتخاذ القرارات.

ما هو نوع القرارات؟

  • إذا كان عدد اللقطات في الثانية أعلى من 60 لقطة في الثانية، نخفّضه. في الوقت الحالي، لا يفرض requestAnimationFrame في بعض إصدارات Firefox حدًا أقصى لمعدل عرض اللقطات، وليس هناك داعٍ لإهدار وحدة المعالجة المركزية. يُرجى العِلم أنّنا نحدّ من هذا المعدل إلى 65 لقطة في الثانية بسبب أخطاء التقريب التي تؤدي إلى زيادة معدل عرض اللقطات قليلاً عن 60 لقطة في الثانية على المتصفّحات الأخرى، ولا نريد بدء الحد من هذا المعدل عن طريق الخطأ.

  • إذا كان عدد اللقطات في الثانية أقل من 10 لقطات في الثانية، نبطئ بساطة المحرك بدلاً من حذف اللقطات. إنّ هذا الخيار يضرّ بالمستخدمين، ولكنني أعتقد أنّ تخطّي اللقطات بشكل مفرط قد يؤدي إلى حدوث المزيد من الارتباك مقارنةً ببطء اللعبة (ولكن مع الحفاظ على التماسك). هناك تأثير جانبي آخر جيد لذلك: إذا كان النظام بطيئًا مؤقتًا، لن يلاحظ المستخدم قفزة مفاجئة إلى الأمام أثناء محاولة المحرّك اللحاق بالسرعة. (لقد اتّبعتُ أسلوبًا مختلفًا قليلاً في لعبة Pac-Man، ولكنّ الحدّ الأدنى لعدد اللقطات في الثانية هو أسلوب أفضل).

  • أخيرًا، يمكننا التفكير في تبسيط الرسومات عندما يصبح معدّل عرض اللقطات منخفضًا بشكل خطير. لن نفعل ذلك في رسم Lem باستثناء وأشارة الماوس (مزيد من المعلومات أدناه)، ولكن من الناحية النظرية، يمكننا التخلص من بعض الرسوم المتحرّكة المزعجة لجعل الرسم يبدو سلسًا حتى على أجهزة الكمبيوتر البطيئة.

لدينا أيضًا مفهومان للعلامة المادية والعلامة المنطقية. تأتي النسبة الأولى من requestAnimationFrame/setTimeout. تكون النسبة في المباريات العادية 1:1، ولكن عند تقديم الفيديو بسرعة، نضيف المزيد من العلامات المنطقية لكل علامة حقيقية (حتى 1:5). يتيح لنا ذلك إجراء جميع الحسابات اللازمة لكل علامة منطقية، ولكن نحدّد فقط العلامة الأخيرة لتكون هي التي تعدّل العناصر على الشاشة.

قياس الأداء

يمكن الافتراض (وقد تم بالفعل في وقت مبكر) أنّ canvas سيكون أسرع من DOM عندما يكون متاحًا. هذا ليس صحيحًا دائمًا. أثناء الاختبار، تبيّن لنا أنّ الإصدارات 10.0 و10.1 من Opera على أجهزة Mac وFirefox على Linux أسرع في نقل عناصر DOM.

في السيناريو المثالي، سيقيّم التطبيق بشكلٍ صامت تقنيات رسومات مختلفة، مثل عناصر DOM التي يتم نقلها باستخدام style.left وstyle.top، والرسم على اللوحة، وربما حتى عناصر DOM التي يتم نقلها باستخدام عمليات التحويل في CSS3.

– ثمّ انتقِل إلى أيّ منها يقدّم أعلى معدّل عرض للإطارات. بدأت في كتابة رمز لذلك، ولكن تبيّن لي أنّ طريقة قياس الأداء التي استخدمتها كانت غير موثوقة إلى حدٍ كبير وتتطلّب الكثير من الوقت. الوقت الذي لا نملكه في صفحتنا الرئيسية: نحن نهتم كثيرًا بالسرعة ونريد أن يظهر الرسم المتحرك على الفور وأن يبدأ تشغيل اللعبة فور النقر عليه.

في النهاية، يُختزل تطوير الويب أحيانًا في تنفيذ ما تحتاجه. لقد نظرتُ خلف كتفي للتأكّد من أنّه لا أحد ينظر، ثمّ عمدتُ إلى إزالة Opera 10 وFirefox من اللوحة. في الحياة التالية، سأعود كعلامة <marquee>.

الحفاظ على وحدة المعالجة المركزية

هل لديك صديق يأتي إلى منزلك ويشاهد الحلقة الأخيرة من الموسم في Breaking Bad ويفسّرها لك ثم يمحوها من جهاز تسجيل الفيديو الرقمي؟ لا تريد أن تكون هذا الشخص، أليس كذلك؟

نعم، هذا هو أسوأ تشبيه على الإطلاق. لا نريد أيضًا أن يكون لدينا رمز متحرك بهذه الطريقة، فنحن نعتبر أنّ السماح لنا بالظهور في علامة تبويب المتصفّح هو ميزة، وسنكون ضيفًا غير مرغوب فيه إذا احتلنا دورات وحدة المعالجة المركزية أو تشتتنا انتباه المستخدم. لذلك، إذا لم يكن أحد يلعب بالرسم المتحرك (بدون نقرات أو نقرات الماوس أو حركات الماوس أو الضغط على المفاتيح)، نريد أن يتم إيقافه في النهاية.

الموعد؟

  • بعد 18 ثانية على الصفحة الرئيسية (تُعرف هذه الميزة في ألعاب الأركيد باسم وضع الجذب)
  • بعد 180 ثانية إذا كان التركيز على علامة التبويب
  • بعد 30 ثانية إذا لم تكن علامة التبويب هي العلامة التي تركّز عليها المستخدم (على سبيل المثال، إذا غيّر المستخدم إلى نافذة أخرى، ولكن لا يزال يشاهد الرسم الآن في علامة تبويب غير نشطة)
  • على الفور إذا أصبحت علامة التبويب غير مرئية (على سبيل المثال، إذا غيّر المستخدِم إلى علامة تبويب أخرى في النافذة نفسها، فلا داعي لإهدار دورات إذا لم يكن بإمكاننا الظهور)

كيف نعرف أنّ علامة التبويب هي التي تركّز عليها حاليًا؟ نوافق على window.focus وwindow.blur. كيف نعرف أنّ علامة التبويب مرئية؟ نحن نستخدم واجهة برمجة التطبيقات الجديدة Page Visibility API ونقوم بالاستجابة للحدث المناسب.

إنّ فترات الانتظار المذكورة أعلاه أكثر تساهلاً من المعتاد. لقد عدّلت هذه العناصر لتتلاءم مع هذه الصورة المتحرّكة التي تتضمّن الكثير من الرسوم المتحركة المحيطة (أبرزها السماء والطيور). من الأفضل أن تكون فترات الاستراحة مشروطة بالتفاعل في اللعبة، مثلاً بعد الهبوط مباشرةً، يمكن للطائر إبلاغ الشعار المتحرك بأنّه يمكنه النوم الآن، ولكن لم أطبّق ذلك في النهاية.

بما أنّ السماء في حركة دائمة، لا يتوقف الرسم المتحرك أو يبدأ عند النوم والاستيقاظ، بل يبطئ قبل الإيقاف المؤقت، والعكس صحيح عند استئناف الرسم المتحرك، مع زيادة أو خفض عدد النقرات المنطقية لكل نقرة جسدية حسب الحاجة.

الانتقالات والتحويلات والأحداث

لطالما كان من مزايا HTML أنّه يمكنك تحسينه بنفسك: إذا لم يكن هناك عنصر جيد بما يكفي في مجموعة HTML المعتادة وCSS، يمكنك استخدام JavaScript لتحسينه. ويعني ذلك في كثير من الأحيان أنّه عليك البدء من الصفر. إنّ الانتقالات في CSS3 رائعة، ولكن لا يمكنك إضافة نوع انتقال جديد أو استخدام الانتقالات لإجراء أيّ عملية أخرى غير عناصر التصميم. مثال آخر: عمليات التحويل في CSS3 رائعة لمعالجة DOM، ولكن عند الانتقال إلى مساحة الرسم، ستتولى أنت إدارة هذه العمليات.

هذه المشاكل وغيرها هي سبب توفُّر محرك خاص لعملية النقل التحويل في Lem doodle. نعم، أعلم أنّه تمّت الإشارة إلى 2000 وما إلى ذلك، فالميزات التي أدرجتها ليست قريبة من فعالية CSS3، ولكن مهما كان ما يقوم به المحرك ، فهو ينفّذه بشكلٍ متّسق ويمنحنا مزيدًا من التحكّم.

لقد بدأت بنظام إجراءات بسيط (حدث) وهو مخطط زمني يطلق الأحداث في المستقبل بدون استخدام setTimeout، لأنّه في أي وقت معيّن يمكن أن ينفصل وقت الرسم عن الوقت الفعلي عندما يصبح أسرع (التقديم السريع) أو أبطأ (انخفاض معدل عرض اللقطات أو الدخول في وضع السكون لتوفير وحدة المعالجة المركزية) أو يتوقف تمامًا (انتظار انتهاء تحميل الصور).

إنّ الانتقالات هي نوع آخر من الإجراءات. بالإضافة إلى الحركات الأساسية والدوران، نسمح أيضًا باستخدام الحركات النسبية (مثل تحريك عنصر 10 بكسل إلى اليمين)، والعناصر المخصّصة مثل الارتعاش، بالإضافة إلى الصور المتحرّكة للصور الرئيسية.

لقد ذكرت عمليات الدوران، ويتم تنفيذها يدويًا أيضًا: لدينا صور متحرّكة لزوايا مختلفة للكائنات التي يجب تدويرها. والسبب الرئيسي هو أنّ عمليات تدوير CSS3 وcanvas كانت تؤدي إلى ظهور عناصر مرئية غير مقبولة، بالإضافة إلى أنّ هذه العناصر كانت تختلف من منصة إلى أخرى.

بما أنّ بعض الأجسام التي تدور تكون مرتبطة بغيرها من الأجسام الدوّارة، مثل يد الروبوت المرتبطة بالجزء السفلي من الذراع والتي تكون هي نفسها مرتبطة بالجزء العلوي من الذراع الدوّار، كان عليّ أيضًا إنشاء نقطة تحول بديلة على شكل نقاط محورية.

كلّ هذا يشكّل قدرًا كبيرًا من العمل الذي يغطي في النهاية المساحة التي تمّت تغطيتها من قِبل HTML5، ولكن في بعض الأحيان لا يكون التوافق الأصلي جيدًا بما يكفي، ويكون الوقت قد حان لإعادة ابتكار الحلول.

التعامل مع الصور والعناصر الصغيرة

لا يُستخدَم المحرّك فقط لتشغيل الصورة المتحرّكة، بل يمكن استخدامه أيضًا لتعديلها. لقد شاركنا بعض مَعلمات تصحيح الأخطاء أعلاه: يمكنك العثور على البقية في engine.readDebugParams.

إنشاء الصور المتحرّكة هو أسلوب معروف نستخدمه أيضًا في إنشاء الرسومات. ويسمح لنا ذلك ب توفير وحدات البايت وتقليل أوقات التحميل، بالإضافة إلى تسهيل التحميل المُسبَق. ومع ذلك، يزيد هذا الإجراء من صعوبة التطوير، لأنّ كل تغيير في الصور يتطلّب إعادة إنشاء ملفات sprit (يتم ذلك بشكل آلي إلى حد كبير، ولكن يظلّ مرهقًا). لذلك، يتوافق المحرّك مع التشغيل على الصور الأولية لعملية التطوير، بالإضافة إلى الصور الرمزية لعملية الإنتاج من خلال engine.useSprites، وكلاهما مضمّن في رمز المصدر.

رسم شعار Google للعبة Pac-Man
الصور الرمزية المستخدَمة في رسم شعار Pac-Man

تتيح لك هذه الميزة أيضًا تحميل الصور مسبقًا أثناء إنشاء الصورة المتحرّكة وإيقاف الميزة إذا لم يتم تحميل الصور في الوقت المناسب ، بالإضافة إلى شريط تقدم وهمي. (هذا الإجراء غير صحيح لأنّه لا يمكن حتى لـ HTML5 إعلامنا بحجم ملف الصورة الذي تم تحميله).

لقطة شاشة لرسم بياني للتحميل مع شريط التقدّم الذي تم التلاعب به
لقطة شاشة لرسم بياني للتحميل مع شريط التقدّم الذي تم التلاعب به

في بعض المشاهد، نستخدم أكثر من صورة متحركة واحدة، ليس كثيرًا لتسريع عملية loading باستخدام اتصالات متوازية، ولكن ببساطة بسبب الحدّ الأقصى المسموح به للصور على نظام التشغيل iOS وهو 3/5 مليون بكسل.

ما هو دور HTML5 في كل هذا؟ لا يتوفّر الكثير من هذه التقنيات أعلاه، ولكن أداة إنشاء الصور المصغرة أو اقتصاصها التي كتبتها كانت كلها تكنولوجيات ويب جديدة: لوحة الرسم والأشكال المتعدّدة a[download]. من الميزات المثيرة للاهتمام في HTML أنّه يتضمّن تدريجيًا إجراءات كان يجب إجراؤها في السابق خارج المتصفّح، والجزء الوحيد الذي كان علينا تنفيذه هو تحسين ملفات PNG.

حفظ الحالة بين المباريات

كانت عوالم ليام دائمًا كبيرة ونابضة بالحياة وواقعية. كانت قصصه تبدأ عادةً بدون الكثير من التفسيرات، وتبدأ الصفحة الأولى في منتصف القصة، وعلى القارئ أن يجد طريقه بنفسه.

لم يكن Cyberiad استثناءً، وأردنا تكرار هذا الشعور في الرسم. نبدأ بمحاولة عدم شرح القصة بشكل مفرط. يتمثل العنصر الآخر المؤثر في الأداء باستخدام الأرقام العشوائية التي تناسب الطبيعة الميكانيكية لعالم الكتاب. لدينا عدد من الدوالّ المساعِدة التي تتعامل مع الأرقام العشوائية ونستخدمها في العديد من المواضع.

أردنا أيضًا زيادة إمكانية إعادة تشغيل اللعبة بطرق أخرى. لهذا السبب، احتاجنا إلى معرفة عدد المرات التي تم فيها إنهاء الصورة المتحرّكة من قبل. إنّ الحلّ التكنولوجي الصحيح من الناحية التاريخية لهذه المشكلة هو ملف تعريف الارتباط، ولكنّه لا يعمل مع الصفحة الرئيسية في Google، لأنّ كل ملف تعريف ارتباط يزيد من حمولة كل صفحة، ونحن نهتم كثيرًا بالسرعة ووقت الاستجابة.

لحسن الحظ، يوفّر لنا HTML5 مساحة تخزين على الويب، وهي سهلة الاستخدام، ما يتيح لنا حفظ تذكر عدد مرات التشغيل العام والمشهد الأخير الذي شاهده المستخدم، وبطريقة أكثر سلاسة من ملفّات تعريف الارتباط.

كيف نتعامل مع هذه المعلومات؟

  • نعرض زرّ تقديم سريع، ما يتيح التنقّل بسرعة خلال المشاهد التي سبق للمستخدم مشاهدتها.
  • نعرض عددًا مختلفًا من العناصر N خلال النهاية.
  • رفعنا قليلاً من مستوى صعوبة التصوير
  • نعرض تنينًا صغيرًا من قصة مختلفة في المرة الثالثة والتالية من تشغيل اللعبة، وذلك كنوع من المفاجآت المخفية.

هناك عدد من مَعلمات تصحيح الأخطاء التي تتحكّم في ذلك:

  • ?doodle-debug&doodle-first-run – التظاهر بأنّه أول تشغيل
  • ?doodle-debug&doodle-second-run – التظاهر بأنّه إجراء إعادة تشغيل ثانية
  • ?doodle-debug&doodle-old-run – التظاهر بأنّه مسار قديم

الأجهزة التي تعمل باللمس

أردنا أن تبدو هذه الصورة المصغّرة مناسبة تمامًا على الأجهزة التي تعمل باللمس، لأنّ أحدث الأجهزة قوية بما يكفي لتشغيل هذه الصورة المصغّرة بشكل جيد، وتعدّ تجربة اللعب من خلال النقر على الشاشة أكثر متعةً من النقر عليها.

كان من الضروري إجراء بعض التغييرات المُسبقة على تجربة المستخدم. في الأصل، كان مؤشر الماوس هو المكان الوحيد الذي يشير إلى أنّه يتم عرض مشهد مقتطع/جزء غير تفاعلي. أضفنا لاحقًا مؤشرًا صغيرًا في أسفل يسار الشاشة، ما سمح لنا بعدم الاعتماد على مؤشر الماوس وحده (نظرًا لعدم توفّره على الأجهزة التي تعمل باللمس).

عادي مشغول يمكن النقر عليه تم النقر عليه
العمل قيد التقدّم
مؤشر العمل الجاري العادي
مؤشر مشغول للعمل قيد الإنجاز
مؤشر قابل للنقر يشير إلى أنّ العمل لا يزال قيد التقدّم
مؤشر النقر على العمل الجاري
النهائي
المؤشر العادي النهائيv
المؤشر النهائي للانشغال
المؤشر النهائي القابل للنقر
المؤشر الذي تم النقر عليه أخيرًا
مؤشرات الماوس أثناء التطوير، ونظائرها النهائية

عملت معظم العناصر على الفور. ومع ذلك، أظهرت اختبارات سهولة الاستخدام المفاجئة لتجربة اللمس لدينا مشكلتَين: كان من الصعب جدًا الضغط على بعض الأهداف، وتم تجاهل النقرات السريعة لأنّنا تجاوزنا أحداث نقرات الماوس.

لقد ساعدني كثيرًا استخدام عناصر DOM شفافة منفصلة يمكن النقر عليها، لأنّه كان بإمكاني تغيير حجمها بشكل مستقل عن العناصر المرئية. أضفت حشوة إضافية بحجم 15 بكسل للأجهزة التي تعمل باللمس وكنت أستخدمها عند إنشاء عناصر قابلة للنقر. (لقد أضفت أيضًا هامشًا بحجم 5 بكسل لأنظمة التشغيل التي تستخدم الماوس، فقط لإرضاء السيد Fitts).

بالنسبة إلى المشكلة الأخرى، تأكّدت للتو من إرفاق واختبار عناصر التحكّم المناسبة في بدء اللمس وانتهائه، بدلاً من الاعتماد على نقرة الماوس.

ونحن نستخدم أيضًا سمات أنماط أكثر حداثة لإزالة بعض ميزات اللمس التي تضيفها متصفّحات WebKit تلقائيًا (النقر على تمييز، والنقر على نص توضيحي).

كيف يمكننا معرفة ما إذا كان الجهاز الذي يعرض الرسم المتحرّك يتيح استخدام ميزة اللمس؟ ببطء. بدلاً من معرفة ذلك مسبقًا، استخدمنا فقط ذكاءنا الاصطناعي المجمّع لاستنتاج أنّ الجهاز يتوافق مع اللمس… بعد أن نحصل على حدث بدء اللمس الأول.

تخصيص مؤشر الماوس

ولكن ليست كل العناصر تعتمد على اللمس. كان أحد المبادئ الأساسية التي اتّبعناها هو تضمين أكبر عدد ممكن من العناصر في نطاق الصورة المتحرّكة. واجهة المستخدم الصغيرة للشريط الجانبي (الترجيع السريع وعلامة الاستفهام) ونصائح الاستخدام وحتى مؤشر الماوس.

كيف يمكن تخصيص مؤشر الماوس؟ تسمح بعض المتصفّحات بتغيير مؤشر الماوس من خلال الربط بملف صورة مخصّص. ومع ذلك، لا يُتاح استخدام هذه الميزة بشكل جيد، وهي أيضًا مقيّدة إلى حدٍ ما.

إذا لم يكن هذا هو الحلّ، ما هو الحلّ؟ لماذا لا نجعل مؤشر الماوس مجرّد عنصر آخر في الصورة المتحرّكة؟ يمكن إجراء ذلك، ولكن هناك عدد من الاحتياطات التي يجب أخذها في الاعتبار، وأهمها:

  • يجب أن يكون بإمكانك إزالة مؤشر الماوس الأصلي.
  • يجب أن تكون ماهرًا في الحفاظ على توافق مؤشر الماوس مع المؤشر "الحقيقي".

أما الطريقة الأولى، فهي صعبة. تسمح لغة CSS3 باستخدام cursor: none، ولكن هذه الميزة غير متاحة أيضًا في بعض المتصفحات. كان علينا اللجوء إلى بعض الحيل: استخدام ملف .cur فارغ كخيار احتياطي، وتحديد سلوك محدّد لبعض المتصفّحات، وحتى الترميز الثابت لمتصفّحات أخرى خارج تجربتنا على الإطلاق.

أما المشكلة الأخرى، فهي بسيطة نسبيًا، ولكن بما أنّ مؤشر الماوس هو جزء آخر من كون الرسم، سيرث كل مشاكله أيضًا. هل هو أكبر تحدٍّ؟ إذا كان عدد اللقطات في الثانية للرسم المتحرّك منخفضًا، سيكون عدد اللقطات في الثانية لمؤشر الماوس منخفضًا أيضًا، ما سيؤدي إلى عواقب وخيمة لأنّ مؤشر الماوس هو امتداد طبيعي ليدك، لذا يجب أن يكون سريع الاستجابة بغض النظر عن أي شيء. (يقرّ الحاضرون الذين استخدموا Commodore Amiga في السابق بصحة هذه العبارة ويهزّون رؤوسهم بقوة).

من بين الحلول المعقّدة إلى حدٍ ما لهذه المشكلة، فصل مؤشر الماوس عن حلقة التحديث العادية. لقد فعلنا ذلك في كونٍبديل لا أحتاج فيه إلى النوم. هل هناك حلّ أبسط لهذه المشكلة؟ ما عليك سوى الرجوع إلى مؤشر الماوس الأصلي إذا انخفض عدد اللقطات المتحركة إلى أقل من 20 لقطة في الثانية. (هذا هو المكان الذي يكون فيه معدل التبديل للصور مفيداً. إذا تفاعلنا مع معدّل عرض اللقطات الحالي، وإذا كان يتأرجح حول 20 لقطة في الثانية، سيرى المستخدم مؤشّر الماوس المخصّص يختفي ويظهر طوال الوقت.) يقودنا ذلك إلى:

نطاق عدد اللقطات في الثانية السلوك
>10 لقطات في الثانية يمكنك إبطاء سرعة اللعبة لتجنُّب فقدان المزيد من اللقطات.
من 10 إلى 20 لقطة في الثانية استخدِم مؤشّر الماوس الأصلي بدلاً من المؤشّر المخصّص.
من 20 إلى 60 لقطة في الثانية التشغيل العادي
أكثر من 60 لقطة في الثانية يمكنك ضبط معدّل نقل البيانات بحيث لا يتجاوز معدّل عرض اللقطات هذه القيمة.
ملخّص للسلوك الذي يعتمد على عدد اللقطات في الثانية

يُرجى العِلم أنّ مؤشر الماوس يظهر باللون الداكن على أجهزة Mac، ولكن باللون الأبيض على أجهزة الكمبيوتر الشخصي. لماذا؟ لأنّ حروب المنصات تحتاج إلى مزيد من الوقود حتى في الكون الخيالي.

الخاتمة

هذا المحرك ليس مثاليًا، ولكنه لا يحاول أن يكون كذلك. تم تطويره إلى جانب رسم Lem، وهو مرتبط به بشكل كبير. لا بأس، فكما قال دون كنوث في إحدى مقولاته الشهيرة: "التحسين المبكر هو أصل كل الشرور"، لا أعتقد أنّه من المنطقي كتابة محرك بشكل منفصل أولاً، وتطبيقه لاحقًا فقط، لأنّ الممارسة تُعلِم النظرية تمامًا كما تُعلِم النظرية الممارسة. في حالتي، تم تجاهل الرمز البرمجي، وإعادة كتابة عدة أجزاء مرارًا وتكرارًا، والعديد من القطع الشائعة لاحظت النشر، بدلاً من ante factum. في النهاية، سمحت لنا هذه التصاميم بتحقيق ما أردناه، وهو الاحتفال بحياة Stanisław Lem والرسومات التي رسمها Daniel Mróz بأفضل طريقة ممكنة.

نأمل أن يلقي القسم أعلاه الضوء على بعض خيارات التصميم والمفاضلات التي كان علينا اتخاذها، وكيفية استخدامنا لـ HTML5 في سيناريو محدّد في الحياة اليومية. الآن، يمكنك استخدام رمز المصدر واختباره وإعلامنا برأيك.

لقد أنشأتُ هذا الرسم بنفسي. وقد كان معروضًا على الإنترنت في الأيام الأخيرة، وكان العد التنازلي يقترب من الساعات الأولى من يوم 23 تشرين الثاني (نوفمبر) 2011 في روسيا، وهي المنطقة الزمنية الأولى التي ظهرت فيها رسمة شعار Lem. قد يبدو هذا الأمر مضحكًا، ولكن تمامًا مثل الرموز المضحكة، فإنّ الأشياء التي تبدو غير مهمة في بعض الأحيان لها معنى عميق، فقد كان هذا المقياس "اختبارًا قاسيًا" رائعًا للمحرّك.

لقطة شاشة لساعة العد التنازلي في رسم Lem المخصّص للعالم
لقطة شاشة لساعة العد التنازلي في رسم Lem المتحرك

وهذه إحدى الطرق للنظر إلى رحلة إنشاء رسم Google Doodle: أشهر من العمل، أسابيع من الاختبار، 48 ساعة من الإعداد، وكل ذلك من أجل لعبة يلعبها المستخدمون لمدة خمس دقائق. نأمل أن تكون هذه الدقائق الخمس مُجديةً، وذلك من خلال كل سطر من سطور JavaScript الآلاف. مع أطيب التحيّات،