Неделя 5 · JS30 Widgets
🧭 ← 02c — Shelter Part 3 — JavaScript · ← Roadmap · Следующая → Podcast
🎯 Что строим
Два виджета из шести предложенных — homage курсу JavaScript30 Wes Bos. Каждый виджет — standalone статика на чистом vanilla JS + Web APIs. Три стадии на виджет: воспроизведение оригинала → обязательная доп. фича → опциональные улучшения.
Особенности этой задачи:
- Общий курсовой репо (не свой!) — куратор даёт collaborator-доступ, каждый студент в своей подпапке
students/<github-login>/<task-slug>/ - Netlify Preview Bot автоматически деплоит превью на PR — именно эту ссылку сабмитишь в rs app
- Self-evaluation в console — на загрузке страница печатает в
console.logсписок зачтённых пунктов с баллами
🏷 Required Skills (как заявлено в задании)
HTML5 · CSS3 · vanilla JS (ES2020+) · DOM API · event handling · CSS animations · Web Audio API · Canvas API · HTMLVideoElement / HTMLAudioElement · Git branching · PR workflow · code review · Netlify Preview
🚫 Запреты и штрафы
| ❌ | Что нельзя | Штраф |
|---|---|---|
| 🔴 | jQuery, React, Vue, Angular, Lodash и любые JS-фреймворки/библиотеки | -65 (виджет обнуляется целиком) |
| 🔴 | Прямой copy-paste кода оригинала Wes Bos / других студентов | вплоть до -65 |
| 🟡 | Minified / obfuscated JS в коммите | -10 за виджет |
| 🟡 | Один коммит-дамп вместо реальной истории разработки | -10 за виджет |
| 🟡 | PR не открыт против main курсового репо / нет Netlify preview |
-10 за виджет |
| 🟡 | Нет self-evaluation в browser console | -5 за виджет |
| 🟡 | Major bug — функционал ломается после манипуляций или throws в консоль | -15 за баг |
| 🟡 | Minor bug — визуал/state косячит без ошибок в консоли | -5 за баг |
💡 Разрешено: Bootstrap и любые CSS-фреймворки, Sass/Less/PostCSS препроцессоры. Перепечатывать код с видео своими руками тоже норм — суть в том, что ты понял каждую строку.
⛰ Compound из предыдущих задач
К этой неделе у тебя уже есть из Shelter P3:
- DOM-манипуляции —
querySelector,classList,dataset(Photofilter, Drum Kit) - События —
addEventListener, делегирование,event.target(все виджеты) - Анимации CSS —
transition,transform,@keyframes(Clock, Drum Kit, Mole) - Модульная архитектура — раздели UI / state / data layer
Из Slider:
transform: translateи плавныеtransition— Vertical Slider, стрелки Clock
🎯 Рекомендация по выбору: для первого захода в JS30 бери Drum Kit + JS Clock — обе короткие (10-20 мин видео), без Canvas и сложного state. Если уверен в DOM/событиях после Shelter — Photofilter + Custom Video Player (там работа с CSS variables и Media API). Whack-A-Mole — самый трудоёмкий из-за Canvas/таймингов, бери только если хочется challenge.
📚 Что изучить (по порядку)
⚠️ Идти строго по порядку. Виджеты разные, но фундамент (DOM/события/Web API base) общий.
📥 Что должен знать ДО старта
Это пятая задача bootcamp. К этому моменту у тебя должны быть:
- Все скиллы из Slider (CSS layout, transitions, transform)
- Все скиллы из Shelter P3 (vanilla JS, DOM, events, modules)
- Понимание ES Modules и Блочная область видимости -- let и const
1 · Compound из Shelter P3: DOM + события (фундамент)
Зачем: все 6 виджетов на 80% состоят из «слушай событие → меняй DOM/CSS». Без уверенного DOM ты завязнешь даже в Drum Kit.
- querySelectorAll и NodeList
- classList -- add, remove, toggle, contains
- data-атрибуты (dataset)
- События
- Делегирование событий
- preventDefault и stopPropagation
- preventDefault и stopPropagation
- События загрузки -- DOMContentLoaded, load
Self-check: в чём разница event.target и event.currentTarget при делегировании? Когда вешать слушатель — на DOMContentLoaded или сразу в <script defer>?
2 · CSS Variables (нужно для Photofilter, опционально для всех)
Зачем: Photofilter полностью построен на чтении <input type="range"> → запись в CSS custom property → filter: применяется автоматически. Это паттерн «JS пишет переменную — CSS реагирует».
- CSS переменные
- transform -- rotate, scale, translate
- transition -- плавные переходы
- Псевдоклассы —
:hover,:active,:focus-visible - filter —
blur,saturate,hue-rotate,brightness - Keyframes — для постоянных анимаций (Clock «тиканье», Mole «выскочил-скрылся»)
Self-check: как из JS прочитать значение CSS custom property --base? Чем element.style.setProperty('--x', val) отличается от element.style.x = val?
3 · Web APIs — обзор и навигация
Зачем: «Web API» — это всё, что браузер даёт сверх ECMAScript. На JS30 ты пощупаешь сразу несколько разных API. Понимать общую карту полезно, чтобы не путать HTMLAudioElement (DOM-обёртка тега) с Web Audio API (графовый процессор звука) — это разные штуки.
- _MOC Браузерные API
- _MOC DOM
- HTMLAudioElement — базовый класс для
<audio>и<video> - Fetch API — может понадобиться для Drum Kit (если грузишь звуки динамически)
- JS объекты основы — Clock
- requestAnimationFrame — плавные анимации (Mole, Clock-секундомер)
- Web Storage -- localStorage и sessionStorage — для сохранения high-score (Mole, опциональное улучшение)
Self-check: что лучше для анимации стрелки часов — setInterval(1000) или requestAnimationFrame? Почему?
4 · HTMLAudioElement + Web Audio API (Drum Kit)
Зачем: Drum Kit играет звук на клавишу. На «по-быстрому» хватает <audio>.play(), но обязательная доп. фича (см. js30-1.md) обычно требует контроля над звуком — а это уже Web Audio API.
- HTMLAudioElement —
.play(),.pause(),.currentTime,.volume - Web Audio API —
AudioContext,AudioBufferSourceNode,GainNode - HTMLAudioElement —
.mp3vs.ogg, fallback через<source> - HTMLAudioElement
- События клавиатуры -- keydown, keyup — ловим клавишу, маппим на data-атрибут
- События клавиатуры -- keydown, keyup
Self-check: почему повторное нажатие на ту же клавишу не воспроизводит звук с начала? (подсказка: audio.currentTime = 0). Чем event.key отличается от event.code для клавиш KeyA?
5 · HTMLVideoElement (Custom Video Player)
Зачем: Custom Video Player полностью заменяет встроенные controls. Тебе нужен ручной play/pause, scrubber (seek-бар), volume slider, playback rate, fullscreen.
- HTMLVideoElement —
.play(),.pause(),.currentTime,.duration,.playbackRate,.volume,.muted - HTMLAudioElement —
timeupdateдля прогресс-бара - HTMLVideoElement —
element.requestFullscreen - input типы — двусторонняя привязка
input↔currentTime - HTMLVideoElement — опциональное улучшение
- HTMLAudioElement —
Math.floor(s/60),padStart
Self-check: какое событие даёт надёжный момент «видео реально стартовало» — play или playing? Как из currentTime (число секунд) получить строку "02:35"?
6 · Date API + CSS transitions (JS Clock)
Зачем: Clock — самый минималистичный виджет: setInterval + Date + transform: rotate. Главная ловушка — «прыжок» стрелки при переходе с 59→0 секунд (CSS пытается анимировать обратно по часовой) — придётся гасить transition на этот тик.
- JS объекты основы —
new Date,getHours,getMinutes,getSeconds - setTimeout и setInterval
- transform -- rotate, scale, translate —
rotate(${deg}deg) - transform -- rotate, scale, translate — стрелка крутится вокруг центра циферблата
- transition -- плавные переходы —
transition-timing-function: cubic-bezier - Keyframes — опционально, для «тиканья» (jerk-эффект)
- Virtual DOM — на эту задачу: прямые
Self-check: что произойдёт со стрелкой секунд при переходе 59s→0s, если оставить transition: 0.5s all? Как это починить?
7 · Canvas API (Whack-A-Mole, опционально)
Зачем: Whack-A-Mole можно сделать и на чистом DOM (как в оригинале Wes Bos), но если хочешь wow-эффект для Stage 3 — добавь Canvas-фон с эффектом удара (взрыв частиц, ряби).
- Canvas API основы —
<canvas>,getContext('2d') - Canvas API основы —
fillRect,arc,beginPath - Canvas API основы —
clearRect+requestAnimationFrame - Canvas API основы
- JS массивы основы — нора с молью выскакивает в случайной позиции
- Canvas API основы —
willReadFrequently, off-screen canvas
Self-check: зачем перед каждым кадром clearRect(0, 0, width, height)? Что произойдёт, если этого не делать?
8 · События клавиатуры (Drum Kit)
Зачем: Drum Kit маппит клавиатуру на «барабаны». Главный момент — слушать keydown (не keypress!) на window, а не на конкретном элементе, и сопоставлять event.key / event.code с data-key на DOM-элементах.
- События клавиатуры -- keydown, keyup
- События клавиатуры -- keydown, keyup —
code: "KeyA"стабильно,key: "a"зависит от раскладки - Делегирование событий — на
window, а не на каждом.key - transition -- плавные переходы — убираем CSS-класс анимации после её окончания
- События клавиатуры -- keydown, keyup — отсекать, если не хочешь спам при удержании
Self-check: почему keypress устарел? Как поймать момент, когда CSS-анимация удара по барабану закончилась, чтобы убрать класс .playing?
9 · Workflow в shared-репо + Netlify Preview Bot
Зачем: на этой задаче впервые не свой репо, а общий курсовой. Один неаккуратный коммит — и ты задеваешь чужие папки. Нужно дисциплинированно держаться своей ветки и своей подпапки students/<login>/<task-slug>/.
- Repo Workflow для bootcamp — общая схема
- Repo Workflow для bootcamp — что меняется в общем репо
- Ветвление — ветка на каждый виджет:
<login>/drum-kit,<login>/js-clock - Git Commit Convention
- PR Description Schema
- Netlify Drop — как читать комментарий бота, где найти preview URL
- Cross-Check процесс
Self-check: что писать в PR description, чтобы reviewer быстро нашёл список Stage 1 / 2 / 3 пунктов? Где брать deploy-link для сабмита в rs app — из gh-pages или из коммента Netlify-бота?
10 · Self-evaluation шаблон (обязательно!)
Зачем: без console.log self-evaluation на загрузке страницы — -5 за виджет. Reviewer открывает DevTools → Console и сверяет твой claim с тем, что реально работает в превью.
Шаблон, который вставь в script.js (или в отдельный self-eval.js):
console.log('%c=== Self-evaluation: Drum Kit ===', 'font-weight:bold;font-size:14px');
console.table([
{ stage: 1, item: 'Visual match with original', claimed: 10 },
{ stage: 1, item: 'Core behaviour (keys play sounds)', claimed: 10 },
{ stage: 2, item: 'Mandatory feature: <название>', claimed: 15 },
{ stage: 3, item: 'Optional: visual hit feedback', claimed: 10 },
{ stage: 3, item: 'Optional: tempo control', claimed: 10 },
{ stage: 3, item: 'Optional: localStorage preset', claimed: 10 },
]);
console.log('Claimed total: 65/65');
Self-check: твой console.log выводится на загрузке (не по клику)? Список пунктов совпадает с PR description?
✅ Чек-лист критериев (130 баллов = 65 × 2 виджета)
Виджет 1 (65) и Виджет 2 (65) — одинаковый разбор
Stage 1 · Reproduction · 20
- Visual match с оригиналом (layout, цвета, ключевые интеракции) (
+10) - Core behaviour работает end-to-end, без ошибок в консоли (
+10)
Stage 2 · Mandatory feature · 15
- Обязательная доп. фича (см.
js30-N.md) реализована и работает (+10) - Фича интегрирована: не ломает Stage 1, обрабатывает edge cases (
+5)
Stage 3 · Optional improvements · до 30 (cap 30)
- Улучшение №1 —
+10 - Улучшение №2 —
+10 - Улучшение №3 —
+10
Engineering & delivery (штрафы внутри 65)
- JS читаемый, не minified (
-10) - Нет jQuery / React / Vue / Angular (
-65voids widget) - Self-evaluation в console на загрузке (
-5if missing) - Commit history отражает реальную разработку (
-10) - PR открыт в
mainкурсового репо + Netlify preview работает (-10)
Submission
- Ветка
<github-login>/<task-slug>(lowercase + dashes) - Папка
students/<github-login>/<task-slug>/со всеми файлами виджета - PR открыт, не смержен
- Deploy-link (Netlify preview из коммента бота) засабмичен в rs app
🧠 Self-check перед коммитом
Не нажимай git push, пока не сможешь ответить:
- Почему я выбрал именно эти 2 виджета? (не «самые лёгкие», а есть причина)
- Я могу объяснить каждую строку в своём
script.js? Или где-то скопировал с видео не понимая? - Mandatory feature реально работает на превью или только «вроде бы»?
console.logself-eval запускается на DOMContentLoaded и показывает ровно те пункты, что я заявил в PR description?- Моя ветка не трогает чужие папки
students/<другой-login>/? - Коммиты — это реальная история (
feat: add keydown handler,fix: prevent autorepeat), а не один дамп? - PR description заполнен по схеме + список Stage 1/2/3 пунктов?
- Я открыл Netlify preview URL в инкогнито — всё работает без моих закешированных файлов?
➡️ Что переходит в следующие задачи (compound forward)
После JS30 в Podcast переиспользуешь:
- Блоки 1, 4, 5 — DOM/события + HTMLAudioElement = базис для player'а подкастов
- Блок 9 — workflow на отдельном репо (но уже не shared)
В Hangman:
- Блок 8 — обработка клавиатуры (буквы a-z)
- Блок 1 — DOM-стейт игры
В Async Race:
- Блок 3 —
requestAnimationFrameдля гонки машинок - Блок 6 —
transform: translate+ CSS transition (паттерн из Slider тоже здесь)
В Shooter (если будет):
- Блок 7 — Canvas API как фундамент игрового рендера
📚 Внешние ресурсы
- 📄 Полное задание
- JavaScript30 playlist by Wes Bos
- 50 Projects in 50 Days — GitHub
- MDN — DOM Introduction
- MDN — Using Web Audio API
- MDN — Canvas tutorial
- MDN — HTMLMediaElement
- MDN — HTMLVideoElement
- MDN — HTMLAudioElement
- MDN — Fullscreen API
- MDN — KeyboardEvent.code
- MDN — Using CSS custom properties
- MDN — CSS transitions
- MDN — CSS animations
- Git commit convention — RS
- PR requirements — RS
- Cross-check flow — RS
- Netlify Deploy Previews — docs