우수사례 - 스타니스와프 렘 Google 기념일 로고 제작

Marcin Wichary
Marcin Wichary

Hello, (strange) world

Google 홈페이지는 코딩하기에 매력적인 환경입니다. 속도와 지연 시간에 대한 특별한 관심, 모든 종류의 브라우저를 지원하고 다양한 상황에서 작동해야 하는 까다로운 제한사항이 많습니다. 그리고 놀라움과 즐거움도 있습니다.

가끔 로고를 대체하는 특별한 일러스트인 Google 기념일 로고를 말하는 것입니다. 펜과 브러시와의 관계는 오랫동안 금지 명령의 독특한 풍미가 있었지만, 저는 종종 양방향 금지 명령에 기여합니다.

제가 코딩한 모든 양방향 두들 (팩맨, 쥘 베른, 세계 박람회)과 제가 도움을 준 많은 두들은 미래지향적이면서도 시대착오적이었습니다. 최신 웹 기능을 적용한 공상 과학적 애플리케이션을 위한 좋은 기회였지만, 크로스브라우저 호환성의 실용적인 측면도 있었습니다.

Google은 상호작용 드 doodle에서 많은 것을 배웁니다. 최근의 스테니스와프 렘 미니 게임도 예외가 아니었습니다. 17,000줄의 JavaScript 코드가 드 doodle 역사상 처음으로 여러 가지를 시도했습니다. 오늘은 이 코드를 여러분과 공유하고자 합니다. 흥미로운 점을 발견하거나 실수를 지적해 주시면 감사하겠습니다.

스타니스와프 렘 두들 코드 보기 »

Google 홈페이지는 기술 데모를 위한 공간이 아닙니다. Google은 특정 인물과 사건을 기념하기 위해 두들을 제작하며, 이를 위해 최상의 아트와 기술을 사용하고자 합니다. 단, 기술 자체를 기념하기 위한 두들은 제작하지 않습니다. 즉, 광범위하게 이해되는 HTML5의 사용 가능한 부분을 신중하게 살펴보고, 이러한 부분이 주의를 분산시키거나 가리지 않고 더 나은 두들을 만드는 데 도움이 되는지 확인해야 합니다.

이제 스타니스와프 렘 두들에서 사용된 최신 웹 기술과 사용되지 않은 최신 웹 기술을 살펴보겠습니다.

DOM 및 캔버스를 통한 그래픽

캔버스는 강력하며 이 두들에서 하고자 하는 작업에 맞게 만들어졌습니다. 하지만 우리가 중요하게 생각하는 일부 이전 브라우저에서는 이를 지원하지 않았습니다. 훌륭한 excanvas를 만든 사람과 사무실을 공유하고 있지만 다른 방법을 선택하기로 했습니다.

'rects'라는 그래픽 원시를 추상화하는 그래픽 엔진을 만든 다음 캔버스를 사용할 수 없는 경우 DOM을 사용하여 렌더링합니다.

이 접근 방식에는 몇 가지 흥미로운 문제가 있습니다. 예를 들어 DOM에서 객체를 이동하거나 변경하면 즉각적인 결과가 발생하지만, 캔버스에서는 모든 것이 동시에 그려지는 특정 순간이 있습니다. 캔버스를 하나만 두고 프레임마다 캔버스를 지우고 처음부터 다시 그리기로 했습니다. 한편으로는 움직이는 부분이 너무 많고 다른 한편으로는 겹치는 여러 캔버스로 분할하고 선택적으로 업데이트할 만큼 복잡하지는 않습니다.)

안타깝게도 캔버스로 전환하는 것은 drawImage()로 CSS 배경을 미러링하는 것만큼 간단하지 않습니다. DOM을 통해 여러 항목을 조합할 때 무료로 제공되는 여러 항목(가장 중요한 것은 z 인덱스 레이어링 및 마우스 이벤트)이 사라집니다.

저는 이미 '평면'이라는 개념으로 z-index를 추상화했습니다. 두들은 멀리 뒤에 있는 하늘부터 모든 것 앞에 있는 마우스 포인터까지 여러 평면을 정의했으며 두들 내의 모든 행위자는 자신이 속한 평면을 결정해야 했습니다 (planeCorrection를 사용하여 평면 내에서 작은 더하기/빼기 수정 가능).

DOM을 통해 렌더링하면 평면이 z-index로 간단히 변환됩니다. 하지만 캔버스를 통해 렌더링하는 경우 직사각형을 그리기 전에 평면을 기준으로 직사각형을 정렬해야 합니다. 매번 이렇게 하면 비용이 많이 들기 때문에 행위자가 추가되거나 다른 평면으로 이동할 때만 순서가 다시 계산됩니다.

마우스 이벤트도 추상화했습니다. DOM과 캔버스 모두 z 인덱스가 높은 완전히 투명한 플로팅 DOM 요소를 추가로 사용했습니다. 이 요소의 기능은 마우스 오버/아웃, 클릭, 탭에만 반응하는 것입니다.

이번 두들에서 시도하고자 한 것 중 하나는 4차원 벽을 허무는 것이었습니다. 위 엔진을 사용하면 캔버스 기반 행위자를 DOM 기반 행위자와 결합할 수 있습니다. 예를 들어 피날레의 폭발은 내부 세계 객체의 캔버스와 나머지 Google 홈페이지의 DOM에 모두 있습니다. 새는 평소에 다른 행위자처럼 날아다니며 들쭉날쭉한 마스크에 의해 잘리지만 촬영 수준에서는 문제를 피하기로 결정하고 무작위 버튼에 앉습니다. 새가 캔버스를 떠나 DOM 요소가 되고 나중에 그 반대로 전환되는 방식으로, 방문자에게 완전히 투명하게 보이기를 바랐습니다.

프레임 속도

현재 프레임 속도를 파악하고 속도가 너무 느려지거나 너무 빨라질 때 이에 대응하는 것이 엔진의 중요한 부분이었습니다. 브라우저는 프레임 속도를 다시 보고하지 않으므로 직접 계산해야 합니다.

먼저 requestAnimationFrame을 사용하고, 이를 사용할 수 없는 경우 기존의 setTimeout로 대체했습니다. requestAnimationFrame는 일부 상황에서는 CPU를 영리하게 절약합니다. 아래에서 설명하는 것처럼 일부 작업은 자체적으로 실행하지만 setTimeout보다 높은 프레임 속도를 얻을 수도 있습니다.

현재 프레임 속도를 계산하는 것은 간단하지만 급격한 변화가 있을 수 있습니다. 예를 들어 다른 애플리케이션이 잠시 동안 컴퓨터를 독점하면 빠르게 떨어질 수 있습니다. 따라서 모든 실제 틱 100개마다 '롤링'(평균) 프레임 속도를 계산하고 이를 기반으로 결정을 내립니다.

어떤 종류의 결정일까요?

  • 프레임 속도가 60fps를 초과하면 제한됩니다. 현재 일부 Firefox 버전의 requestAnimationFrame에는 프레임 속도에 상한선이 없으며 CPU를 낭비할 이유가 없습니다. 다른 브라우저에서 프레임 속도가 60fps보다 약간 높아지는 반올림 오류로 인해 실제로는 65fps로 제한됩니다. 실수로 제한을 시작하고 싶지 않습니다.

  • 프레임 속도가 10fps 미만이면 프레임을 삭제하는 대신 엔진 속도를 줄입니다. 모두에게 손실이 되는 상황입니다. 하지만 프레임을 과도하게 건너뛰는 것이 단순히 느린 (하지만 일관된) 게임을 제공하는 것보다 더 혼란스러울 것 같았습니다. 또 다른 좋은 부작용도 있습니다. 시스템이 일시적으로 느려지더라도 엔진이 필사적으로 따라잡기 위해 갑자기 앞으로 이동하는 이상한 현상이 발생하지 않습니다. (Pac-Man의 경우 약간 다르게 했지만 최소 프레임 속도가 더 나은 접근 방식입니다.)

  • 마지막으로 프레임 속도가 위험할 정도로 낮아지면 그래픽을 간소화할 수 있습니다. 마우스 포인터를 제외하고는 렘 낙서에 적용하지는 않지만, 가령 느린 컴퓨터에서도 낙서가 부드럽게 느껴지도록 불필요한 애니메이션을 일부 삭제할 수 있습니다.

물리적 틱과 논리적 틱이라는 개념도 있습니다. 전자는 requestAnimationFrame/setTimeout에서 가져옵니다. 일반 게임플레이의 비율은 1:1이지만, 빨리 감기의 경우 실제 틱당 더 많은 로직 틱을 추가합니다 (최대 1:5). 이렇게 하면 모든 논리적 틱에 필요한 모든 계산을 실행할 수 있지만 마지막 틱만 화면의 항목을 업데이트하도록 지정할 수 있습니다.

벤치마킹

캔버스가 사용 가능한 경우 언제나 DOM보다 빠르다는 가정을 할 수 있습니다 (실제로 초기에는 그렇게 가정했습니다). 항상 그런 것은 아닙니다. 테스트 결과, Mac의 Opera 10.0~10.1 및 Linux의 Firefox가 DOM 요소를 이동할 때 실제로 더 빠른 것으로 나타났습니다.

이상적인 상황에서는 드로잉이 style.leftstyle.top를 사용하여 이동하는 DOM 요소, 캔버스에 그리기, CSS3 변환을 사용하여 이동하는 DOM 요소 등 다양한 그래픽 기법을 자동으로 벤치마킹합니다.

– 그런 다음 프레임 속도가 가장 높은 것으로 전환합니다. 이를 위한 코드를 작성하기 시작했지만, 적어도 내가 사용하는 벤치마킹 방식은 상당히 신뢰할 수 없고 시간이 많이 걸린다는 것을 알게 되었습니다. 홈페이지에 표시할 시간이 없습니다. Google은 속도를 매우 중요하게 생각하며 사용자가 클릭하거나 탭하는 즉시 두들기기가 표시되고 게임플레이가 시작되기를 바랍니다.

결국 웹 개발은 해야 할 일을 해야 하는 것으로 귀결됩니다. 뒤를 돌아 아무도 보고 있지 않은지 확인한 다음 캔버스에서 Opera 10과 Firefox를 하드코딩했습니다. 다음 생에는 <marquee> 태그로 돌아오겠습니다.

CPU 절약

집에 놀러 와서 Breaking Bad 시즌 피날레를 시청한 후 스포일러를 알려주고 DVR에서 삭제하는 친구가 있나요? 그런 사람이 되고 싶지 않으시겠죠?

그렇습니다. 최악의 비유입니다. 하지만 Google Doodle이 그런 존재가 되기를 바라지도 않습니다. 누군가의 브라우저 탭에 표시될 수 있다는 것은 특권이며 CPU 사이클을 독점하거나 사용자의 주의를 분산시키는 것은 Google Doodle을 불쾌한 존재로 만들 것입니다. 따라서 아무도 낙서를 사용하지 않으면(탭, 마우스 클릭, 마우스 움직임, 키 누르기 없음) 결국 절전 모드로 전환되도록 해야 합니다.

일시

  • 홈페이지에서 18초 후 (아케이드 게임에서는 이를 어트랙트 모드라고 함)
  • 탭에 포커스가 있는 경우 180초 후
  • 탭에 포커스가 없으면 30초 후 (예: 사용자가 다른 창으로 전환했지만 비활성 탭에서 여전히 낙서를 시청하고 있는 경우)
  • 탭이 보이지 않게 되면 즉시 (예: 사용자가 동일한 창에서 다른 탭으로 전환함 - 표시되지 않으면 사이클을 낭비할 필요가 없음)

현재 탭에 포커스가 있는지 어떻게 알 수 있나요? window.focuswindow.blur에 연결합니다. 탭이 표시되는지 어떻게 알 수 있나요? 새로운 Page Visibility API를 사용하고 적절한 이벤트에 반응합니다.

위의 시간 제한은 평소보다 관대한 편입니다. 나는 이러한 애니메이션을 배경 애니메이션 (주로 하늘과 새)이 많이 포함된 이 특정 두들에 맞게 조정했습니다. 이상적으로는 시간 초과가 게임 내 상호작용에 따라 제한되어야 합니다.예를 들어 착륙 직후 새가 이제 잠을 잘 수 있다고 드로잉에 다시 보고할 수 있습니다. 하지만 결국에는 구현하지 않았습니다.

하늘은 항상 움직이기 때문에 잠들거나 깨어날 때 두들은 멈추거나 시작하지 않습니다. 일시중지하기 전에 속도가 느려지고 다시 시작할 때는 그 반대로 속도가 빨라지며, 필요한 경우 실제 틱당 논리적 틱 수를 늘리거나 줄입니다.

전환, 변환, 이벤트

HTML의 강점 중 하나는 항상 직접 개선할 수 있다는 것입니다. HTML 및 CSS의 일반 포트폴리오에서 충분하지 않은 경우 JavaScript를 사용하여 확장할 수 있습니다. 안타깝게도 처음부터 다시 시작해야 하는 경우가 많습니다. CSS3 전환은 좋지만 새 전환 유형을 추가하거나 전환을 사용하여 요소의 스타일을 지정하는 것 이외의 작업을 할 수는 없습니다. 또 다른 예: CSS3 변환은 DOM에 적합하지만 캔버스로 이동하면 갑자기 혼자입니다.

이러한 문제로 인해 Lem Doodle에는 자체 전환 및 변환 엔진이 있습니다. 2000년대라고 뭐라고 할 수도 있겠지만, 제가 내장한 기능은 CSS3만큼 강력하지는 않습니다. 하지만 엔진이 하는 모든 작업은 일관되게 이루어지며 훨씬 더 많은 제어 기능을 제공합니다.

간단한 작업(이벤트) 시스템으로 시작했습니다. 이 시스템은 setTimeout를 사용하지 않고 향후 이벤트를 실행하는 타임라인입니다. 특정 시점에서 낙서 시간이 더 빨라지거나 (빨리 감기), 느려지거나(프레임 속도가 느리거나 CPU 절약을 위해 절전 모드로 전환), 완전히 중지되면(이미지 로드가 완료될 때까지 기다림) 실제 시간과 분리될 수 있기 때문입니다.

전환은 다른 유형의 작업일 뿐입니다. 기본적인 움직임과 회전 외에도 상대적 움직임 (예: 오른쪽으로 10픽셀 이동), 흔들림과 같은 맞춤 항목, 키프레임 이미지 애니메이션도 지원합니다.

회전도 수동으로 실행됩니다. 회전해야 하는 객체의 다양한 각도에 관한 스프라이트가 있습니다. 주된 이유는 CSS3 및 캔버스 회전 모두 허용되지 않는 시각적 아티팩트를 도입했기 때문입니다. 게다가 이러한 아티팩트는 플랫폼마다 다릅니다.

회전하는 일부 객체가 다른 회전 객체에 연결되어 있습니다. 예를 들어 회전하는 상완에 연결된 하완에 연결된 로봇의 손이 여기에 해당합니다. 따라서 피벗 형태로 변환 출처를 대신 만들어야 했습니다.

이 모든 작업은 궁극적으로 HTML5에서 이미 처리한 영역을 다루는 상당한 양의 작업입니다. 하지만 네이티브 지원이 충분하지 않은 경우도 있으며, 이때는 혁신을 통해 새로운 방법을 찾아야 합니다.

이미지 및 스프라이트 처리

엔진은 두들 작동뿐만 아니라 두들 작업에도 사용됩니다. 위에서 몇 가지 디버그 매개변수를 공유했습니다. 나머지는 engine.readDebugParams에서 확인할 수 있습니다.

스프라이팅은 Google에서도 낙서에 사용하는 잘 알려진 기법입니다. 이를 통해 바이트를 절약하고 로드 시간을 줄일 수 있으며 미리 로드하기가 더 쉬워집니다. 하지만 개발도 더 어려워집니다. 이미지를 변경할 때마다 스프라이트를 다시 만들어야 하기 때문입니다 (대부분 자동화되지만 여전히 번거롭습니다). 따라서 엔진은 개발을 위한 원시 이미지와 engine.useSprites를 통한 프로덕션용 스프라이트에서 실행을 지원합니다. 두 가지 모두 소스 코드에 포함되어 있습니다.

팩맨 기념일 로고
Pac-Man 낙서에서 사용되는 스프라이트입니다.

또한 이미지를 미리 로드하고 이미지가 제때 로드되지 않으면 드 doodle을 중지하는 기능도 지원합니다. 가짜 진행률 표시줄도 제공됩니다. (불행히도 HTML5조차도 이미지 파일 중 얼마나 많은 부분이 이미 로드되었는지 알 수 없으므로 가짜입니다.)

조작된 진행률 표시줄이 있는 로드 그래픽의 스크린샷
조작된 진행률 표시줄이 있는 로드 그래픽의 스크린샷

일부 장면에서는 병렬 연결을 사용하여 로드 속도를 높이기 위해서가 아니라 iOS의 이미지에 적용되는 350만 픽셀 제한 때문에 두 개 이상의 스프라이트를 사용합니다.

HTML5는 이 모든 것과 어떤 관련이 있나요? 위에는 별로 없지만 제가 스프라이팅/자르기에 작성한 도구는 모두 새로운 웹 기술(캔버스, blob, a[download])이었습니다. HTML의 흥미로운 점 중 하나는 이전에는 브라우저 외부에서 실행해야 했던 작업을 점진적으로 포함한다는 것입니다. 여기서 해야 할 유일한 작업은 PNG 파일을 최적화하는 것이었습니다.

게임 간에 상태 저장

렘의 세계는 항상 크고 생생하며 사실적으로 느껴졌습니다. 그의 이야기는 일반적으로 설명 없이 시작되었으며, 첫 페이지는 미디어스레스(중간에 시작)로 시작하여 독자가 스스로 길을 찾아야 했습니다.

사이버리아드도 예외가 아니며 Google은 그 느낌을 Doodle에 재현하고자 했습니다. 먼저 스토리를 과도하게 설명하지 않도록 합니다. 또 다른 중요한 부분은 책의 세계관에 적합하다고 생각한 무작위 생성입니다. 무작위 생성을 처리하는 여러 도우미 함수가 있으며 이를 여러 위치에서 사용합니다.

다른 방식으로 재생성을 높이고자 했습니다. 이를 위해 이전에 낙서가 완료된 횟수를 알아야 했습니다. 이에 대한 역사적으로 올바른 기술적 해결책은 쿠키이지만 Google 홈페이지에는 적합하지 않습니다. 모든 쿠키는 모든 페이지의 페이로드를 늘리며, 속도와 지연 시간은 Google에서 매우 중요하기 때문입니다.

다행히 HTML5에서는 사용하기 간단한 웹 저장소를 제공하므로 쿠키에서 허용하는 것보다 훨씬 더 우아하게 일반 재생 횟수와 사용자가 재생한 마지막 장면을 저장하고 호출할 수 있습니다.

이 정보는 어떻게 사용되나요?

  • 사용자가 이전에 이미 본 컷신을 빠르게 지나갈 수 있는 빨리 감기 버튼을 표시합니다.
  • 피날레 중에 서로 다른 N개의 항목을 표시합니다.
  • 촬영 수준의 난이도를 약간 높였습니다.
  • 세 번째 재생부터는 다른 이야기의 작은 이스터 에그 확률 드래곤이 표시됩니다.

이를 제어하는 여러 디버그 매개변수가 있습니다.

  • ?doodle-debug&doodle-first-run – 첫 실행인 것처럼 척합니다.
  • ?doodle-debug&doodle-second-run – 두 번째 실행인 것처럼 척합니다.
  • ?doodle-debug&doodle-old-run – 이전 런으로 간주

터치 기기

Google은 드 doodle이 터치 기기에서 자연스럽게 작동하기를 바랐습니다. 최신 기기는 성능이 뛰어나 드 doodle이 원활하게 실행되며 탭을 통해 게임을 경험하는 것이 클릭보다 훨씬 더 재미있습니다.

사용자 환경을 사전에 일부 변경해야 했습니다. 원래 마우스 포인터는 컷신/비대화형 부분이 진행 중임을 알리는 유일한 장소였습니다. 나중에 오른쪽 하단에 작은 표시기를 추가하여 터치 기기에는 마우스 포인터가 없으므로 마우스 포인터만 사용할 필요가 없었습니다.

보통 바쁨 클릭 가능 클릭함
진행 중인 작업
진행 중인 일반 포인터
진행 중인 작업 바쁜 포인터
진행 중인 작업 클릭 가능한 포인터
진행 중인 작업을 클릭한 포인터
종료
최종 일반 포인터v
최종 사용 중인 포인터
클릭 가능한 최종 포인터
마지막으로 클릭한 포인터
개발 중 마우스 포인터와 최종 등가 항목

대부분의 기능은 즉시 작동했습니다. 하지만 터치 환경에 대한 즉석 사용성 테스트에서 두 가지 문제가 발견되었습니다. 일부 타겟은 너무 세게 눌러야 했고, 마우스 클릭 이벤트를 재정의했기 때문에 빠른 탭이 무시되었습니다.

클릭 가능한 투명한 DOM 요소를 별도로 두면 시각 자료와 별도로 크기를 조절할 수 있으므로 큰 도움이 되었습니다. 터치 기기에 15픽셀의 추가 패딩을 도입하고 클릭 가능한 요소가 생성될 때마다 이를 사용했습니다. 피츠 씨를 기쁘게 하기 위해 마우스 환경에도 5픽셀 패딩을 추가했습니다.

다른 문제의 경우 마우스 클릭을 사용하는 대신 적절한 터치 시작 및 종료 핸들러를 연결하고 테스트했습니다.

또한 더 현대적인 스타일 속성을 사용하여 WebKit 브라우저에서 기본적으로 추가하는 일부 터치 기능 (탭 강조 표시, 탭 콜아웃)을 삭제하고 있습니다.

그리고 낙서를 실행하는 특정 기기가 터치를 지원하는지 어떻게 감지하나요? 느긋하게. 사전에 이를 파악하는 대신, 첫 번째 터치 시작 이벤트를 받은 후 결합된 IQ를 사용하여 기기가 터치를 지원한다고 추론했습니다.

마우스 포인터 맞춤설정

하지만 모든 것이 터치 기반은 아닙니다. Google의 기본 원칙 중 하나는 두들의 세계에 최대한 많은 항목을 포함하는 것이었습니다. 작은 사이드바 UI (빨리 감기, 물음표), 도움말, 마우스 포인터까지도

마우스 포인터를 맞춤설정하는 방법 일부 브라우저에서는 맞춤 이미지 파일에 연결하여 마우스 커서를 변경할 수 있습니다. 하지만 이 방법은 지원이 잘 되지 않고 다소 제한적입니다.

그렇지 않다면 어떻게 해야 하나요? 마우스 포인터를 드 doodle의 또 다른 행위자로 만들면 어떨까요? 이 방법은 작동하지만 몇 가지 단점이 있습니다.

  • 네이티브 마우스 포인터를 삭제할 수 있어야 합니다.
  • 마우스 포인터를 '실제' 포인터와 동기화하는 데 능숙해야 합니다.

전자는 까다롭습니다. CSS3에서는 cursor: none를 허용하지만 일부 브라우저에서는 지원되지 않습니다. 이를 위해 몇 가지 기교를 사용해야 했습니다. 빈 .cur 파일을 대체로 사용하고, 일부 브라우저에 구체적인 동작을 지정하고, 경험에서 다른 브라우저를 완전히 하드코딩했습니다.

다른 하나는 표면적으로는 비교적 사소하지만 마우스 포인터가 낙서 세계의 또 다른 부분이므로 모든 문제를 상속받습니다. 가장 큰 도전과제는 무엇일까요? 낙서 프레임 속도가 낮으면 마우스 포인터의 프레임 속도도 낮아집니다. 마우스 포인터는 손의 자연스러운 연장선이므로 어떤 상황에서도 반응이 있어야 하므로 이는 심각한 결과를 초래합니다. (이전에 Commodore Amiga를 사용한 사람들은 이제 고개를 끄덕입니다.)

이 문제를 해결하는 다소 복잡한 방법 중 하나는 마우스 포인터를 일반 업데이트 루프에서 분리하는 것입니다. 실제로 그렇게 했습니다. 제가 잠을 잘 필요가 없는 대체 우주에서요. 더 간단한 해결 방법이 있나요? 롤링 프레임 속도가 20fps 미만으로 떨어지면 기본 마우스 포인터로 되돌립니다. 이때 롤링 프레임 속도가 유용합니다. 현재 프레임 속도에 반응하고 20fps 주변에서 흔들리면 맞춤 마우스 포인터가 항상 숨겨졌다가 표시되는 것을 볼 수 있습니다.) 다음과 같은 이점이 있습니다.

프레임 속도 범위 동작
10fps 초과 더 많은 프레임이 누락되지 않도록 게임 속도를 줄입니다.
10~20fps 맞춤 마우스 포인터 대신 네이티브 마우스 포인터를 사용합니다.
20~60fps 정상 작동
60fps 초과 프레임 속도가 이 값을 초과하지 않도록 제한합니다.
프레임 속도에 종속된 동작의 요약입니다.

마우스 포인터는 Mac에서는 어둡지만 PC에서는 흰색입니다. 왜냐하면 가상의 세계에서도 플랫폼 전쟁에는 연료가 필요하기 때문입니다.

결론

완벽한 엔진은 아니지만 완벽을 추구하지는 않습니다. 렘 드 doodle과 함께 개발되었으며 렘 드 doodle에만 적용됩니다. 괜찮습니다. 도널드 커누스가 유명하게 말한 것처럼'성급한 최적화는 모든 악의 근원'입니다. 먼저 엔진을 단독으로 작성하고 나중에 적용하는 것이 합리적이라고 생각하지 않습니다. 이론이 실무에 도움이 되는 만큼 실무도 이론에 도움이 됩니다. 제 경우에는 코드가 삭제되고 여러 부분이 반복해서 재작성되었으며 많은 일반적인 부분이 ante factum이 아닌 post를 발견했습니다. 하지만 결국 우리가 원하는 바를 할 수 있었습니다. 바로 스타니스와프 렘의 경력과 다니엘 마르조의 그림을 생각할 수 있는 최선의 방법으로 기념하는 것입니다.

위 내용을 통해 Google에서 취해야 했던 몇 가지 디자인 선택사항과 절충사항, 그리고 특정 실제 시나리오에서 HTML5를 사용한 방법을 이해하는 데 도움이 되었기를 바랍니다. 이제 소스 코드를 사용해 보고 의견을 알려주세요.

제가 직접 했습니다. 아래는 러시아에서 렘 기념일 로고가 처음으로 표시된 시간대인 2011년 11월 23일 새벽까지 카운트다운하는 마지막 날의 실시간 화면입니다. 우스꽝스러울 수도 있지만, 낙서처럼 중요하지 않아 보이는 것에도 때로는 더 깊은 의미가 있습니다. 이 카운터는 엔진에 대한 훌륭한 '스트레스 테스트'였습니다.

렘 기념일 로고 우주 카운트다운 시계의 스크린샷
Lem Doodle의 내부 카운트다운 시계 스크린샷

Google 두들의 수명은 한 가지 측면에서 볼 때 몇 개월의 작업, 몇 주간의 테스트, 48시간의 베이킹을 거쳐 만들어지며, 이 모든 과정은 사람들이 5분 동안 즐길 수 있는 두들 하나를 위해 진행됩니다. 수천 개의 JavaScript 라인은 모두 5분이 잘 보냈으면 하는 바람을 담고 있습니다. 즐기시기 바랍니다.