Тема 8, урок 2 з 2 · останній урок модуля · 120 хвилин
Минулого уроку ти зібрав сцену з трьох фігур. Вона гарна, але мертва: ніщо в ній не рухається й не відповідає на твої дії.
Сьогодні фігур стане п'ять. Одна крутитиметься сама. Друга рахуватиме твої кліки написом просто в сцені.
Друга робота дня — портфоліо. Це одна сторінка, з якої відкриваються всі вісім робіт модуля.
Сцену ти покажеш на захисті сьогодні. А портфоліо лишиться після курсу: це адреса, яку можна дати будь-кому.
| Етап | Хв | Що робимо |
|---|---|---|
| Перевірка ДЗ | 10 | GDD: як гравець виграє |
| П'ять об'єктів і анімація | 20 | Атрибут animation, три види руху |
| Інтерактив і лічильник | 30 | Курсор, клік, <a-text> |
| Перерва | 10 | — |
| Портфоліо модуля | 15 | ~/www/index.html і вісім посилань |
check 08 | 10 | Фінальний прогін до зеленого |
| Захист прототипів | 20 | 2 хвилини на людину + питання по коду |
| Підсумок модуля | 5 | Вісім тем однією картою |
| Разом | 120 |
lesson-08.
Бо це восьма тема модуля.
Теки lesson-16 немає й не буде.Перший рядок сцени вирішує, чи вона взагалі відкриється
Ти пишеш <a-box> — і в браузері з'являється куб.
Робить це A-Frame, бібліотека для опису 3D-сцени звичайними HTML-тегами.
Далі вона все бере на себе. Будує сцену. Керує камерою. Малює кадри. Вмикає VR-режим на телефоні.
Підключається вона одним рядком у <head>.
У цьому рядку стоїть адреса файлу.
Якщо адреса веде на чужий сервер, check 08 це побачить
і критерій не зарахує.
Бібліотеку можна не класти в себе, а тягнути з чужого сервера. Такі роздавальні сервери звуться CDN.
Вони швидкі й безкоштовні. Тому в інтернеті майже всі приклади A-Frame написані саме так. Але в нас так не можна, і причин три.
| Причина | Що це означає на практиці |
|---|---|
| Сайт має працювати завжди | CDN може бути недоступний: збій, блокування, шкільний фільтр, урок без інтернету. Твоя сцена тоді — біла сторінка. Локальний файл лежить на тому самому сервері, що й сторінка: якщо відкрилася сторінка — відкриється й бібліотека |
| Версія не змінюється сама | Файл у твоїй теці — той самий і за пів року. Посилання на CDN у форматі
@latest одного дня приведе іншу версію, і сцена зламається без
жодної правки з твого боку |
| Чужий сервер бачить твоїх гостей | Кожен, хто відкриє сторінку, непомітно постукає ще й на CDN. Той запише його IP-адресу й адресу твоєї сторінки. Тому в цьому курсі локально лежать навіть шрифти |
Саме через ці три причини правило записали в критерій.
check 08 шукає в HTML посилання на зовнішні домени.
Знайшов — критерій не пройдено, хоча вдома все працювало.
aframe.min.js учитель розклав у кабінети ще до уроку 15.
По FTP ти його не завантажуєш.
Він важить близько 1,8 МБ — майже впритул до ліміту приймальні у 2 МБ.
Заливати 25 однакових копій немає сенсу.
Твоя справа — правильний відносний шлях до нього.~/www/lesson-08/index.html.
Бібліотека — у ~/www/lesson-08/assets/aframe.min.js.
Тому в src пиши assets/aframe.min.js,
без слеша на початку.
Слеш на початку відлічує від кореня сайту, а там цього файлу немає.Удома сцена крутиться, у школі — біла сторінка, у консолі порожньо, крім
червоного рядка про aframe.min.js. У <head>
стоїть src="https://aframe.io/releases/1.7.0/aframe.min.js".
Що сталося?
Напис у сцені малює тег <a-text>. Системний шрифт він
не бере — йому потрібен окремий файл із намальованими літерами.
За замовчуванням A-Frame тягне цей файл з cdn.aframe.io.
Тобто із чужого домену — навіть коли сама бібліотека лежить локально.
Тому шрифт теж має бути у твоїй теці:
Поруч із aframe.min.js учитель кладе два файли шрифту:
Roboto-msdf.json і Roboto-msdf.png.
В атрибуті ти вказуєш перший. Другий підтягнеться сам — його ім'я записане всередині JSON.
Якщо цих файлів у теці немає — скажи вчителеві. Ставити посилання на CDN не треба.
Сцена малюється, куби на місці, але напису з лічильником не видно взагалі,
а в консолі — червоний рядок про Roboto-msdf.json.
Де шукати причину?
Мінімальна сцена — це вісім рядків, і кожен з них щось означає
| Рядок | Що він робить |
|---|---|
<a-scene> |
корінь сцени. Створює полотно на весь екран, запускає рендер, додає кнопку «VR» у кутку й два світла за замовчуванням |
<a-sky> |
небо — величезна сфера навколо всього. Без неї фон чорний |
<a-plane> |
плоский прямокутник 1×1 м. Стоїть вертикально, як стіна; підлогою стає після повороту на −90° по X |
<a-box> |
куб 1×1×1 м |
<a-sphere radius> |
куля. Радіус за замовчуванням — 1 м, тобто 2 метри завширшки: найчастіша причина «щось величезне закрило екран» |
<a-camera> |
очі глядача. Якщо не написати — A-Frame додасть свою |
<a-cursor> |
курсор усередині камери. Пускає невидимий промінь уперед; без нього клікати нема чим |
Атрибут position="x y z" — це три числа через пробіл.
Без ком. Одиниця виміру — метр.
Нуль — центр сцени на рівні підлоги.
position="0 0 0" і не бачить нічого.
Об'єкт там є. Просто він у тебе під ногами й позаду камери.
Другий варіант тієї самої помилки — position="0 1.6 0".
Тоді камера опиняється всередині об'єкта.
Зсередини грані не малюються, тож екран чорний.Ти хочеш поставити кулю так, щоб вона висіла на рівні твоїх очей за три метри
попереду. Яке значення position?
| Атрибут | Формат | Що робить |
|---|---|---|
rotation | "x y z", градуси |
повертає об'єкт навколо трьох осей. "-90 0 0" кладе вертикальну
площину горизонтально — так робиться підлога |
scale | "x y z", множник |
"2 2 2" — удвічі більший, "0.5 0.5 0.5" — удвічі
менший. Одиниця — без змін |
color | "#E76F51" або "tomato" |
колір матеріала. Той самий шістнадцятковий запис, що й у CSS |
id, class | як у звичайному HTML | щоб знайти об'єкт із JS: querySelector('#score'),
querySelectorAll('.clickable') |
<a-plane> малює одну сторону.
Обійдеш площину — побачиш порожнечу.
Для стіни, повз яку ходять, додай material="side: double".Ти зробив підлогу <a-plane scale="8 8 8">, але вона стоїть
перед тобою стіною. Який атрибут забули?
Рух у A-Frame пишеться в розмітці, а не в JavaScript
Рух у A-Frame вмикають атрибутом animation.
Він уже вбудований у бібліотеку, докачувати нічого не треба.
Ти кажеш йому три речі. Що змінювати. До якого значення. За скільки часу. Усі проміжні стани він щокадру рахує сам.
| Властивість | Значення | Що означає |
|---|---|---|
property | rotation, position,
scale, material.color |
що саме змінюємо |
to | кінцеве значення | задається абсолютно, а не «на скільки». Для position
це нова точка у метрах, а не зсув |
dur | мілісекунди | тривалість одного проходу. 6000 — шість секунд на оберт |
loop | true або число |
true — нескінченно, 3 — три рази |
dir | alternate |
рух туди-назад. Без нього об'єкт стрибне на початок ривком |
easing | linear,
easeInOutSine… |
характер руху. Для нескінченного обертання беруть linear,
інакше видно ривок на стику кіл |
animation="…" властивості розділяються
крапкою з комою. А координати всередині значення — пробілом.
Кома не працює ніде. Помилки в консолі при цьому може й не бути —
просто нічого не рухається.Куля має плавно підніматися й опускатися, і так нескінченно. Ти написав
property: position; to: 0 2.1 -5; loop: true; dur: 2000 —
куля повзе вгору й кожні дві секунди ривком падає вниз. Чого бракує?
Помилка номер один усієї теми — і вона в одному рядку
У 3D-сцені немає «кліку по картинці». Працює це як ліхтарик, прикріплений до голови.
З камери вперед виходить невидимий промінь. У що промінь упреться,
те й отримає подію click, коли ти натиснеш.
Промінь створює курсор. Немає курсора — немає променя. Немає променя — жоден обробник не спрацює.
Запис raycaster="objects: .clickable" каже променю перевіряти
лише позначені об'єкти.
Без цього рядка теж працює. Але тоді браузер щокадру перевіряє все підряд. На телефоні це помітно з'їдає кадри.
<a-text>Напис у сцені — окремий об'єкт зі своєю позицією. Змінити його текст із JavaScript можна лише трьома аргументами: назва компонента, назва властивості, нове значення.
score.setAttribute('value', n) нічого не зробить.
Тут value — не компонент, а властивість усередині
компонента text.
Правильно так: score.setAttribute('text', 'value', n).
Помилки в консолі не буде.
Лічильник у пам'яті рахує, а напис у сцені мовчить.event-set__click
У прикладах в інтернеті клік часто вішають атрибутом
event-set__click. Це стороннє доповнення.
Усередині aframe.min.js його немає — потрібен ще один файл,
а качати його з CDN нам не можна.
Тому в нас клік обробляє звичайний addEventListener.
Так навіть чесніше: видно, що саме відбувається.Ти додав у обробник console.log(n) — числа в консолі ростуть
після кожного кліку. Але напис у сцені так і показує «Очки: 0».
Де помилка?
Крути параметри — код праворуч оновлюється сам. Копіюєш і вставляєш
у свій index.html
Самої бібліотеки тут немає: сторінка уроку теж нічого не тягне з CDN. Тому замість тривимірного перегляду — дві схеми.
Вигляд згори показує, де об'єкти стоять на підлозі. Вигляд збоку — на якій вони висоті. А головний результат — готова розмітка внизу.
А ось те, що з цього виходить. Кнопка «копіювати» бере весь файл цілком:
від <!doctype> до останнього тега.
У редакторі ти поставив п'ять об'єктів, але всі — a-box трьох різних
кольорів, з анімацією й кліком. Чекер усе одно червоний. Яку вимогу порушено?
Консоль браузера — F12, вкладка Console. Спочатку читаємо, потім правимо
| Що бачиш | Що в консолі | Що робити |
|---|---|---|
| Біла порожня сторінка, жодного полотна | GET .../lesson-08/assets/aframe.min.js 404 (Not Found) |
Неправильний шлях до бібліотеки. Перевір: файл справді в
lesson-08/assets/, у src немає слеша на початку,
ім'я теки саме assets, а не Assets —
Linux розрізняє регістр |
| Чорний екран, але кнопка «VR» у кутку є | порожньо | Немає <a-sky> — фон за замовчуванням чорний. Другий варіант:
ти додав власний <a-light>, і A-Frame прибрав два свої
стандартні світла; одного слабкого замало |
| Чорний екран, і він не змінюється, коли крутиш камеру | порожньо | Камера всередині об'єкта. Зсередини грані не малюються. Прибери з точки
0 1.6 0 все, що там стоїть |
| Сцена є, але порожня | порожньо | Об'єкти позаду камери: z додатний або нуль. Став від'ємний:
-3, -4, -5 |
| Клік нічого не робить | порожньо | Немає <a-cursor> всередині <a-camera>.
Або в raycaster="objects: .clickable" вказано клас,
якого немає на об'єктах |
| Лічильник не змінюється | порожньо | setAttribute('value', n) замість
setAttribute('text', 'value', n) |
| Напису немає взагалі | GET .../assets/Roboto-msdf.json 404 |
Шрифт не лежить поруч із бібліотекою. Попроси вчителя розкласти
Roboto-msdf.json і Roboto-msdf.png |
| Локально працює, на сервері біло | 404 на будь-який файл | Різниця в регістрі імен після заливання по FTP або файл потрапив не в ту теку. Відкрий адресу файлу напряму в браузері — 200 чи 404 видно одразу |
| Чекер каже «зовнішній домен» | — | У HTML лишилося посилання на CDN — на бібліотеку, на шрифт або на
event-set. Шукай у файлі рядок https:// |
https://логін.домен/lesson-08/ —
глянув консоль. І так щоразу, а не раз наприкінці уроку.Сторінка відкривається, кнопка «VR» у кутку є, камера крутиться — але екран чорний і не змінюється, хоч куди повернись. У консолі жодної помилки. Що це майже напевно?
Вісім тем зводяться в один файл: ~/www/index.html
Усі вісім тем ти складав по одній теці. Сьогодні вони з'єднуються.
Головна сторінка твого сабдомена — це зміст усього модуля. З неї має відкриватися кожна робота. І кожне посилання має віддавати 200.
Саме лише посилання нічого не каже. Тому пиши по три частини: що це, що саме зроблено, чого навчився. Два-три рядки, без води.
| Погано | Добре |
|---|---|
| Тема 3. Звук. | Тема 3. Одне джерело — чотири формати. Порахував розмір WAV за формулою й звірив із реальним файлом; різниця 0,4%. Зрозумів, за що платимо бітрейтом. |
| Тема 6. Скрипт. | Тема 6. Пакетна конвертація 10 файлів. Скрипт визначає справжній тип за першими байтами, а не за розширенням — три файли в наборі були підписані неправильно. |
href="lesson-04/" веде на теку.
Сервер сам віддасть із неї index.html.
Запис href="lesson-04" без слеша спрацює не завжди.
А href="/lesson-04/" зі слешем спереду — це вже корінь сайту.
Один зайвий символ — і чекер бачить 404.Одрук у назві теки — найчастіша причина червоного фінального критерію. Команда нижче проходить усі вісім посилань за секунду й показує код кожного.
Вивід тут ілюстративний — показано, як виглядає знайдена помилка. У тебе всі вісім мають бути 200.
Набирати довгу адресу на телефоні незручно. Тому згенеруй QR-код.
Програма qrencode уміє віддавати його як SVG,
а SVG приймальня пропускає.
Чекер пише: lesson-04 → 404. Ти заходиш по FTP — тека
lesson-04 на місці, файли всередині є. Що перевіряєш першим?
Тему 5 ти закрив давно, а в теці www/lesson-05/ досі лежить
забутий out.mp4 на 12 МБ. Сьогодні йде фінальний прогін
по всьому кабінету. Що буде?
Спочатку доводимо сцену локально, тоді заливаємо. Галочки зберігаються — сторінку можна закрити.
index.html лежить поруч із локальною копією
aframe.min.js.
По FTP іде лише готовий легкий текст.
Медіафайли сервер і не прийме.check 08Найважчий чекер модуля. Він відкриває сцену справжнім браузером без вікна, рахує об'єкти й натискає на них. Спроби не обмежені.
Демонстраційний режим: результат згенеровано для показу. На сервері
ця кнопка викликає POST /api/check, який запускає
/opt/school/check/lesson-08.sh від імені учня.
Код він не читає. Код можна написати гарно й неробочий.
Замість цього він відкриває сторінку браузером без вікна.
Зчитує напис у <a-text>. Робить два кліки
по клікабельному об'єкту. Зчитує напис ще раз.
Не змінилося — критерій червоний. Навіть якщо на вигляд усе на місці.
З консоллю так само. Чекер збирає всі помилки рівня error.
Їх має бути нуль. Один 404 на шрифт — і критерій не пройдено.
Це те, що бачить учитель, коли виставляє оцінку.
| Складник | Вага | Результат |
|---|
Надішли посилання на своє портфоліо у чат класу. Додай три речення: яка з восьми тем виявилася найкориснішою і чому.
Не «сподобалась», а саме найкорисніша. Тобто те, чим ти скористаєшся поза уроком.
У вересні ти вмів користуватися комп'ютером. Зараз ти вмієш давати йому команди й розуміти, що він відповідає.
І в тебе є адреса в інтернеті, де це видно. Не переказ уроків, а вісім робіт, які ти зробив сам.
| Тема | Не вмів на початку | Умієш тепер |
|---|---|---|
| Вступ | сервер — щось абстрактне | заходиш по SSH, орієнтуєшся в кабінеті, публікуєш файл по FTP |
| 1 | «у мене хороший комп'ютер» | читаєш склад машини командами й пишеш скрипт, що робить це за тебе |
| 2 | «інтернет не працює» | розрізняєш кабель, порт і протокол, міряєш швидкість і читаєш маршрут |
| 3 | звук — просто файл | рахуєш розмір WAV за формулою і пояснюєш, за що платиш бітрейтом |
| 4 | «картинка розмита, збільш її» | вибираєш формат під задачу і робиш вектор, який не розмивається ніколи |
| 5 | відео = mp4 | відрізняєш кодек від контейнера й монтуєш із командного рядка |
| 6 | тип файлу — це розширення | визначаєш справжній тип за першими байтами й автоматизуєш це скриптом |
| 7 | ШІ «просто малює» | розумієш, звідки береться зображення, і чесно позначаєш походження |
| 8 | 3D — це магія | пишеш власну сцену з анімацією та інтерактивом і налагоджуєш її по консолі |
Є ще одна навичка, і вона не належить жодній темі окремо. Ти навчився шукати причину, а не перезавантажувати.
404 у консолі. Великі літери в імені файлу. Зайва кома в атрибуті. Це вже не «нічого не працює», а конкретна поломка з конкретним виправленням.
Саме це й лишиться з тобою, коли назви бібліотек і версій забудуться.
Офіційна документація A-Frame, специфікації й довідники. Перевіряти дозволено й корисно.
<a-scene>,
примітиви, система «сутність — компонент».
aframe.io/docs/1.7.0/introductionanimation: властивості property,
to, dur, loop, dir,
easing.
aframe.io/docs/1.7.0/components/animationcursor: як курсор породжує події
click, mouseenter, mouseleave.
aframe.io/docs/1.7.0/components/cursorraycaster: властивість objects
і чому селектор економить кадри.
aframe.io/docs/1.7.0/components/raycastertext: MSDF-шрифти, властивість font,
стандартний шрифт roboto з cdn.aframe.io.
aframe.io/docs/1.7.0/components/texta-box, a-sphere
(радіус 1), a-cylinder, a-plane, a-sky.
aframe.io/docs/1.7.0/primitivescamera: положення камери за замовчуванням
на висоті 1,6 м.
aframe.io/docs/1.7.0/components/camerasetAttribute у A-Frame: форма з трьох аргументів
для однієї властивості компонента.
aframe.io/docs/1.7.0/core/entityaframe-event-set-component — стороннє доповнення,
яке не входить до aframe.min.js.
github.com/supermedium/superframe · event-setassets/…
і /assets/… ведуть у різні місця.
developer.mozilla.org · What is a URLПовний список із поясненнями, що саме звідки взято і які числа
є ілюстративними, — у файлі urok-16-джерела.md поруч
із цією сторінкою.