1 पॉइंट द्वारा GN⁺ 2025-02-22 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • बंद न किए गए tab bar की खाली जगह को स्क्रीन की तरह इस्तेमाल करते हुए, Chrome के 240 टैब के favicon को पिक्सेल के रूप में उपयोग करने वाला Pong प्रयोग बनाया गया
  • 8×30 टैब ग्रिड AppleScript से बनाया गया, और हर टैब URL query में मौजूद windowIndex और tabIndex से अपनी position निकालता है
  • background tabs में setInterval लगभग 1 सेकंड के अंतराल तक धीमा हो गया था, लेकिन timer को Web Worker में ले जाने पर favicon refresh पर्याप्त तेज़ हो गया
  • server WebSocket की जगह Broadcast Channel API से समान domain वाले टैब synchronize किए गए, और सभी टैब registration पूरी होने के बाद main tab ने animation शुरू किया
  • सबसे बड़ा bottleneck हर frame में सैकड़ों favicon दोबारा बनाना था; सिर्फ वास्तव में बदले हुए टैब update करने पर animation काफी ज़्यादा smooth हो गया

240 टैब को एक स्क्रीन की तरह इस्तेमाल करने का तरीका

  • यह project बंद न किए गए browser tabs द्वारा घेर ली गई जगह का उपयोग करके Pong चलाने का एक प्रयोग है
  • स्क्रीन Chrome की 8 windows और हर window में 30 tabs से बने 8×30 tab grid से बनी है
  • ball और paddles सामने वाली window के HTML canvas और ऊपर के tab bar के favicon area के बीच लगातार move करते हैं
  • code GitHub पर faviconic में公開 है, और इसके साथ prototype स्थिति का “awful” code होने की चेतावनी दी गई है

Flappy Favi से शुरू हुआ idea

  • प्रेरणा Tru द्वारा बनाए गए favicon के अंदर चलने वाले Flappy Bird version Flappy Favi से मिली
  • favicon browser tab bar में दिखने वाली छोटी image होती है, लेकिन एक ही favicon बहुत छोटा होता है और देखना मुश्किल होता है
  • कई tabs में फैली image draw करने के लिए पहले तीन समस्याएं हल करनी थीं
    • tabs को देखने में अच्छा लगने वाले grid में arrange करने का तरीका
    • background tabs में भी favicon को तेज़ी से update करने का तरीका
    • कई tabs की screen को आपस में synchronize करने का तरीका

AppleScript से Chrome tab grid बनाना

  • शुरुआत में Chrome का new tab button बार-बार दबाकर tabs को छोटा किया गया, फिर दूसरी window को align करके दूसरी row बनाई गई, ताकि feasibility देखी जा सके
  • बड़ा grid manually बनाना झंझट भरा था, इसलिए इसे AppleScript से automate किया गया
  • script Chrome की 8 windows खोलती है, हर window में 30 tabs बनाती है, और windows को इस तरह position करती है कि वे एक-दूसरे के ऊपर stack हों
  • Chrome द्वारा बंद किए गए tabs को फिर से खोलने की कोशिश करने की समस्या थी, इसलिए script शुरू करते समय इसे साफ करना पड़ा
  • हर tab URL में windowIndex और tabIndex शामिल होते हैं
    • आखिरी खुले tab में isMain=true, numWindows, numTabs, fullWidth जैसे अतिरिक्त parameters लगते हैं

background tabs में favicon को तेज़ी से refresh करना

  • browser default favicon URL ढूंढता है, लेकिन HTML head में favicon location बताने वाला element जोड़कर और उसे update करके icon बदला जा सकता है
  • Chrome में favicon refresh अनुभव के अनुसार लगभग 4 बार प्रति सेकंड के स्तर का है
  • background tabs में resource usage सीमित होता है, इसलिए 250ms पर favicon बदलने वाला छोटा loop भी लगभग 1 सेकंड में सिर्फ एक बार चल रहा था
  • Web Audio API के background audio callback को workaround के तौर पर इस्तेमाल करने की कोशिश की गई, लेकिन वह ठीक से काम नहीं कर पाया
  • बाद में timer को Web Worker में ले जाकर, worker से main document को message भेजकर favicon update कराने पर समस्या हल हो गई
  • example structure में worker emoji को OffscreenCanvas पर draw करता है, उसे data URL में convert करता है, और फिर main document को भेजता है
    • main document link rel="shortcut icon" के href को बदलकर असल favicon update करता है

Broadcast Channel से tab registration और synchronization संभालना

  • tabs के बीच communication में दो चुनौतियां थीं
    • हर tab को पता होना चाहिए कि वह किस number की window का किस number का tab है
    • tab updates भेजने के लिए कौन सा communication channel इस्तेमाल करना है, यह तय करना था
  • position पता करना AppleScript द्वारा डाले गए URL query parameters से windowIndex और tabIndex पढ़कर हल किया गया
  • शुरुआती proof of concept में हर tab WebSocket server से connect करता था और server images भेजता था
  • WebSocket तरीका project के लक्ष्य से अच्छी तरह मेल नहीं खाता था
    • server के बिना दुनिया भर के browser tabs में deploy करना चाहने वाली aesthetic वजह से टकराता था
    • हर tab का connection समय अलग होता था, इसलिए updates synchronized नहीं रहते थे
  • इसके बाद समान domain के कई tabs तक जानकारी पहुंचाने वाले Broadcast Channel API पर switch किया गया
  • background tab अपने tab/window index वाला registration message broadcast channel पर भेजता है, और main tab उसे पाकर ack लौटाता है
  • main tab सभी background tabs की registration मिलने के बाद animation शुरू करता है

canvas और favicon की alignment मिलाना

  • सामने वाली window में draw की गई objects ऐसी दिखें जैसे वे tab bar में “घुस” रही हों, इसके लिए असल canvas और ऊपर के favicons को एक extended canvas की तरह treat किया गया
  • implementation में Chrome window के actual dimensions खुद मापने पड़े
    • Chrome window के left edge से पहले favicon तक 92 pixels
    • favicon के bottom से actual window top तक 58 pixels
    • favicon size 16×16
  • इन measurements और tabs/windows की संख्या का उपयोग करके तीन values calculate की गईं
    • favicon से align होने के लिए display किए जाने वाले canvas की width
    • हर tab की width
    • favicon row, URL bar और actual canvas समेत पूरे “canvas” की width और height
  • अगर rectangle URL bar के नीचे है तो उसे actual canvas पर draw किया जाता है, और अगर URL bar के ऊपर है तो उस area की जानकारी दूसरे tabs को broadcast की जाती है
  • हर tab अपने pixel coordinates calculate करने के बाद favicon को white/black pixels से update करता है

bottleneck data transfer नहीं, favicon generation था

  • शुरुआती implementation चल तो रहा था, लेकिन canvas animation अटक रहा था, और requestAnimationFrame के अंदर draw करने पर भी smooth नहीं था
  • शुरू में शक था कि main thread सभी favicon pixel states calculate करके broadcast channel में डालता है, और सैकड़ों tabs उसे पढ़ते हैं—इस structure में बहुत अधिक data copy हो रहा है
  • सिर्फ rectangle की position broadcast करके हर tab से खुद intersection calculate कराने में बदला गया, लेकिन performance improve नहीं हुई
  • असली समस्या यह थी कि हर tab हर frame में 4×4 black-and-white favicon image दोबारा बनाता था और toDataURL("image/png") से URL generate करता था
  • result canvas बदला न हो, फिर भी सैकड़ों tabs प्रति सेकंड कई बार छोटे white favicons लगातार regenerate कर रहे थे
  • favicon सचमुच बदलने पर ही update करने में बदलने से performance काफी बेहतर हो गई
  • हालांकि दूसरे tabs का काम सामने वाले tab के animation को इतना धीमा क्यों बना रहा था, यह स्पष्ट रूप से समझे बिना ही रह गया

Snake की जगह Pong चुनने की वजह

  • rectangle movement experiment के बाद छोटा “engine” साफ किया गया, और उसके ऊपर बनाने के लिए game चुना गया
  • पहला candidate Snake था, क्योंकि वह block-based है और favicon के साथ अच्छी तरह fit हो सकता था
  • लेकिन Snake बहुत ज्यादा block-based था, इसलिए माना गया कि front canvas की continuous movement का tab bar में discrete pixels में बदलने वाला effect उतना उभरकर नहीं आएगा
  • अंततः Pong चुना गया
    • ball और paddles को canvas और tab bar के बीच अक्सर आना-जाना पड़ता है
    • यह movement project के visual effect से अच्छी तरह मेल खाता है

Pong implementation notes

  • favicon drawing API तैयार होने के बाद Pong implementation खुद अपेक्षाकृत सरल था
  • right-side computer player हमेशा paddle के center को ball के center से मिलाने की कोशिश करता है
  • ball के paddle से bounce होने का angle paddle center के साथ relative position का उपयोग करने वाली simple trigonometry से calculate किया जाता है
  • यह तरीका realistic नहीं है, लेकिन ball के हमेशा उसी angle पर बने रहने की समस्या रोक देता है
  • collision detection के लिए दो rectangles intersect करते हैं या नहीं, यह check करने वाला function इस्तेमाल किया गया
  • ball और paddles के favicon में smoothly प्रवेश करने वाले effect को highlight करने के लिए ball में trail जोड़ा गया

Recurse Center में बनाया गया चौथा game

  • project Recurse Center batch के दौरान लिखा गया
  • Recurse Center को programming के लिए free writer’s retreat जैसी जगह के रूप में introduce किया गया है
  • यह project लगभग 40 दिनों में बनाया गया चौथा game है
  • इच्छुक readers को Recurse Center में apply करने पर विचार करने के लिए कहा गया है

1 टिप्पणियां

 
GN⁺ 2025-02-22
Hacker News की रायें
  • नमस्ते! यह मैंने बनाया है। सोच रहा था कि HN पाठकों को यह पसंद आएगा या नहीं :)
    अगर कोई सवाल हों तो जवाब दूंगा। कुछ बिखरे हुए विचार लिखूं तो, animated favicon इस्तेमाल करने पर यह कैसा दिखेगा, यह जानने की मुझे सच में उत्सुकता है। Firefox animated favicon को support करता है, इसलिए मसलन गेंद की future position predict करके animated SVG बनाया जाए तो शायद कहीं बेहतर frame rate मिल सके।
    एक दोस्त ने offline बताया कि canvas rasterization आम तौर पर GPU पर handle होता है, इसलिए अटकी-अटकी animation देखकर जो मेरी performance intuition बनी थी, वह शायद उतनी सही नहीं थी।
    Chrome favicon updates को प्रति सेकंड 4 बार तक सीमित करता है, इस पर मुझे कुछ हद तक ही भरोसा है। favicon refresh करने के कई तरीके हैं, इसलिए हो सकता है मैंने कुछ miss किया हो

    • बेतुका Pong बनाने वालों के बीच कहूं तो, वाकई शानदार काम है। इस तरह की technical performance art बनाना भी मजेदार है और देखना भी। शायद यह उस वजह से भी जुड़ता है कि मैं juggling क्यों करता हूं: “इसे और मुश्किल बनाने का कोई न कोई तरीका जरूर होगा”
    • क्या आपने वह हिस्सा हल कर लिया? सरल JavaScript game design material के लिए Jake Gordon का blog अच्छा है। वह front/back canvas वाला double-buffered game loop इस्तेमाल करते हैं।
      [0] https://jakesgordon.com/writing/javascript-pong/part1/
    • बहुत बढ़िया, और काम करने की आपकी speed सचमुच कमाल है!
      1 Million Checkboxes के बाद यह, global cap locks, bad apple regex, uuid वगैरह—इतना momentum प्रभावशाली है
    • अब browser tabs में चलने वाला Doom देखना चाहता हूं
  • मैंने Nolen की हाल की Recurse presentation देखी, और इस तरह के पूरी तरह पागलपन भरे लेकिन मूल रूप से मजेदार और शानदार one-off games सच में बहुत आनंद देते हैं।
    पुराने internet की याद आती है। वह दौर जब लोग बस silly और fun करने के लिए कुछ बना देते थे। कल रात उनकी पोस्टों से प्रेरित होकर, मैंने BEAM decompilation और कुछ tricks से एक बेहद मजेदार quasi-quine बनाया, जिसमें page अपना ही source code output करता है।
    काश मेरे पास भी ऐसी चीजें लगातार निकालने का समय होता, और सिर्फ यह बात कि लोग इस तरह लगातार दिलचस्प चीजें बना रहे हैं, मुझे हंसा देती है।
    जो लोग हंसना चाहें, उनके लिए वह sort-of quine हिस्सा यहां है: https://github.com/notactuallytreyanastasio/blog/blob/main/l...

  • Nolen जो भी बनाते हैं, अच्छा ही होता है। मेरे लिए वे single-purpose apps/sites के उस sweet spot को ठीक-ठीक छूते दिखते हैं, जो पुराने internet के बारे में nostalgia जगाता है

  • Matthew Rayfield का एक मिलता-जुलता experiment भी है, जिसमें tab favicon के बजाय address bar इस्तेमाल किया गया था: https://www.youtube.com/watch?v=q7GtCLwTmV4

    • Matt का काम मेरे लिए बहुत बड़ी inspiration है!
      इसे बनाते समय उनका URL वाला काम मेरे दिमाग में जरूर था, लेकिन सच कहूं तो blog पढ़े या video देखे काफी समय हो गया था। project के बीच में दोबारा देखते हुए यह याद आया कि वे भी “windows को stack करके 2D बनाना” वाली दिशा में गए थे—यह सचमुच मजेदार था
  • यह याद आता है:
    “Show HN: I saw this mind-blowing experiment, so I made a simple version of it” (25.11.2023) https://news.ycombinator.com/item?id=38413660
    “Synchronize a 3D scene across multiple windows using Three.js and localStorage” (27.11.2023) https://news.ycombinator.com/item?id=38437773

  • मैं दावे से कहता हूं कि अगला Doom है

    • Doom थोड़ा झंझट वाला है। मेरी जानकारी में प्रति सेकंड 4 frames की सीमा है, और tabs को update कर पाने की frequency ही ऐसी है।
      साथ ही हर frame में screen का ज्यादा हिस्सा बदलने की संभावना अधिक है, इसलिए favicon update करने के लिए कहीं ज्यादा “canvas को data URL में बदलना” पड़ेगा। मौजूदा implementation में यह महंगा है। हालांकि मुझे OffscreenCanvas के बारे में पता नहीं था, और शायद यह मदद कर सकता है
    • अगर आपका taste ऐसा है, तो मेरी जानकारी में Nolen पहले ही iPhoto में Doom चला चुके हैं
  • Firefox में tabs ज्यादा narrow हो जाने की समस्या हो तो, अब भी Firefox browser को खुद inspect करके minimum tab width की style rule ढूंढी जा सकती है और उसे userChrome.css में डाला जा सकता है।
    इससे जुड़े कुछ guides हैं, और tab width के लिए शायद किसी ने पहले से संकलन कर रखा होगा।
    हालांकि यह cheat भी माना जा सकता है। browser.tabs.tabMinWidth भी है, लेकिन मेरी याद में वह फिर भी minimum value enforce करता है

  • band Ok Go ने पहले Google Chrome के साथ मिलकर एक music video बनाया था, जिसमें browser windows और dancers बहुत शानदार तरीके से synchronize थे और kaleidoscope जैसे effects भी दिखे थे। इसे देखकर मुझे वही याद आया