Своя игра: создаём собственную «Змейку»
Не так давно мы разбирали, как искусственный интеллект учится играть в змейку. А теперь мы сами сделаем такую игру, чтобы ей могли насладиться обычные люди. Что нам понадобится:
- HTML, чтобы можно было играть прямо в браузере;
- CSS для украшений;
- JavaScript для самой игры.
Логика игры
У классической змейки правила простые:
- есть поле из клеточек, где случайным образом появляется еда;
- есть змейка, которая всё время двигается и которой мы можем управлять;
- если змейка на своём пути встречает еду — еда исчезает, появляется в новом месте, а сама змейка удлиняется на одну клеточку;
- если змейка врежется в стену или в саму себя, игра заканчивается.
Чтобы играть было проще, мы сделаем так, чтобы змейка не врезалась в стенки, а проходила сквозь них. Если что — сможете это сами потом настроить в коде, когда захотите посложнее.
Последовательность наших действий будет такой:
- Делаем пустую HTML-страницу.
- Настраиваем внешний вид с помощью CSS.
- Рисуем игровое поле.
- Пишем скрипт, который и будет отвечать за всю игру.
Делаем HTML-страницу
С этим всё просто: берём стандартный код и сохраняем его как файл snake.html .
Змейка
Это даст нам пустую страницу, которую мы сейчас немного настроим стилями.
Настраиваем внешний вид
За внешний вид на странице у нас отвечает раздел , поэтому мы просто добавим в него CSS-код:
html, body < height: 100%; margin: 0; >/*Задаём глобальные параметры*/ body < background: black; display: flex; align-items: center; justify-content: center; >/*Делаем границу вокруг игрового поля*/ canvas
Теперь у нас на странице нет лишних отступов, зато всё по центру, есть чёрный фон и граница вокруг игрового поля. Самое время создать само игровое поле.
Рисуем игровое поле
Поле делается очень просто:
400 пикселей в ширину, столько же в высоту, название поля — game. Этого достаточно, чтобы браузер отобразил холст с такими размерами и позволил нам на нём рисовать.
Пишем скрипт
1. Зададим все переменные, которые нам понадобятся.
// Поле, на котором всё будет происходить, — тоже как бы переменная var canvas = document.getElementById('game'); // Классическая змейка — двухмерная, сделаем такую же var context = canvas.getContext('2d'); // Размер одной клеточки на поле — 16 пикселей var grid = 16; // Служебная переменная, которая отвечает за скорость змейки var count = 0; // А вот и сама змейка var snake = < // Начальные координаты x: 160, y: 160, // Скорость змейки — в каждом новом кадре змейка смещается по оси Х или У. На старте будет двигаться горизонтально, поэтому скорость по игреку равна нулю. dx: grid, dy: 0, // Тащим за собой хвост, который пока пустой cells: [], // Стартовая длина змейки — 4 клеточки maxCells: 4 >; // А это — еда. Представим, что это красные яблоки. var apple = < // Начальные координаты яблока x: 320, y: 320 >;
2. Сделаем генератор случайных чисел. Он нам понадобится, чтобы размещать еду на поле случайным образом.
// Делаем генератор случайных чисел в заданном диапазоне
function getRandomInt(min, max) < return Math.floor(Math.random() * (max - min)) + min;
3. Напишем основной игровой цикл, который будет работать бесконечно.
// Игровой цикл — основной процесс, внутри которого будет всё происходить function loop() < // Дальше будет хитрая функция, которая замедляет скорость игры с 60 кадров в секунду до 15. Для этого она пропускает три кадра из четырёх, то есть срабатывает каждый четвёртый кадр игры. Было 60 кадров в секунду, станет 15. requestAnimationFrame(loop); // Игровой код выполнится только один раз из четырёх, в этом и суть замедления кадров, а пока переменная count меньше четырёх, код выполняться не будет. if (++count < 4) < return; >// Обнуляем переменную скорости count = 0; // Очищаем игровое поле context.clearRect(0, 0, canvas.width, canvas.height); // Двигаем змейку с нужной скоростью snake.x += snake.dx; snake.y += snake.dy; // Если змейка достигла края поля по горизонтали — продолжаем её движение с противоположной стороны if (snake.x < 0) < snake.x = canvas.width - grid; >else if (snake.x >= canvas.width) < snake.x = 0; >// Делаем то же самое для движения по вертикали if (snake.y < 0) < snake.y = canvas.height - grid; >else if (snake.y >= canvas.height) < snake.y = 0; >// Продолжаем двигаться в выбранном направлении. Голова всегда впереди, поэтому добавляем её координаты в начало массива, который отвечает за всю змейку. snake.cells.unshift(< x: snake.x, y: snake.y >); // Сразу после этого удаляем последний элемент из массива змейки, потому что она движется и постоянно особождает клетки после себя if (snake.cells.length > snake.maxCells) < snake.cells.pop(); >// Рисуем еду — красное яблоко context.fillStyle = 'red'; context.fillRect(apple.x, apple.y, grid - 1, grid - 1); // Одно движение змейки — один новый нарисованный квадратик context.fillStyle = 'green'; // Обрабатываем каждый элемент змейки snake.cells.forEach(function (cell, index) < // Чтобы создать эффект клеточек, делаем зелёные квадратики меньше на один пиксель, чтобы вокруг них образовалась чёрная граница context.fillRect(cell.x, cell.y, grid - 1, grid - 1); // Если змейка добралась до яблока. if (cell.x === apple.x && cell.y === apple.y) < // увеличиваем длину змейки snake.maxCells++; // Рисуем новое яблочко // Помним, что размер холста у нас 400x400, при этом он разбит на ячейки — 25 в каждую сторону apple.x = getRandomInt(0, 25) * grid; apple.y = getRandomInt(0, 25) * grid; >// Проверяем, не столкнулась ли змея сама с собой // Для этого перебираем весь массив и смотрим, есть ли у нас в массиве змейки две клетки с одинаковыми координатами for (var i = index + 1; i < snake.cells.length; i++) < // Если такие клетки есть — начинаем игру заново if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) < // Задаём стартовые параметры основным переменным snake.x = 160; snake.y = 160; snake.cells = []; snake.maxCells = 4; snake.dx = grid; snake.dy = 0; // Ставим яблочко в случайное место apple.x = getRandomInt(0, 25) * grid; apple.y = getRandomInt(0, 25) * grid; >> >); >
4. Сделаем управление стрелочками на клавиатуре.
// Смотрим, какие нажимаются клавиши, и реагируем на них нужным образом document.addEventListener('keydown', function (e) < // Дополнительно проверяем такой момент: если змейка движется, например, влево, то ещё одно нажатие влево или вправо ничего не поменяет — змейка продолжит двигаться в ту же сторону, что и раньше. Это сделано для того, чтобы не разворачивать весь массив со змейкой на лету и не усложнять код игры. // Стрелка влево // Если нажата стрелка влево, и при этом змейка никуда не движется по горизонтали… if (e.which === 37 && snake.dx === 0) < // то даём ей движение по горизонтали, влево, а вертикальное — останавливаем // Та же самая логика будет и в остальных кнопках snake.dx = -grid; snake.dy = 0; >// Стрелка вверх else if (e.which === 38 && snake.dy === 0) < snake.dy = -grid; snake.dx = 0; >// Стрелка вправо else if (e.which === 39 && snake.dx === 0) < snake.dx = grid; snake.dy = 0; >// Стрелка вниз else if (e.which === 40 && snake.dy === 0) < snake.dy = grid; snake.dx = 0; >>);
5. Запускаем игру. Для этого достаточно запустить предыдущий бесконечный цикл, поэтому пишем:
6. Наслаждаемся результатом:
Чтобы у вас тоже получилось такое, просто скопируйте готовый код, сохраните его как HTML-файл и откройте в браузере.
Готовый код
Змейка html, body < height: 100%; margin: 0; >/*Задаём глобальные параметры*/ body < background: black; display: flex; align-items: center; justify-content: center; >/*Делаем границу вокруг игрового поля*/ canvas
Как улучшить
Этот код — самая простая реализация змейки, и игру можно сделать ещё лучше:
- выводить количество набранных очков;
- сделать так, чтобы нельзя было проходить сквозь стены;
- добавить препятствия;
- поставить таймер — кто больше соберёт еды за 5 минут;
- добавить вторую змейку и играть вдвоём.
Проголосуйте за тот вариант, который вам больше всего нравится, в комментариях, или сделайте свою змейку, где всё это будет одновременно.
Апскиллинг, как говорится
Апскиллинг — это, например, переход с уровня junior на уровень middle, а потом — senior. У «Яндекс Практикума» есть курсы ровно для этого: от алгоритмов и типов данных до модных фреймворков.

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Как я сделал игру для Блокнота
Пока читал про необычные решения от инди-разработчиков, наткнулся на золото. Вот вам статья про игру в текстовом редакторе. Арт, анимация, сюжет — все как положено.
Я создал игру And yet it hurt (возможно, автор хотел сказать it hurts, но мог использовать такой вариант намеренно, — прим.).
Все началось в 2017 году с вопроса: «Реально ли сделать игру в Блокноте?» Тогда я только усмехнулся. Прошло три года. Обдумав, как все будет работать, и убедившись, что это реально, я решил сделать эту игру.
Обычно вы жмете на кнопку, и в игре что-то происходит. Жмете А, и Марио прыгает. Все завязано на получении информации и отклике. Игра получает входные данные и выводит свои.
В игре для Блокнота на входе будут изменения, которые вносит пользователь в файл, а на выходе изменения, которые вносит в файл сама игра. Для этого приложение отслеживает время последнего сохранения файла. Если оно изменилось, игра считывает содержимое файла и вносит в него новые данные.
Возникает проблема: Блокнот от Microsoft не проверяет, был ли файл изменен. Пришлось бы сохранять файл, закрывать и открывать его заново. Создать такую игру возможно, но звучит не очень весело. Пришлось искать альтернативу.
Могу понять ваше разочарование из-за того, что игра в итоге сделана не в самом обычном Блокноте. Мой тайтл можно запустить в нем — просто процесс немного замороченный. Я решил пожертвовать крутостью проекта, чтобы сделать игру более приятной.
Альтернатива
Пришлось искать другой текстовый редактор. Единственным требованием было — автоматическое обновление файла. Хотя чуть позже вы увидите, что я использовал еще одну фичу.
Сначала на ум пришли Notepad++ и Sublime Text. Но они совсем не похожи на Блокнот внешне, очарование проекта развеялось бы окончательно. Плюс, они спрашивают игрока, хотел бы он обновить файл. Это куда лучше, чем закрывать и открывать файл, но все равно отвлекает от геймплея. Я хотел, чтобы файл обновлялся автоматически. Тогда мне на глаза попался Notepad2. Он был почти идеален.
Редактор можно настроить, чтобы он был похож на MS Блокнот, а главное — он проверяет изменения, внесенные в файл. Но также как Notepad++ и Sublime Text, Notepad2 спрашивает игрока, нужно ли изменить файл. К счастью, у редактора открытый код, и я мог отполировать его до совершенства.

Notepad2 написан на C. Я немного знаком с этим языком, пусть меня и нельзя назвать экспертом. Опытный программист Javascript сможет прочитать и уловить общую суть кода, но понять исходный код Notepad2, чтобы внести необходимые изменения, оказалось не так просто.
Для начала я решил поискать текст из диалогового окна: «Файл был изменен внешней программой. Перезагрузить файл?». Это значение переменной, которая используется в качестве аргумента в функции диалогового окна. И я ее нашел.
if ((iFileWatchingMode == 2 && !bModified && iEncoding == iOriginalEncoding) || MsgBox(MBYESNO,IDS_FILECHANGENOTIFY) == IDYES)
Этот код проверяет, не изменилось ли содержимое файла. Если оно изменилось, открывается окно, и программа проверяет, выбрал ли пользователь ответ «Да». Мне нужно было лишь заменить кусок
MsgBox(MBYESNO,IDS_FILECHANGENOTIFY) == IDYES
на TRUE, и программа начала автоматически обновлять файл. Таким образом, я создал рендер на базе ASCII. Осталось создать подходящий движок.
Отрисовка
Игра создана с любовью: LÖVE — фреймворк с открытым исходным кодом для 2D-игр, написанных на Lua. Я много лет пользовался этой платформой и даже собрал туториал. Для этого проекта в основном использовался LÖVE-модуль файловой системы, потому что он предоставляет все необходимые возможности. Обычно с помощью LÖVE создают изображение, которое затем выводится на экран.
Мне нужно было почти то же самое: вывод ASCII-арта в текстовом файле. Я начал с домика и птички, причем птичка должна была лететь через файл. Взял арт, который нашел на ASCII Art, но в игре используются только оригинальные работы (за исключением шрифтов).


Загрузка арта — это просто чтение файла.
house = love.filesystem.read("art_house.txt") bird = love.filesystem.read("art_bird.txt")
Дом используется в качестве фона, поэтому я начал с прорисовки этого изображения на «экране». Экран в данном случае — это home.txt.
love.filesystem.write("home.txt", house)
Я хотел, чтобы с птичкой можно было работать в таком ключе:
local x, y = 20, 40 drawArt(bird, x, y)
х — номер столбца, y — номер строки. Поэтому разбил экран и птицу на списки строк.
-- Get the current canvas screen = love.filesystem.read("home.txt") -- Create a table. A table is like an array. screen_lines = <> -- The lua pattern (.-)\n says capture everything until the \n (newline). -- We add an \n to the end of the file so that it captures the last line as well. for line in (screen .. "\n"):gmatch("(.-)\n") do table.insert(screen_lines, line) end
С птицей сделал то же самое. Теперь код, описывающий птицу, должен был перекрывать код про дом. Вот, что мне было нужно:
- Найти строку, в которой должна быть отрисована птица.
- Вывести всю строку до x.
- Вывести оставшуюся часть строки, начиная с x + длина арта с птицей.
- Создать новую строку с первой частью, птицей и оставшейся частью.
- Повторить то же самое для всех остальных строк.
function drawArt(art, x, y) art_lines = getLines(art) -- In Lua, you can get the length of a table and string with # for i=1, #screen_lines do if i == y then for j=1 ,#art_lines do -- With string:sub(start, end) we can get part of a string local first_part = screen_lines[i]:sub(1, x - 1) local second_part = screen_lines[i] :sub(x + #art_lines[j], #screen_lines[i]) screen_lines[i] = first_part .. art_lines[i] .. second_part end end end end
Наверное, вы заметили, что птица представляет собой прямоугольник — в ее арте используются пробелы. Чтобы исправить ситуацию, я посчитал количество пробелов в начале каждой строки и добавил это число к координатам, чтобы отрисовывался только арт.
-- (%s) gets all the whitespace characters. local spaces = art_lines[j]:match("(%s*)") -- Remove the spaces from the line. art_lines[i] = art_lines[i]:sub(#spaces + 1, #art_lines[i]) local first_part = screen_lines[i]:sub(1, x + #spaces - 1) local second_part = screen_lines[i]:sub(x + #spaces + #art_lines[j], #screen_lines[i]) screen_lines[i] = first_part .. art_lines[i] .. second_part
Стало намного лучше:
Анимация
Я начал добавлять больше фишек, например, анимацию:
Все кадры расположены в одном файле и разделены тегом >. Тег определяется при чтении и позволяет задать последовательность кадров. Благодаря этому мы получаем классическую анимацию. Создаем таймер и отрисовываем кадры в соответствии с ним.
> _ _ 'v' > --v-- > _/v\_
Также я реализовал вывод печатаемого текста и отобразил отдельно экран, инвентарь и окно для ввода решения. Оставалась одна проблема. Как игра узнает, что был открыт файл? Это и есть вторая фича, о которой я говорил ранее.
В исходном коде Notepad2 я прописал, что файл должен сохраняться сразу после открытия. Затем игра проверяет, не изменилось ли время последнего сохранения. Так она узнает, что файл был открыт, и может его менять.
// At the end of the FileLoad function. // If the file is not new, and the file has not been reloaded, save it. if (!bNew && !bReload)
В итоге я получил фреймворк, в котором можно работать. Самое время создавать игру.
За девять дней разработки (судя по дате создания gif-файлов) я сделал это:
Если вы запускали игру, то знаете, что в ней нет печатаемого текста и анимации. На то было несколько причин:
- Я опасался, что порчу свой HDD/SSD постоянной перезаписью файла. Тестирование игры с этими функциями сделало из меня параноика. Не хочу, чтобы игроки испытывали это чувство.
- Вы не можете ничего делать во время анимации. Если вы попытаетесь выбрать ответ и напечатаете символ в окошке, вы не успеете сохраниться до того, как следующий кадр загрузится и удалит ваш символ. Так что поначалу анимации кажутся классными, но в итоге только мешают.
- Анимация — это здорово, но она не вписывается в стиль Блокнота. В текстовых файлах не должно быть анимации. По той же причине в игре нет музыки. Конечно, я мог сделать так, чтобы игра создавала аудио-файл, который вы открыли бы в медиаплеере. Но такие действия отвлекали бы от Блокнота. Я оставил несколько анимаций, чтобы показать, как круто они выглядят. Плюс, во время сражения врага лучше бить, когда он моргает, — хороший сигнал к действию.
Программа по умолчанию
Меня бесило, что пользователю приходилось перетаскивать файл в окно Notepad2 для запуска игры. При двойном щелчке по файлу, открывался Блокнот или другая программа по умолчанию для чтения .txt. Можно было прописать команду, которая меняла приложение для таких файлов на Notepad2, но лично мне не понравится, если какая-то игра проделает такой финт на моем компьютере.
Может, возвращать исходные настройки при закрытии игры? Это возможно, но возникнет проблема, если игра вылетит или неожиданно закроется.
Все решения казались недостаточно обоснованными, пока я не догадался, что вместо обычных .txt можно использовать файлы с другим «x». Если быть точным — Unicode-символ U+0445 (Cyrillic Small Letter Ha). Чтобы не запутаться, я назвал файл *.tXt. В итоге, все файлы игры были с разрешением *.tXt, и по дефолту открывались в Notepad2.
assoc .tXt=tXt ftype tXt=[directory]/.notepad/Notepad2.exe "%1"
Программу по умолчанию можно назначить только от имени администратора. Если вы открываете игру под другой учетной записью, будут использоваться txt-файлы. Если вы открываете файл в обычном Блокноте, игра сообщит, что нужно перетащить файл в открытое окно Блокнота. Либо запустить ее от имени администратора, чтобы она открылась по дабл-клику.
Мотивация
На самом деле всё было сделано три года назад. Что я делал все остальное время? Классический пример отсутствия мотивации.
Изначально сюжет был немного длиннее, чем сейчас. Твоих родителей убил дракон, ты должен пойти к кузнецу Фердану, чтобы он выковал меч. Задумывалось, что меч делается из трех материалов, которые нужно собрать. Это сильно увеличивало объем игры и отодвигало конец разработки. Игра получалась не очень-то развлекательной, и я забросил проект через два месяца.
Но я все время держал его в голове. Я отладил целый фреймворк, который позволял создать игру в Блокноте, а проект не двигался с мертвой точки. Нужно было доделать его. В 2019 году я не завершил почти ни одного проекта. Разочарование подтолкнуло меня к решению: закончить незаконченное в 2020-м.
И вот она. Я сократил сюжет, дал себе месяц на все (получилось на неделю дольше) и бросился в бой. Еще подал заявку на A MAZE. Awards, соответственно, дедлайн был назначен на 2 февраля. Так появилась мотивация.
Заключение
Я рад, что доделал игру. Удивительно, сколько времени проект просто собирал цифровую пыль, а в итоге хватило месяца. Игру не стоило делать настолько объемной, как я хотел сначала — такой нестандартный проект должен лишь показывать особенности, которые можно в нем реализовать.
Что дальше? Игра в Paint? Игра в Калькуляторе? Вряд ли я их сделаю. Но мне нравится думать об играх, которые используют нетрадиционные платформы.
- Блог компании Playgendary
- Ненормальное программирование
- Разработка игр
- Дизайн игр
- Игры и игровые консоли
Как написать программу в блокноте
wikiHow работает по принципу вики, а это значит, что многие наши статьи написаны несколькими авторами. При создании этой статьи над ее редактированием и улучшением работали, в том числе анонимно, 44 человек(а).
Количество просмотров этой статьи: 205 746.
В этой статье:
Из этой статьи вы узнаете, как написать программу в стандартном приложении «Блокнот» для Windows. Если коротко, то вам нужно будет построчно ввести код программы в Блокнот, а затем сохранить файл в формате необходимого языка программирования.
Часть 1 из 6:
Общие указания
![]()
- Файлы Блокнота по умолчанию сохраняются в виде текстовых документов.
![]()
Найдите и запустите Блокнот. Наиболее простой способ запустить Блокнот — открыть меню «Пуск»

, ввести блокнот , а затем нажать на синюю иконку Блокнота в верхней части меню «Пуск».
![]()
- Если вы не знаете ни одного языка программирования, воспользуйтесь одним из примеров, указанных в статье.
![]()
Завершив строку кода, нажмите ↵ Enter . Как и в большинстве редакторов кода, отдельные строки кода должны располагаться на разных строках Блокнота.
![]()
Закройте все открытые фигурные и квадратные скобки. Если вы открыли квадратную или фигурную скобки ( или [ ), ее обязательно нужно закрыть, чтобы завершить строку кода. Несоблюдение этого правила приведет к ошибкам в коде.
Редактор для HTML: пишем код, чтобы было удобно
Для того, чтобы написать код, сгодится вообще любой текстовый редактор. Подойдёт даже «Блокнот» на вашем компьютере (но в нём очень неудобно всё делать). Мы скачаем и установим хороший редактор, заточенный под веб-разработку. Покажем всё на примере Visual Studio Code.
Зайдите на сайт и скачайте редактор. Если у вас Windows, то нажмите на любую из синих кнопок. Если Mac OS или Linux — нажмите Other platforms.

Установка пройдёт как обычно — нужно запустить файл VSCodeUserSetup, много раз нажать «Далее» и поставить пару галочек.
Шаг 2. Запускаем редактор и осматриваемся
Свежеустановленный VS Code встречает нас экраном с большим количеством ссылок. С ними можно познакомиться позже, а сейчас нужно настроить всё для работы.
Хорошо бы, чтобы во время работы все нужные файлы лежали в одной папке (пока проект маленький, так можно делать). Для этого добавим рабочую папку, чтобы VS Code показывал нам только её содержимое.

По шагам на скриншоте:
- Add workspace folder — открывает меню выбора папки.
- Создадим новую папку personal_page в любом удобном месте и зайдём в неё.
- Нажмём Add.
После этого слева появится панель Explorer с пустым рабочим пространством Untitled (Workspace). Мы создали папку, давайте её наполним.
Шаг 3. Добавляем файлы
После создания папка пустая. Щёлкнем правой кнопкой по заголовку personal_page и добавим три файла, которые понадобятся в работе — index.html, style.css и script.js. Для начала этого хватит.
Шаг 4. Делаем работу удобнее
Сейчас все три файла открыты во вкладках, и между ними не всегда удобно переключаться. Чтобы было удобнее, код со стилями можно перенести в другую часть окна, например, вниз. Для этого нажмите правой кнопкой по вкладке со style.css и выберите split down, чтобы увидеть результат.

Шаг 5. Добавляем код
Пока отредактируем только index.html (файл с разметкой) и style.css (файл со стилями), а script.js оставим на будущее. Если у вас уже есть какой-нибудь код, напишите его, или используйте готовый — мы, например, возьмём код из интерактивных курсов.
Сайт начинающего верстальщика Взгляд упал на кота.
Скопируем код со стилями из файла — откройте его в браузере, скопируйте все строки и вставьте в файл style.css в редакторе.
Шаг 6. Запускаем код и смотрим на результат
Самый простой способ — открыть папку с файлами через проводник и запустить файл index.html . Вы увидите результат вёрстки в браузере, но это не слишком удобно — при любых изменениях придётся переходить в браузер и обновлять страницу.
Давайте настроим всё так, чтобы наша страничка открывалась сама и обновлялась, если вы что-то изменили в разметке или стилях.
Для этого нам понадобится расширение Live Server. Найти его можно прямо в VS Code (пятая иконка в меню слева) — введите название и нажмите Install. Другой способ — скачать Live Server из магазина расширений, но это менее удобно.

После установки расширения Windows может попросить разрешение на доступ к сети. Это нужно, чтобы запускать локальный сервер, Разрешайте, это безопасно.

Чтобы запустить код, нажмите кнопку Go Live на нижней панели.

Результат выглядит так. Слева — редактор, справа — браузер. Теперь измените код в редакторе и сохраните его, а он автоматически изменится и в окне браузера.
Что мы сделали
- Установили и настроили редактор кода.
- Создали рабочую папку и добавили туда файлы нашего проекта.
- Научились редактировать и сохранять файлы с кодом.
- Установили расширение, чтобы сразу видеть результат вёрстки.
«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.
