Как я детей вайбкодингу учил
- пятница, 3 апреля 2026 г. в 00:00:07
Привет, Хабр.
Я продолжаю свою педагогическую вахту. В прошлый раз я рассказывал о том, как боролся с костылями в генераторе судоку, а сегодня хочу поднять тему, которая вызывает массу споров: искусственный интеллект.
У меня сложилось стойкое ощущение, что среди моего окружения почти никто не умеет пользоваться этим инструментом правильно. Для большинства это либо волшебная кнопка, которая выдает мусор, либо шпаргалка, убивающая критическое мышление. Я решил показать детям другой путь, когда ИИ становится не заменой мозга, а мощным ускорителем реализации идей.

Подготовительный этап: Чтение кода глазами
Прежде чем бросаться в омут, нам нужно было заложить фундамент. Мы с ребятами уже прошли основы HTML и CSS. Мой метод был прост: я давал им готовые файлы, густо испачканные комментариями. Логика была такая: Посмотри в строку 42, измени параметр background-color, сохрани и посмотри на страницу, что изменилось? Это приучило их не бояться чужого кода и понимать куда именно нужно смотреть, чтобы увидеть результат своих действий.
Концепция: От карандаша к алгоритму
Когда руки перестали дрожать при виде тегов, мы перешли к проектированию. Я сторонник того, что любая программа начинается на бумаге. Мы взяли обычные листы А4 и обычные карандаши.
В качестве идеи выбрали классику, аналог игры Поймай крота (Whack-a-mole). Но делать просто кротов скучно. Мы решили, вместо кротов у нас будут фотографии самих учеников. В обычном состоянии - просто лицо, а в момент “появления” - то же, но с раздутыми щеками.
Мы обсудили логику:
Сетка из “норок”
Рандомное появление изображения в одной из ячеек
Таймер и сброс состояния
Почему такой стек?
Выбор пал на HTML, CSS и JavaScript. Для школьного проекта это идеальное сочетание:
Нулевой порог входа: не нужно устанавливать тяжелые IDE или настраивать окружение. Достаточно браузера и блокнота
Мгновенный фидбек: изменил строчку, нажал F5, увидел результат
Портируемость: проект можно отправить родителям в виде одной ссылки или файла, и он будет работать везде
Пока дети фотографировались и нарезали фотографии в Фотошопе, для "учительской” реализации я решил использовать картинки с мультяшными котиками. Выбрав одну в интернете, с помощью нехитрого промта, я сгенерировал ещё восемь других котят и девять реакций на прикосновение.

Составляем промт
Я объяснил детям, что ИИ, это очень исполнительный, но бесконечно глупый стажер. Если попросить его “сделай игру”, он выдаст среднюю температуру по больнице.
Мы сели и вместе составили подробный запрос для бесплатного ИИ от Google (Gemini).
Prompt for creating the game "Catch the Cheeks"
Role: You are an experienced Frontend developer. You need to create a simple web game using pure HTML, CSS, and JavaScript in a single file. It should be similar to “Whac-A-Mole,” but instead of characters popping up, use photos where they puff their cheeks.
Overall style: Light background, everything centered on the page.
Game field: A white panel with rounded corners and a soft shadow. Inside is a 3×3 grid.
Cells: 9 square images. The images should have rounded corners and a press (shrink) effect when clicked.
On mobile devices, the cells should scale relative to the screen width.
Use 18 image files.
Normal state: photo 1 normal.jpg … photo 9 normal.jpg.
Changed state: photo 1 highlighted.jpg … photo 9 highlighted.jpg.
Every 5 seconds, a random “normal” image changes to “highlighted” (puffed cheeks).
The player must click or tap the image to return it to the “normal” state.
With each new change, the game speed increases.
If all 9 images become “highlighted” at the same time, the game ends.
On loss, input (clicks/taps) is completely disabled for 5 seconds.
All 9 images start blinking synchronously (normal/puffed) every 0.5 seconds.
After 5 seconds from the start of blinking, a modal window appears.
The modal background should blur the game.
Modal text:
once again?Button:
sure!
Clicking the button resets all timers, clears the field, and returns the game to its initial speed.
Code requirements:
All code (HTML, CSS, JS) must be in a single file.
Use modern JavaScript methods.
Include concise and clear explanatory comments for styles and key functions.
Make sure there are no blue tap highlights on smartphones.
Что из этого вышло
Через несколько секунд у нас был рабочий прототип. Конечно, нам пришлось внести пару корректировок, но база была создана мгновенно.
Ниже финальный результат нашего совместного творчества с ИИ.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Kittens!</title> <style> /* Variables for easy adjustment of sizes and colors in one place ตัวแปรสำหรับการปรับขนาดและสีในที่เดียวอย่างง่ายดาย */ :root { --bg-color: #f0f2f5; /* Light gray background / พื้นหลังสีเทาอ่อน */ --grid-gap: 15px; /* Distance between cards / ระยะห่างระหว่างการ์ด */ --cell-size: 180px; /* Base size of the photo square / ขนาดพื้นฐานของช่องรูปภาพ */ --text-color: #333; /* Dark gray color for text / สีเทาเข้มสำหรับข้อความ */ } /* Main screen settings การตั้งค่าหน้าจอหลัก */ body { margin: 0; padding: 0; display: flex; /* Use Flexbox for alignment / ใช้ Flexbox สำหรับจัดวาง */ justify-content: center; /* Center horizontally / จัดกึ่งกลางแนวนอน */ align-items: center; /* Center vertically / จัดกึ่งกลางแนวตั้ง */ min-height: 100vh; /* Height equals browser window / ความสูงเท่ากับหน้าต่างเบราว์เซอร์ */ background-color: var(--bg-color); font-family: 'Segoe UI', Tahoma, sans-serif; overflow: hidden; /* Disable scrolling / ปิดการเลื่อนหน้าจอ */ user-select: none; /* Disable selection on fast clicks / ปิดการเลือกข้อความเมื่อคลิกเร็วๆ */ -webkit-tap-highlight-color: transparent; /* Remove blue highlight on mobile tap / ลบแถบไฮไลท์สีน้ำเงินเมื่อแตะบนมือถือ */ } /* General container for instructions and the game คอนเทนเนอร์หลักสำหรับคำแนะนำและตัวเกม */ .main-wrapper { display: flex; flex-direction: column; /* Stack text and grid vertically / วางข้อความและตารางต่อกันในแนวตั้ง */ align-items: center; /* Center horizontally / จัดกึ่งกลางแนวนอน */ } /* Styles for text instructions สไตล์สำหรับคำแนะนำข้อความ */ .instructions { text-align: center; /* Center text / ข้อความจัดกึ่งกลาง */ color: var(--text-color); font-size: 1.8rem; line-height: 1.4; /* Line spacing for two lines / ระยะห่างระหว่างบรรทัด */ margin-bottom: 25px; /* Spacing from text to game field / ระยะห่างถึงพื้นที่เล่นเกม */ font-weight: 500; } /* 3x3 game grid container คอนเทนเนอร์ตารางเกมขนาด 3x3 */ .game-container { display: grid; grid-template-columns: repeat(3, 1fr); /* 3 equal columns / 3 คอลัมน์เท่ากัน */ grid-template-rows: repeat(3, 1fr); /* 3 equal rows / 3 แถวเท่ากัน */ gap: var(--grid-gap); padding: 20px; background: white; /* White background under grid / พื้นหลังสีขาวใต้ตาราง */ border-radius: 24px; /* Rounding of the main tablet / การลบมุมของกระดานหลัก */ box-shadow: 0 10px 40px rgba(0,0,0,0.08); /* Soft shadow for volume / เงาฟุ้งเพื่อสร้างมิติ */ position: relative; } /* Locked state: disable clicks when game is over สถานะล็อก: ปิดการคลิกเมื่อเกมจบลง */ .game-container.disabled { pointer-events: none; /* Ignore mouse/tap inputs / ไม่รับการคลิกหรือการแตะ */ } /* Wrapper for each photo คอนเทนเนอร์สำหรับแต่ละรูปภาพ */ .cell { width: var(--cell-size); height: var(--cell-size); overflow: hidden; /* Clip photo edges / ตัดขอบรูปภาพไม่ให้ล้น */ border-radius: 16px; /* Corner rounding of the photo / การลบมุมของรูปภาพ */ cursor: pointer; transition: transform 0.1s ease; /* Smooth animation on click / แอนิเมชันที่ลื่นไหลเมื่อคลิก */ background: #f9f9f9; /* Background color while loading / สีพื้นหลังขณะรอโหลดรูป */ } /* Click effect: card shrinks slightly / เอฟเฟกต์เมื่อคลิก: การ์ดย่อตัวลงเล็กน้อย */ .cell:active { transform: scale(0.96); } /* Actual image inside cell / รูปภาพภายในช่อง */ .cell img { width: 100%; height: 100%; object-fit: cover; /* Fill square without distortion / เติมเต็มช่องโดยไม่เสียสัดส่วน */ display: block; } /* Fullscreen modal window หน้าต่างโมดอลแบบเต็มจอ */ #modal { display: none; /* Hidden by default / ซ่อนไว้โดยค่าเริ่มต้น */ position: fixed; /* Fixed on top of all content / ยึดไว้ด้านบนสุดของเนื้อหาทั้งหมด */ top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.01); /* Transparent background / พื้นหลังโปร่งใส */ backdrop-filter: blur(15px); /* Main effect: background blur / เอฟเฟกต์เบลอพื้นหลัง */ -webkit-backdrop-filter: blur(15px); /* Safari blur support / รองรับการเบลอใน Safari */ justify-content: center; /* Center content horizontally / จัดเนื้อหาให้อยู่กึ่งกลางแนวนอน */ align-items: center; /* Center content vertically / จัดเนื้อหาให้อยู่กึ่งกลางแนวตั้ง */ z-index: 100; /* Bring to front / นำมาไว้ที่ชั้นหน้าสุด */ } /* White card inside modal / แผ่นสีขาวภายในหน้าต่างโมดอล */ .modal-content { background: white; padding: 50px; border-radius: 30px; text-align: center; box-shadow: 0 15px 60px rgba(0,0,0,0.15); /* Deep shadow for accent / เงาที่ลึกเพื่อความโดดเด่น */ border: 1px solid rgba(255,255,255,0.3); } .modal-content h2 { margin: 0 0 30px 0; font-size: 28px; color: #222; } /* Restart button / ปุ่มเริ่มเกมใหม่ */ .modal-content button { background: #222; /* Dark stylish button / ปุ่มสไตล์สีเข้ม */ color: white; border: none; padding: 16px 50px; font-size: 18px; border-radius: 14px; cursor: pointer; transition: all 0.2s ease; } .modal-content button:hover { background: #000; transform: translateY(-2px); /* Float up effect / เอฟเฟกต์ลอยขึ้นเมื่อวางเมาส์ */ box-shadow: 0 5px 15px rgba(0,0,0,0.2); } /* Adaptation for mobile devices การปรับให้เหมาะสมกับอุปกรณ์มือถือ */ @media (max-width: 650px) { :root { --cell-size: 28vw; /* Size depends on screen width / ขนาดช่องตามความกว้างหน้าจอ */ --grid-gap: 10px; /* Reduce gaps on small screens / ลดระยะห่างบนหน้าจอเล็ก */ } .instructions { font-size: 1rem; /* Smaller text on mobile / ลดขนาดข้อความบนมือถือ */ } } </style> </head> <body> <div class="main-wrapper"> <div class="instructions"> look carefully at the kittens<br> if anything has changed - tap </div> <div class="game-container" id="grid"></div> </div> <div id="modal"> <div class="modal-content"> <h2>once again?</h2> <button id="restartBtn">sure!</button> </div> </div> <script> const grid = document.getElementById('grid'); const modal = document.getElementById('modal'); const restartBtn = document.getElementById('restartBtn'); const TOTAL_CELLS = 9; const INITIAL_DELAY = 4600; const SPEED_UP_FACTOR = 0.96; let states = Array(TOTAL_CELLS).fill(false); let currentDelay = INITIAL_DELAY; let gameTimer = null; let flashTimer = null; let isGameOver = false; // Grid initialization: creating cells and adding handlers // การเริ่มต้นตาราง: สร้างช่องต่างๆ และเพิ่มตัวรับเหตุการณ์ function initGrid() { grid.innerHTML = ''; for (let i = 1; i <= TOTAL_CELLS; i++) { const cell = document.createElement('div'); cell.className = 'cell'; const img = document.createElement('img'); img.src = `photo ${i} normal.jpg`; cell.appendChild(img); cell.addEventListener('click', () => handleCellClick(i - 1)); cell.addEventListener('touchstart', (e) => { e.preventDefault(); // Prevent mouse emulation after tap / ป้องกันการเลียนแบบการคลิกเมาส์ handleCellClick(i - 1); }); grid.appendChild(cell); } } // Updating a specific image / การอัปเดตรูปภาพเฉพาะเจาะจง function updateImage(index, forceState = null) { const img = grid.children[index].querySelector('img'); const photoNum = index + 1; const isHighlighted = (forceState !== null) ? forceState : states[index]; img.src = isHighlighted ? `photo ${photoNum} highlighted.jpg` : `photo ${photoNum} normal.jpg`; } // Click logic: resetting the "puffed cheeks" state / ตรรกะการคลิก: รีเซ็ตสถานะ "แก้มป่อง" function handleCellClick(index) { if (isGameOver) return; if (states[index]) { states[index] = false; updateImage(index); } } // Main game loop / ลูปหลักของเกม function gameStep() { if (isGameOver) return; const normalIndices = states .map((s, i) => s === false ? i : null) .filter(i => i !== null); if (normalIndices.length > 0) { const randomIdx = normalIndices[Math.floor(Math.random() * normalIndices.length)]; states[randomIdx] = true; updateImage(randomIdx); if (states.every(s => s === true)) { triggerGameOver(); return; } // Interval acceleration / การเร่งความเร็วของช่วงเวลา currentDelay *= SPEED_UP_FACTOR; if (currentDelay < 300) currentDelay = 300; clearTimeout(gameTimer); gameTimer = setTimeout(gameStep, currentDelay); } } // Finale: flashing and lockout for 5 seconds / ช่วงจบเกม: การกะพริบและล็อกการทำงาน 5 วินาที function triggerGameOver() { isGameOver = true; clearTimeout(gameTimer); grid.classList.add('disabled'); // Enable CSS click blocking / เปิดการใช้งานการล็อกการคลิกด้วย CSS let flashOn = false; flashTimer = setInterval(() => { flashOn = !flashOn; for (let i = 0; i < TOTAL_CELLS; i++) { updateImage(i, flashOn); } }, 500); setTimeout(() => { modal.style.display = 'flex'; // Show blur and button / แสดงการเบลอและปุ่ม }, 5000); } // Reset and start a new game / รีเซ็ตและเริ่มเกมใหม่ function resetGame() { isGameOver = false; modal.style.display = 'none'; grid.classList.remove('disabled'); clearInterval(flashTimer); states.fill(false); currentDelay = INITIAL_DELAY; for (let i = 0; i < TOTAL_CELLS; i++) updateImage(i); gameTimer = setTimeout(gameStep, currentDelay); } restartBtn.addEventListener('click', resetGame); initGrid(); gameTimer = setTimeout(gameStep, INITIAL_DELAY); </script> </body> </html>
https://drive.google.com/drive/folders/1kBznLB6SKCJ6DsulXsYVCvjdvfBBjbGA?usp=sharing
Итоги
Главный урок, который вынесли дети: программирование сегодня, это не только знание синтаксиса, но и умение четко формулировать свои мысли. Мы не просто “списали” код у робота, мы выступили в роли архитекторов, которые использовали ИИ как очень быстрые руки.
Дети были в восторге. Оказывается, чтобы создать свою игру с собой в главной роли, не нужно учиться пять лет, нужно просто понимать, как работают базовые технологии и как правильно разговаривать с “кремниевым разумом”.
Это и есть тот самый вайбкодинг: минимум рутины, максимум творчества и быстрая реализация идей.
Вместо послесловия
Прислушавшись к немногочисленным, но полезным комментариям к предыдущей статье, я решил подумать над новой идеей для игры, которая не была бы "головоломкой для яйцеголовых". И мне кажется, такую идею я нашёл. Новый проект показался мне ещё более интересным! Мне пришлось изучать логику работы "искусственных противников" и столкнуться с нехваткой вычислительных мощностей для сложной математики. Плотно работаю над реализацией. Ниже фотографии моих самых маленьких тестеров. Сейчас "летние занятия", и с программой не так строго.



