Obsługa gamepada w przeglądarce

Ostatnio podpiąłem do mojego kompa pad przez USB. Do czego ta zabawka służy, niby każdy wie. Mimo to zamiast włączyć grę, zacząłem się zastanawiać, jak jeszcze można takie urządzenie wykorzystać. Rezultaty mnie zaskoczyły, dlatego chcę się nimi podzielić.

Szczegóły techniczne

// Jeśli nie piszesz aplikacji internetowych, pomiń ten fragment. Poniżej znajdziesz kilka ciekawszych rzeczy (obiecuję).

Specyfikacja W3C pozostaje szkicem, choć pierwsze wdrożenie prototypu API w publicznej przeglądarce da się określić na rok 2012. W telegraficznym skrócie, mamy do czynienia z dwoma detektorami zdarzeń i prostym interfejsem (obiektem) JavaScript.

Informacje o podłączonych urządzeniach pobrać można dzięki navigator.getGamepads(). Dostajemy obiekt w którym pod kolejnymi indeksami kryją się interfejsy padów.
Przykład odczytanych danych:

{
index: 0, // Identyfikator/slot
id: "EX10 GAMEPAD (Vendor: 0f0d Product: 0009)",
connected: true,
mapping: "",
axes: [
-0.7176470756530762,
0.5372549295425415,
0.003921627998352051,
// itd
],
buttons: [
{
pressed: false,
value: 0
},
{
pressed: true,
value: 1
},
// itd
],
timestamp: 51682
};

Wszystkie atrybuty są tylko do odczytu.

Póki co, monitorowane zdarzenia dostępne przez API to:
gamepadconnected i gamepaddisconnected.
window.addEventListener("gamepadconnected", function(event) {
console.log(event.gamepad);
});

Omawiam tu z grubsza tylko niezbędne minimum, dlatego do dalszej nauki polecam szczegółowy poradnik na developer.mozilla.org.

Kalibracja i mapowanie

Niestety nic nie jest tak proste, na jakie wygląda na pierwszy rzut oka. Oryginalne, nowe pady połączone przez Bluetooth nie powinny sprawiać problemu. Inne modele potrafią zaskoczyć różnymi konfiguracjami: od innej kolejności przycisków i osi, po d-pad zgłaszający się jako oś, zamiast zestawu przycisków. Twórcy specyfikacji też przewidzieli taką ewentualność. Dodanie ustawień sterowania w aplikacji jest co najmniej zalecane, nawet pomimo standaryzacji.

Precyzja gałek

Osie analogowe zwracają wartości od -1 do 1. Wartość dla położenia środkowego jest bliska, ale nie zawsze równa 0. Kontroler, którego aktualnie używam działa poprawnie przy progu ±0.01. Nie tylko z tego powodu w grach zwykle pojawia się opcja odcięcia (threshold / dead zone). Stick, który znajduje się na sprężynie, przy puszczeniu od krawędzi może odbić w drugą stronę.

Czas przetestować sprzęt

Mały proof-of-concept.

See the Pen Gamepad test by Tymoteusz Czech (@Tymek) on CodePen.

Do wizualizacji użyłem przekształcenia z kwadratu na koło:

Inne strony do sprawdzania pada

HTML5 Gamepad Tester – numeryczne wartości odczytywane z urządzania
Gamepad Viewer – wizualizacja urządzenia na ekranie (może wymagać dodatkowej konfiguracji)

Dodatkowy eksperyment

Na czas redagowania wpisu nie używam myszki, ani touchpada. Kursorem poruszam za pomocą gałek (stick’ów). Nie jest to może najprzyjemniejsze rozwiązanie, ale przy dobrej konfiguracji okazuje się co najmniej wykonalne.

Ustawienie tego w sensowny sposób zajęło chwilę. Przetestowałem kilka programów umożliwiających mapowanie kontrolera zanim trafiłem na antimicro.

Przemyślenia dotyczące interakcji

Interfejs użytkownika nie kończy się na tym, co zostaje wyświetlone na ekranie. Wikipedia bardzo trafnie definiuje UI, jako „przestrzeń, w której następuje interakcja człowieka z maszyną”. Do tej przestrzeni zaliczają się wszystkie interaktywne komponenty maszyny.

Wiele aplikacji internetowych mogło by wiele zyskać na wdrożeniu obsługi gamepada. Widać to było przy okazji sporej ilości eksperymentalnych stron korzystających z telefonu jako kontrolera. Choć klawiatura ma więcej przycisków, a myszka oferuje większą precyzję #pcmasterrace, trzymanie pada w rękach zawsze będzie o wiele wygodniejsze.

 

Materiał sponsorowany

przez wujka, który mi pada pożyczył.


Walidacja numeru telefonu

Weryfikacja danych wprowadzanych przez użytkownika bywa równie ważna, co trudna. Łatwo się o tym przekonać szukając odpowiedniego wzorca dla adresu e-mail. Niby każdy wie, jak to powinno wyglądać: login@domena.TLD, a jednak odpowiednie wyrażenie potrafi mieć kilka tysięcy znaków.

Niedawno potrzebowałem sprawdzić numery telefonów. Szybkie wyszukiwanie w Google nie dało żadnych dobrych odpowiedzi, więc chciałbym podzielić się tym, czego dowiedziałem się rozgrzebując temat.

Ludzie kontra standardy

Miałem sporo przemyśleń podczas rejestrowania karty stałego klienta w Decathlonie. Formularz był wyjątkowo nieintuicyjny. Oczywiście, niedopuszczenie do wprowadzenia złych danych jest niezwykle ważne przy programowaniu. Z drugiej strony, jedną z podstaw projektowania, jest zwrócenie uwagi na łatwość użycia. Wymaganie konkretnego formatu danych, zwłaszcza bez jasnego zakomunikowania ograniczeń, jest frustrujące dla użytkownika.

Wracając do numeru telefonu – każdy ma swój preferowany zapis:

123-456-789 vs. 12 345 67 89 vs. (+48) 123 456 789

Odstępy, prefiks, nawiasy, to dopiero początek problemów.

Co kraj, to obyczaj

Można napisać dość proste wyrażenie regularne obsługujące tylko polskie numery, ale co z resztą świata? Tu zaczynają się schody. Na szczęście ktoś zrobił to już za nas, więc nie przedłużając przejdę do rozwiązań.

Proponowane rozwiązania

Własne wyrażenie regularne

Tak. Wiem, że to dziwna sugestia. Wszystko zależy jednak od wymagań konkretnego projektu.
Wyrażenia regularne nie są tak trudne, jakby się wydawać mogło. Jeśli nie wiesz jak je ugryźć, polecam regexone.com. Poza tym, niczego się nie nauczysz kopiując przypadkowy kod z cudzego bloga. Sam trafiłem na naprawdę tragiczne wpisy na ten temat w internecie.

Jeśli nie chcesz słuchać dobrej rady, proszę bardzo. Luźna wersja dla polskiego numeru telefonu:

/^(?:\(?\+?48)?(?:[-\.\(\)\s]*(\d)){9}\)?$/


Trzeba później usunąć wszystkie spacje i dozwolone w tym zapisie znaki specjalne (()-. itd.)

libphonenumber

Pod adresem https://github.com/googlei18n/libphonenumber można znaleźć świetną bibliotekę do weryfikacji numeru telefonu. Oficjalnie całość dostępna jest w trzech językach programowania: C++, Java i JavaScript. Istnieją także porty na C#, objective-c, Pythona, Ruby i na całe szczęście: PHP.

Uwagi

W tym wpisie nie wspomniałem o numerach wewnętrznych, które znacznie komplikują zabawę. libphonenumber ich nie obsługuje.

Żadna weryfikacja nie zastąpi wysłania kodu SMS 😉


Intencjonalne projektowanie

Wiele osób formując założenia projektu dodaje „innowacyjność”. Niestety kiedy przychodzi do projektowania strony internetowej, często są to równie piękne, co puste słowa. Stan faktyczny to neutralność i naśladowanie. U góry belka z logotypem po lewej i nawigacją po prawej. Poniżej wklej slider zawierający przypadkowe zdjęcia. Później dodaj blok tekstu, ewentualnie tryptyk z kolumn. Stopka, copyright, autor. O nas, galeria, kontakt z formularzem. Wszystko jak wyplute z automatycznego generatora. Bezmyślne kopiowanie zasłania prawdziwy potencjał.

Weryfikacja nawyków

Wiele błędów bierze się z przyzwyczajeń, które choć kiedyś miały swoje miejsce, z czasem przestają być użyteczne. Ciągle pojawiają się nowe możliwości, które zmuszają nas do zastanowienia nad utrwalonymi schematami.

Grafika na skróty

Jednym z najpoważniejszych błędów jest użycie „stockowych” fotografii. Nie mam nic przeciwko kupowaniu gotowych zdjęć celem uatrakcyjnienia strony, ale mało jest rzeczy które tak skutecznie rujnują wiarygodność marki jak obrazki, które już gdzieś się widziało.

Płaskie myślenie

Strona internetowa, to nie obrazek. Składa się na nią nie tylko tekst i oprawa graficzna, ale także sposób funkcjonowania. Wszystko od struktury nawigacji, przez ruch (animacje lub ich brak), po użyty język ma znaczenie.

Autoodtwarzanie

Dźwięk jest atrakcyjnym dodatkiem i kiedy to uzasadnione, powinno się go używać częściej. Dźwięk ma też bardzo konkretny wpływ na działanie użytkownika: odtwarzany bez ostrzeżenia prawdopodobnie spowoduje, że w panice opuści on stronę. Pamiętaj, że nie masz kontroli nad poziomem głośności, a stopniowe zwiększanie poziomu dźwięku może być jeszcze bardziej frustrujące. Żeby lepiej zrozumieć jak może poczuć się gość twojego serwisu, polecam poszukać John Cena Prank.

Trwa ładowan…

Nie znam praktycznego przypadku, w którym poprzedzenie strony głównej indykatorem wczytywania byłoby uzasadnione. Nawet przy dużej ilości interaktywnej treści można wyświetlić ten element na części ekranu i pokazać inne informacje (np. przy wczytywaniu modelu 3D).  Jeśli strona używa dźwięku i trzeba przed tym ostrzec użytkownika, o wiele lepszą opcją jest krótka animacja wyświetlająca przycisk odtwarzania. Ktoś ma inne sugestie? Czekam na komentarze i polecam wcześniejszy wpis o optymalizacji wczytywania stron internetowych.

Bez przesady

Schematy nie są złe. Pomagają nam szybciej i wygodniej dotrzeć do informacji. Zasady łam świadomie, bo inaczej wszystko co nieszablonowe stanie się bezużyteczne. Zamiast eksperymentować i szukać przełomowych technologii, lepiej skupić się na zasadności użycia typowych elementów.

Celowość

Mam nadzieję, że wyczerpująco opisałem problem. To jednak nie wszystko.

„Jeśli nie jesteś częścią rozwiązania, jesteś częścią problemu.”

Co w takim razie zmienić? W jaki sposób projektować intencjonalne, czyli innymi słowy przemyślane, celowe, zasadne strony i aplikacje? Wystarczy zacząć od podpowiedzi na kilka pytań.

  • Kim jest potencjalny użytkownik? – np. Co wie (o produkcie/firmie)?
  • Jakich informacji lub wrażeń szuka? – np. Numer telefonu? Data wydarzenia? Nowa muzyka?
  • Dlaczego (w jakim celu)? – np. Porównanie z konkurencją? Umówienie spotkania?
  • Gdzie (w którym miejscu) i w jaki sposób? – np. Na jakie miejsce zwróci uwagę? Stopka? Formularz? Z jakiego urządzenia korzysta?

Gęstość informacji

Jeśli potraktujemy przeczytanie, lub poświęcenie uwagi danemu elementowi jako wybór, warto zastanowić się ile danych strona internetowa lub aplikacja przekazuje użytkownikowi w konkretnym momencie. Kluczem jest efektywne wykorzystanie przestrzeni. W przypadku wersji mobilnej najważniejsza będzie nawigacja, za to przy dużej rozdzielczości monitorach nie należy zostawiać za dużo pustej przestrzeni, ale o tym innym razem.

Obowiązkowa lektura

Opracowując dzisiejszy tekst przygotowałem listę pojęć, na których temat warto uzupełnić swoją wiedzę. Część z nich już pewno znasz. Gwarantuję, że nawet podstawowe poznanie wypisanych terminów może radykalnie zmienić podejście do pracy.

  • Projektowanie kierowane wzrostem (Growth Driven Design)
  • Metodologia S.M.A.R.T.
  • Prawo Hicka (Hick’s law)
  • Zarządzanie wymaganiami
  • Metoda MoSCoW
  • Zasada Pareta

Optymalizacja wczytywania strony

Poza zawartością i wyglądem witryny lub aplikacji powinniśmy dbać także o wygodę korzystania z niej. Pierwszymi rzeczami z którymi (świadomie, lub «oby» nie) styka się użytkownik jest pobieranie, renderowanie i wyświetlanie naszej treści przez przeglądarkę. Mamy wtedy świetną okazję, żeby już w pierwszych sekundach zdenerwować naszego klienta.

Co za dużo, to niezdrowo

… doskonałość osiąga się nie wtedy, kiedy nie można nic już dodać, ale kiedy nie można nic już zabrać.   Antoine de Saint-Exupéry, Ziemia, planeta ludzi

Można by jeszcze dodać, że „Najważniejsze jest…” (neee. Nie lubię tego cytatu. I tej książki.). Skupmy się na konkretach: ilości i rozmiar plików. Zaczynając od podstaw: ważne by na serwerze włączona była kompresja gzip. Mając to z głowy, zastanówmy się ile zbędnych bajerów, głównie skryptów, wpakowaliśmy. Okazuje się, że „możesz nie potrzebować jQuery”. Przypomnę jeszcze, że instalowanie losowych wtyczek do systemu zarządzania treścią to prosta droga do katastrofy.

Grafika

Obrazki mają zwykle znacznie większy rozmiar od tekstów, arkuszy stylów i skryptów. Wczytywanie ich w odpowiedni sposób jest bardzo ważne dla optymalizacji ładowania strony. Pierwszym i podstawowym krokiem jest kompresja. Ze stratną kompresją JPEG lepiej nie przesadzać, ale póki artefakty nie zaczynają być widoczne, zwiększenie o kilka procent nie zaszkodzi. Warto pamiętać, że grafiki PNG można bezstratnie skompresować nawet o kilkadziesiąt procent. Polecam w tym celu stronę tinypng.com. Dodatkowym bardzo przydatnym trikiem jest przygotowanie miejsca o wielkości grafiki i wypełnienie go uśrednionym kolorem. Tak robi na przykład Pinterest.

Wektory na ratunek

Wszystkie nowoczesne przeglądarki (i Internet Exploder Explorer od wersji 9) wspierają format SVG. Trzeba trochę z tym uważać, bo nie wszystkie w równym stopniu. Tak czy inaczej stworzone w ten sposób grafiki ważą znacznie mniej. Dodatkowo istnieje możliwość osadzenia ich bezpośrednio w kodzie, dzięki czemu zmniejszamy ilość odwołań do serwera. Wadą tego rozwiązania jest wczytywanie tej samej treści przy każdym odświeżeniu strony. Rozwiązać to można na przykład za pomocą opóźnionego ładowania i Kukiz Cookies. Przy pierwszym ładowaniu serwujemy wersję osadzoną w kodzie, wczytujemy plik w tle po załadowaniu innych elementów strony i ustawiamy ciasteczko, dzięki któremu przy kolejnym wczytaniu odniesiemy się do załadowanego pliku zamiast ponownie umieszczać grafikę w kodzie.

It’s all about that bass base

Jest jeszcze jeden sposób na osadzania grafik dowolnego typu w kodzie HTML lub CSS. Data URI z kodowaniem Base64. Znacznie ułatwiają to prekompilatory (SASS, LESS). Z powodu opisanego powyżej proponuję stosowanie tego typu rozwiązania raczej w kodzie CSS. Metoda nie jest bez wad. Po więcej szczegółów odsyłam od Chrisa Coyiera na css-tricks.com/data-uris/.

Ładowanie sekwencyjne (progresywne)

Przez ustawienie elementów w odpowiedniej kolejności w kodzie i użycie zdarzeń document.ready i window.load możemy nadać priorytet części zawartości. Osobiście używam takiej listy priorytetów:

  1. HTML – treść, a przynajmniej widoczna jej część, powinna być pobierana w pierwszym zapytaniu.
  2. Podstawowy CSS – wielkość fontu i szerokość kolumn, tło większych elementów.
  3. Font – tak wysoko na mojej liście z dwóch powodów:
    1. Przeglądarki w większości dają nam aktualnie 3 sekundy na dostarczenie przed wyświetleniem zamiennika.
    2. O ile nie używamy przesadnej ilości krojów, mamy do czynienia z sensownie niewielkimi plikami.
  4. Ważne skrypty, np. otwieranie menu.
  5. Reszta stylu – główny plik CSS zawierający zwykle framework.
  6. Grafika

Jest kilka cyfr, o których warto pamiętać:

  • 300ms na pojawienie się pierwszych elementów strony.
  • 3s na (w miarę) kompletne załadowanie.
  • 10s jako granica po przekroczeniu której użytkownik traci zainteresowanie, a czasem cierpliwość.

Przy czym nie każdy ma turbo internet. Pod tym względem warto brać przykład z Facebooka (Wtorki z 2G). DevTool w Chrome ma opcję ograniczania transferu (network throttling). Oto co goście z Google mają do powiedzenia w temacie:

Miałem zamiar dodać jeszcze coś o optymalizacji pod urządzenia mobilne, ale to już temat na kolejny wpis.

Studium przypadku

Przy połączeniu 3G przed optymalizacją (po lewej) mija ponad 2 sekundy do pojawienia się czegokolwiek. Efekty w tym przypadku są mało widoczne, bo i projekt jest niewielki.