<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Web Dev Sandbox</title><subtitle>Веб-разработка, 3d моделирование и путешествия. 
Не только интересные статьи на тему IT, но и персональный блог с мыслями разработчика на удаленке! 🌏</subtitle><author><name>Web Dev Sandbox</name></author><id>https://teletype.in/atom/web_dev_sandbox</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/web_dev_sandbox?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@web_dev_sandbox?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=web_dev_sandbox"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/web_dev_sandbox?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-05-18T12:37:05.375Z</updated><entry><id>web_dev_sandbox:dev_simulate_notes_2</id><link rel="alternate" type="text/html" href="https://teletype.in/@web_dev_sandbox/dev_simulate_notes_2?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=web_dev_sandbox"></link><title>Симулятор разработки: приложение для заметок (часть 2)</title><published>2022-11-02T12:10:18.408Z</published><updated>2022-11-02T12:10:18.408Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/8b/76/8b76c63d-7413-4989-b570-6f9d5e83b672.png"></media:thumbnail><category term="simulyator-razrabotki" label="Симулятор разработки"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/45/01/450162c0-cd0e-4032-a53d-f991f081f338.jpeg&quot;&gt;Продолжаем вести наш проект и разрабатывать приложение для заметок. В предыдущей части мы определились с требованиями, базовыми прототипами и архитектурой, а так же сделали доску с задачами для нашего проекта.</summary><content type="html">
  &lt;p id=&quot;dXcI&quot;&gt;Продолжаем вести наш проект и разрабатывать приложение для заметок. В &lt;a href=&quot;https://blog.travellerlogs.ru/dev_simulate_notes_1&quot; target=&quot;_blank&quot;&gt;предыдущей части&lt;/a&gt; мы определились с требованиями, базовыми прототипами и архитектурой, а так же сделали доску с задачами для нашего проекта.&lt;/p&gt;
  &lt;p id=&quot;mO8R&quot;&gt;Сегодня нам предстоит спланировать этапы, которые будут отвечать за то, в какой последовательности мы будем что-то разрабатывать или настраивать +  начнем работать с кодом, мы то знаем, что это самая кайфовая часть)&lt;/p&gt;
  &lt;figure id=&quot;hKCr&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/45/01/450162c0-cd0e-4032-a53d-f991f081f338.jpeg&quot; width=&quot;2880&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;OrCX&quot;&gt;Давайте посмотрим на то, как выглядит наша доска с задачами в данный момент:&lt;/p&gt;
  &lt;figure id=&quot;jQsG&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/19/de/19de0217-c9a4-4800-a4e2-20b42fc8a75e.png&quot; width=&quot;1688&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;hhIv&quot;&gt;Задача, которая сформулирована как &amp;quot;Создать каркас приложения&amp;quot; - не особо то понятна, помните, что при виде задачи, вы должны с легкостью себе ответить на вопросы:&lt;/p&gt;
  &lt;ul id=&quot;s4L0&quot;&gt;
    &lt;li id=&quot;GGuB&quot;&gt;&lt;strong&gt;Что именно должно быть сделано в этой задаче?&lt;/strong&gt;&lt;/li&gt;
    &lt;li id=&quot;juwV&quot;&gt;&lt;strong&gt;Как я пойму, что задача завершена?&lt;/strong&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;CAWK&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;XlzQ&quot;&gt;Определяемся, что нужно для старта&lt;/h2&gt;
  &lt;p id=&quot;zItP&quot;&gt;И так, для начала нет смысла смотреть на функциональные требования, которые мы с вами определили в прошлой статье, так как у нас еще нет настроенного окружения, где бы мы могли с вами все разрабатывать, поэтому для начала определим задачи, которые помогут нам получить это окружение.&lt;/p&gt;
  &lt;p id=&quot;OOK0&quot;&gt;Что нужно чтобы сделать фронтовой проект? Ну, давайте подумаем...&lt;/p&gt;
  &lt;ol id=&quot;S1Jq&quot;&gt;
    &lt;li id=&quot;e4WL&quot;&gt;Создать базовый проект и очистить его от всего ненужного (банальный &lt;code&gt;create-react-app&lt;/code&gt;)&lt;/li&gt;
    &lt;li id=&quot;NmTn&quot;&gt;Определиться со стайлингом и настроить автоматическое исправление&lt;/li&gt;
    &lt;li id=&quot;3Op5&quot;&gt;Определиться со структурой папок, чтобы не было хаоса&lt;/li&gt;
    &lt;li id=&quot;HtFJ&quot;&gt;Настроить коннект с &lt;em&gt;git&lt;/em&gt;&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;260S&quot;&gt;Пакеты все пачкой ставить не будем, лучше этим заниматься по мере необходимости!&lt;/p&gt;
  &lt;p id=&quot;71eC&quot;&gt;И так, после подобных раздумий наша доска проекта выглядит уже примерно следующим образом:&lt;/p&gt;
  &lt;figure id=&quot;v65D&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/1e/4e/1e4e4add-fcda-4e2a-9166-31d5f8b04ecd.png&quot; width=&quot;1688&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;0l7J&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;c1GG&quot;&gt;Создаем базовый проект и зачищаем ненужное&lt;/h2&gt;
  &lt;p id=&quot;lQ8y&quot;&gt;Приступаем к первой задаче, просто создадим наше приложение:&lt;/p&gt;
  &lt;pre id=&quot;g4Qi&quot; data-lang=&quot;bash&quot;&gt;yarn create react-app note-app --template typescript&lt;/pre&gt;
  &lt;h3 id=&quot;mhUz&quot;&gt;&lt;/h3&gt;
  &lt;p id=&quot;4QtI&quot;&gt;Чтобы у нас не было ничего лишнего, удалим все из папки &lt;em&gt;src&lt;/em&gt;, кроме&lt;em&gt; index.tsx&lt;/em&gt;, index.css и &lt;em&gt;App.tsx&lt;/em&gt;, причем в &lt;em&gt;index.tsx&lt;/em&gt; оставим только вот это:&lt;/p&gt;
  &lt;pre data-lang=&quot;jsx&quot; id=&quot;f363&quot;&gt;import React from &amp;#x27;react&amp;#x27;;
import ReactDOM from &amp;#x27;react-dom/client&amp;#x27;;
import App from &amp;#x27;./App&amp;#x27;;
import &amp;#x27;./index.css&amp;#x27;;

const root = ReactDOM.createRoot(document.getElementById(&amp;#x27;root&amp;#x27;) as HTMLElement);

root.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
);&lt;/pre&gt;
  &lt;p id=&quot;hwNo&quot;&gt;А в &lt;em&gt;App.tsx&lt;/em&gt; вот это:&lt;/p&gt;
  &lt;pre data-lang=&quot;jsx&quot; id=&quot;TxHb&quot;&gt;import React from &amp;#x27;react&amp;#x27;;

const App = () =&amp;gt; {
  return &amp;lt;div&amp;gt;App&amp;lt;/div&amp;gt;;
};

export default App;&lt;/pre&gt;
  &lt;h3 id=&quot;cgtj&quot;&gt;&lt;/h3&gt;
  &lt;p id=&quot;EO7Q&quot;&gt;А в папке &lt;em&gt;public/ оставим только&lt;/em&gt;&lt;/p&gt;
  &lt;p id=&quot;o8EG&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;WXpi&quot;&gt;Настраиваем eslint&lt;/h2&gt;
  &lt;p id=&quot;eza6&quot;&gt;Не знаю как вам, но мне уже не комфортно работать в проекта, где нет базовой настройки для поддержания чистого код стайла, поэтому давайте супер быстро выполним простую настройку и пойдем дальше!&lt;/p&gt;
  &lt;p id=&quot;zxvB&quot;&gt;Для начала поставим необходимые зависимости для eslint:&lt;/p&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;C4Tb&quot;&gt;yarn add -D eslint-plugin-import @typescript-eslint/parser eslint-import-resolver-typescript&lt;/pre&gt;
  &lt;p id=&quot;0XIj&quot;&gt;После чего произведем инициализацию:&lt;/p&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;5x9o&quot;&gt;npx eslint --init&lt;/pre&gt;
  &lt;p id=&quot;hsXC&quot;&gt;Отвечаем на вопросы в консоли примерно вот так:&lt;/p&gt;
  &lt;blockquote id=&quot;RDNz&quot;&gt;How would you like to use ESLint?&lt;/blockquote&gt;
  &lt;p id=&quot;vrL1&quot;&gt;-&amp;gt; To check syntax and find problems&lt;/p&gt;
  &lt;blockquote id=&quot;k0VB&quot;&gt;What type of modules does your project use?&lt;/blockquote&gt;
  &lt;p id=&quot;z0CU&quot;&gt;-&amp;gt; JavaScript modules (import/export)&lt;/p&gt;
  &lt;blockquote id=&quot;wNUC&quot;&gt;Which framework does your project use?&lt;/blockquote&gt;
  &lt;p id=&quot;ZnWW&quot;&gt;-&amp;gt; React&lt;/p&gt;
  &lt;blockquote id=&quot;oRFW&quot;&gt;Does your project use TypeScript?&lt;/blockquote&gt;
  &lt;p id=&quot;xYRR&quot;&gt;-&amp;gt; Yes&lt;/p&gt;
  &lt;blockquote id=&quot;4dlO&quot;&gt;Where does your code run?&lt;/blockquote&gt;
  &lt;p id=&quot;c6fm&quot;&gt;-&amp;gt; Browser, Node&lt;/p&gt;
  &lt;blockquote id=&quot;BfkU&quot;&gt;What format do you want your config file to be in?&lt;/blockquote&gt;
  &lt;p id=&quot;t7uu&quot;&gt;-&amp;gt; JSON&lt;/p&gt;
  &lt;blockquote id=&quot;6KpX&quot;&gt;Would you like to install them now?&lt;/blockquote&gt;
  &lt;p id=&quot;xnJX&quot;&gt;-&amp;gt; yes&lt;/p&gt;
  &lt;blockquote id=&quot;a3RX&quot;&gt;Which package manager do you want to use?&lt;/blockquote&gt;
  &lt;p id=&quot;6Jmh&quot;&gt;-&amp;gt; yarn&lt;/p&gt;
  &lt;p id=&quot;MaCf&quot;&gt;После этого нужно будет внести некоторые изменения в .eslintrc.json чтобы внести немного своих правил + чтобы у нас не было дальше конфликта с prettier, итоговый файл выглядит вот так:&lt;/p&gt;
  &lt;pre data-lang=&quot;javascript&quot; id=&quot;d8Gm&quot;&gt;{
  &amp;quot;env&amp;quot;: {
    &amp;quot;browser&amp;quot;: true,
    &amp;quot;es2021&amp;quot;: true,
    &amp;quot;node&amp;quot;: true,
    &amp;quot;jest&amp;quot;: true
  },
  &amp;quot;extends&amp;quot;: [
    &amp;quot;eslint:recommended&amp;quot;,
    &amp;quot;plugin:react/recommended&amp;quot;,
    &amp;quot;plugin:@typescript-eslint/recommended&amp;quot;,
    &amp;quot;prettier&amp;quot;
  ],
  &amp;quot;overrides&amp;quot;: [],
  &amp;quot;parser&amp;quot;: &amp;quot;@typescript-eslint/parser&amp;quot;,
  &amp;quot;parserOptions&amp;quot;: {
    &amp;quot;ecmaVersion&amp;quot;: &amp;quot;latest&amp;quot;,
    &amp;quot;sourceType&amp;quot;: &amp;quot;module&amp;quot;
  },
  &amp;quot;plugins&amp;quot;: [
    &amp;quot;react&amp;quot;,
    &amp;quot;react-hooks&amp;quot;,
    &amp;quot;@typescript-eslint&amp;quot;,
    &amp;quot;prettier&amp;quot;
  ],
  &amp;quot;rules&amp;quot;: {
    &amp;quot;react/react-in-jsx-scope&amp;quot;: &amp;quot;off&amp;quot;,
    &amp;quot;spaced-comment&amp;quot;: &amp;quot;error&amp;quot;,
    &amp;quot;quotes&amp;quot;: [&amp;quot;error&amp;quot;, &amp;quot;single&amp;quot;],
    &amp;quot;no-duplicate-imports&amp;quot;: &amp;quot;error&amp;quot;
  },
  &amp;quot;settings&amp;quot;: {
    &amp;quot;import/resolver&amp;quot;: {
      &amp;quot;typescript&amp;quot;: {}
    }
  }
}&lt;/pre&gt;
  &lt;h3 id=&quot;ewc8&quot;&gt;&lt;/h3&gt;
  &lt;h2 id=&quot;HCuP&quot;&gt;Настраиваем prettier&lt;/h2&gt;
  &lt;p id=&quot;y1v3&quot;&gt;Устанавливаем необходимые зависимости:&lt;/p&gt;
  &lt;pre data-lang=&quot;bash&quot; id=&quot;VJdV&quot;&gt;yarn add -D prettier eslint-config-prettier eslint-plugin-prettier eslint-plugin-react-hooks&lt;/pre&gt;
  &lt;p id=&quot;Mc3j&quot;&gt;И создаем файл .prettierrc.json:&lt;/p&gt;
  &lt;pre data-lang=&quot;javascript&quot; id=&quot;V7VZ&quot;&gt;{
  &amp;quot;semi&amp;quot;: true,
  &amp;quot;tabWidth&amp;quot;: 2,
  &amp;quot;printWidth&amp;quot;: 100,
  &amp;quot;singleQuote&amp;quot;: true,
  &amp;quot;trailingComma&amp;quot;: &amp;quot;all&amp;quot;,
  &amp;quot;jsxSingleQuote&amp;quot;: true,
  &amp;quot;bracketSpacing&amp;quot;: true
}&lt;/pre&gt;
  &lt;p id=&quot;bYPc&quot;&gt;И так, на этом настройка утилит закончена, осталось только добавить новые скрипты в package.json:&lt;/p&gt;
  &lt;pre data-lang=&quot;javascript&quot; id=&quot;DSwy&quot;&gt;&amp;quot;lint&amp;quot;: &amp;quot;eslint src/**/*.{js,jsx,ts,tsx,json}&amp;quot;,
&amp;quot;lint:fix&amp;quot;: &amp;quot;eslint --fix &amp;#x27;src/**/*.{js,jsx,ts,tsx,json}&amp;#x27;&amp;quot;,
&amp;quot;format&amp;quot;: &amp;quot;prettier --write &amp;#x27;src/**/*.{js,jsx,ts,tsx,css,md,json}&amp;#x27; --config ./.prettierrc&amp;quot;&lt;/pre&gt;
  &lt;h2 id=&quot;8L1M&quot;&gt;&lt;/h2&gt;
  &lt;h2 id=&quot;qSRk&quot;&gt;Структура папок&lt;/h2&gt;
  &lt;p id=&quot;ol29&quot;&gt;Для крупного приложения сложно с самого начала продумать хорошую структуру хранения кода, но основу заложить стоит, чтобы команда, которая состоит из нескольких разработчиков не писала как кому придет в голову.&lt;/p&gt;
  &lt;p id=&quot;ykC5&quot;&gt;И так, я предлагаю придерживаться в нашем проекте вот такой структуры:&lt;/p&gt;
  &lt;pre id=&quot;dTkr&quot;&gt;-src/
----components/
------App/
--------index.ts
--------component.tsx
--------test.tsx 
------- style.css
------Sidebar/
--------index.ts
--------component.tsx
--------test.tsx 
------- style.css
------...

----hooks/
----context/
----typings/
----configs/

----services/
------Database/
--------index.ts
--------service.ts
--------test.ts&lt;/pre&gt;
  &lt;p id=&quot;MaQt&quot;&gt;&lt;/p&gt;
  &lt;ul id=&quot;mveb&quot;&gt;
    &lt;li id=&quot;04lD&quot;&gt;&lt;code&gt;components/&lt;/code&gt; - для хранения компонент нашего приложения&lt;/li&gt;
    &lt;li id=&quot;J9YQ&quot;&gt;&lt;code&gt;hooks/&lt;/code&gt; - для общих хуков, которые используются в разных местах&lt;/li&gt;
    &lt;li id=&quot;Hh8D&quot;&gt;&lt;code&gt;context/&lt;/code&gt; - для описание различных контекстов приложения&lt;/li&gt;
    &lt;li id=&quot;oOtM&quot;&gt;&lt;code&gt;typings/&lt;/code&gt; - для описание типов в приложении&lt;/li&gt;
    &lt;li id=&quot;50MB&quot;&gt;&lt;code&gt;configs/&lt;/code&gt; - для хранения различных кончиков (например, роутинг)&lt;/li&gt;
    &lt;li id=&quot;0aFt&quot;&gt;&lt;code&gt;services/&lt;/code&gt; - для описание различных утилит, которые пригодятся нам при работе&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;oEpb&quot;&gt;Данная структура, возможно, не является оптимальной, да и для большого проекта скорее всего не подойдет, но скорее всего достаточно хорошо ляжет на наш простой проект с заметками.&lt;/p&gt;
  &lt;p id=&quot;MhVD&quot;&gt;Если у вас есть свои идеи по структуре файлов, то жду ваши комментарии)&lt;/p&gt;
  &lt;p id=&quot;wtYB&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;4jYy&quot;&gt;&lt;strong&gt;Следующая задача - подключение к Git&lt;/strong&gt;, думаю, это достаточно простое действие, так что описывать не буду, гайдов на эту тему очень много...&lt;/p&gt;
  &lt;p id=&quot;9G4R&quot;&gt;Ну а мы, пойдем дальше...&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;wBxq&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;NL6N&quot;&gt;Приступаем к планированию разработки&lt;/h2&gt;
  &lt;p id=&quot;uNOC&quot;&gt;Для начала давайте вспомним формальные требования, которые мы составили в прошлый раз:&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;ipVw&quot;&gt;Необходимо создать приложение Заметки с помощью Reactjs и технологий браузеров.&lt;/p&gt;
    &lt;p id=&quot;agd3&quot;&gt;Возможные действия с заметками:&lt;/p&gt;
    &lt;ul id=&quot;f7oj&quot;&gt;
      &lt;li id=&quot;qlUL&quot;&gt;Создать (нажимаем на кнопку создать, открывается markdown редактор на ввод)&lt;/li&gt;
      &lt;li id=&quot;Rs6J&quot;&gt;Редактировать (чтобы редактировать заметку нужно открыть нужную заметку и нажать на отдельную кнопку для редактирования)&lt;/li&gt;
      &lt;li id=&quot;AD5u&quot;&gt;Удалить (чтобы удалить заметку нужно открыть нужную заметку и нажать на отдельную кнопку для удаления, после чего нужна остерегающая модалка)&lt;/li&gt;
    &lt;/ul&gt;
    &lt;p id=&quot;5fMM&quot;&gt;Сохранение изменений в заметке должно происходить автоматически с внесением этих изменений.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;NIzk&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;3FWr&quot;&gt;Если подумать, то нужно сделать примерно следующие задачи:&lt;/p&gt;
  &lt;ul id=&quot;qlE5&quot;&gt;
    &lt;li id=&quot;sOGk&quot;&gt;Настроить навигацию, чтобы иметь возможность перемещаться между заметками&lt;/li&gt;
    &lt;li id=&quot;0SbD&quot;&gt;Подключить базу данных&lt;/li&gt;
    &lt;li id=&quot;ielc&quot;&gt;Настроить общий контекст&lt;/li&gt;
    &lt;li id=&quot;Jzfz&quot;&gt;Отображение списка существующих заметок&lt;/li&gt;
    &lt;li id=&quot;GNAO&quot;&gt;Открытие текста определенной заметки&lt;/li&gt;
    &lt;li id=&quot;wmaN&quot;&gt;Создание простой текстовой заметки&lt;/li&gt;
    &lt;li id=&quot;Yobz&quot;&gt;Удаления заметки&lt;/li&gt;
    &lt;li id=&quot;xuy1&quot;&gt;Редактирование заметки&lt;/li&gt;
    &lt;li id=&quot;v2b8&quot;&gt;Поиск по списку заметок&lt;/li&gt;
    &lt;li id=&quot;xhoo&quot;&gt;Отображение заметки в виде отрендеренного &lt;em&gt;Markdown&lt;/em&gt;&lt;/li&gt;
    &lt;li id=&quot;jI3t&quot;&gt;Что-то еще?&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;OXiM&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;HCEX&quot;&gt;Возможно, сейчас я что-то упустила, но мы это с вами обнаружим в ходе работы, если что!&lt;br /&gt;&lt;br /&gt;Унесите эти задачи себе на доску проекта, чтобы ничего не потерять!&lt;/p&gt;
  &lt;p id=&quot;Q9a8&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;msnU&quot;&gt;На этой стадии проекта мы сегодня закончим, в следующий раз мы уже приступим к написанию кода!&lt;/p&gt;
  &lt;p id=&quot;msnU&quot;&gt;Если вам интересен такой формат разора работы над проектом, то очень жду ваших реакций и комментариев!&lt;/p&gt;
  &lt;hr /&gt;
  &lt;section&gt;
    &lt;p id=&quot;vLIj&quot;&gt;🤖 Чтобы не пропустить новые уроки подпишись на &lt;a href=&quot;https://t.me/travellerLogs&quot; target=&quot;_blank&quot;&gt;телеграм канал!&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;

</content></entry><entry><id>web_dev_sandbox:dev_simulate_notes_1</id><link rel="alternate" type="text/html" href="https://teletype.in/@web_dev_sandbox/dev_simulate_notes_1?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=web_dev_sandbox"></link><title>Симулятор разработки: приложение для заметок (часть 1)</title><published>2022-10-27T11:52:20.706Z</published><updated>2022-10-27T11:52:20.706Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/ac/b5/acb5c713-1d6c-4c7c-8a94-cfb24f9729d0.png"></media:thumbnail><category term="simulyator-razrabotki" label="Симулятор разработки"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/4a/df/4adfe997-7860-49dd-9e43-e2335fd8c1ba.jpeg&quot;&gt;Раньше я считала, что для создания небольших приложений не особо важно структурировать этапы разработки, но после длительного времени работы над огромными проектами, когда без формальностей и планирования всех шагов не обойтись, я изменила свое мнение.</summary><content type="html">
  &lt;p id=&quot;2yAT&quot;&gt;Раньше я считала, что для создания небольших приложений не особо важно структурировать этапы разработки, но после длительного времени работы над огромными проектами, когда без формальностей и планирования всех шагов не обойтись, я изменила свое мнение.&lt;/p&gt;
  &lt;p id=&quot;m9EQ&quot;&gt;Именно поэтому, для тех у кого еще нет опыта работы над большими проектами, я решила запустить новый вид циклов статей &lt;strong&gt;&amp;quot;Симулятор разработки&amp;quot;&lt;/strong&gt;, чтобы вы могли с головой погрузиться в эту историю!&lt;/p&gt;
  &lt;figure id=&quot;CZJS&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/4a/df/4adfe997-7860-49dd-9e43-e2335fd8c1ba.jpeg&quot; width=&quot;2880&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;xcW1&quot;&gt;И так, первым проектом в данной области будут банальные заметки, но на примере такого простого приложения мы с вами посмотрим не только на то, как это приложение запрогать и какие технологии использовать, но и на следующие штуки:&lt;/p&gt;
  &lt;ul id=&quot;D62f&quot;&gt;
    &lt;li id=&quot;Ncyc&quot;&gt;как формализовать требования&lt;/li&gt;
    &lt;li id=&quot;hvBY&quot;&gt;составить простенький макет&lt;/li&gt;
    &lt;li id=&quot;jzwy&quot;&gt;организовать основу архитектуры приложения&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;4EBY&quot;&gt;Если вам не терпится все же узнать технологии, которые вы в последствии сможете попрактиковать, то вот с чем тут придется поработать:&lt;/p&gt;
  &lt;ul id=&quot;dNpN&quot;&gt;
    &lt;li id=&quot;0ni7&quot;&gt;React Context&lt;/li&gt;
    &lt;li id=&quot;QHNc&quot;&gt;React Router&lt;/li&gt;
    &lt;li id=&quot;j2o7&quot;&gt;Markdown&lt;/li&gt;
    &lt;li id=&quot;COyP&quot;&gt;Dexie.js&lt;/li&gt;
    &lt;li id=&quot;qrrw&quot;&gt;Библиотека компонент Antd&lt;/li&gt;
    &lt;li id=&quot;l5oU&quot;&gt;TypeScript&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;4yum&quot;&gt;Формализуем требования&lt;/h2&gt;
  &lt;p id=&quot;TeA5&quot;&gt;Крайне важно понять что клиент хочет от приложения и сделать это, желательно, в самом начале, чтобы потом не пришлось ничего глобально переделывать.&lt;/p&gt;
  &lt;p id=&quot;j3ha&quot;&gt;Поэтому для начала мы с вами формализуем требования к нашему приложению.&lt;/p&gt;
  &lt;p id=&quot;mYs9&quot;&gt;Если подумать, то для в случае заметок, скорее всего, от заказчика мы бы получили примерно следующую формулировку:&lt;/p&gt;
  &lt;blockquote id=&quot;eyRR&quot;&gt;Необходимо создать приложение Заметки с помощью Reactjs и технологий браузеров. Важно, чтобы можно было создавать заметки через markdown и просматривать их в преобразованном виде.&lt;/blockquote&gt;
  &lt;p id=&quot;HYGV&quot;&gt;Но тут надо покопать глубже, для этого, давайте зададим себе несколько уточняющих вопросов, вот первые, которые пришли в голову:&lt;/p&gt;
  &lt;ul id=&quot;dU0D&quot;&gt;
    &lt;li id=&quot;oKox&quot;&gt;Как должно происходить сохранение заметки&lt;/li&gt;
    &lt;li id=&quot;x9jJ&quot;&gt;Открывается ли при клике на заметку сразу режим редактирования или просто отображения?&lt;/li&gt;
    &lt;li id=&quot;Wu18&quot;&gt;Можно ли удалять заметки? Выводим предупреждения?&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;h0wP&quot;&gt;С учетом того, что сейчас мы сами себе заказчики, то ответив на эти вопросы требования уже звучат куда более точно, согласитесь:&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;4DTH&quot;&gt;Необходимо создать приложение Заметки с помощью Reactjs и технологий браузеров.&lt;/p&gt;
    &lt;p id=&quot;uacy&quot;&gt;Возможные действия с заметками:&lt;/p&gt;
    &lt;ul id=&quot;f7oj&quot;&gt;
      &lt;li id=&quot;7CPR&quot;&gt;Создать (нажимаем на кнопку создать, открывается markdown редактор на ввод)&lt;/li&gt;
      &lt;li id=&quot;Mq32&quot;&gt;Редактировать (чтобы редактировать заметку нужно открыть нужную заметку и нажать на отдельную кнопку для редактирования)&lt;/li&gt;
      &lt;li id=&quot;KhFx&quot;&gt;Удалить (чтобы удалить заметку нужно открыть нужную заметку и нажать на отдельную кнопку для удаления, после чего нужна остерегающая модалка)&lt;/li&gt;
    &lt;/ul&gt;
    &lt;p id=&quot;Qi2c&quot;&gt;Сохранение изменений в заметке должно происходить автоматически с внесением этих изменений.&lt;/p&gt;
  &lt;/section&gt;
  &lt;h2 id=&quot;exnc&quot;&gt;&lt;/h2&gt;
  &lt;h2 id=&quot;AY88&quot;&gt;Составим план&lt;/h2&gt;
  &lt;p id=&quot;PKqN&quot;&gt;Когда вы первый раз попадаете в команду, которая что-то разрабатывает может быть непривычно, что все ведут какие-то задачи и куда-то их записывают, для нашего проекта я буду делать тоже самое, чтобы вы уже сейчас начинали к этому привыкать.&lt;/p&gt;
  &lt;p id=&quot;v5ra&quot;&gt;На данном этапе можно представить нашу доску примерно вот так:&lt;/p&gt;
  &lt;figure id=&quot;7sMZ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/ba/ad/baad6518-8f93-4b04-b828-b3bbebf32b7c.png&quot; width=&quot;1686&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;roef&quot;&gt;Я составляю подобные доску в Notion, но в целом можно и в любом другом инструменте, например, Trello.&lt;/p&gt;
  &lt;p id=&quot;pZdJ&quot;&gt;Если вы хотите тоже делать это в Notion, то можете скопировать себе &lt;a href=&quot;https://www.notion.so/fc7af71b2e0e4a3c8d578cb5d27109e5&quot; target=&quot;_blank&quot;&gt;мой шаблон&lt;/a&gt; и использовать!&lt;/p&gt;
  &lt;p id=&quot;pcPR&quot;&gt;Как видите тут еще нет задач на разработку, но нам уже есть что делать дальше, поэтому не будем останавливаться.&lt;/p&gt;
  &lt;p id=&quot;tcRP&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;wAao&quot;&gt;Прототип внешнего вида&lt;/h2&gt;
  &lt;p id=&quot;ZWbN&quot;&gt;Итак, нам надо определиться как примерно будет выглядеть наше приложение, если пробежаться по формализованным требованиям, то выходит, что приложение состоит из сайдбара, области для просмотра/редактирования заметки, поиска по заметкам и кнопкам создать / редактировать / удалить.&lt;/p&gt;
  &lt;p id=&quot;2nTF&quot;&gt;На словах понять что где сложно, поэтому я быстро набросала примерный макет:&lt;/p&gt;
  &lt;figure id=&quot;kIzm&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/94/27/9427c3f6-4af2-45e7-8ebe-73111cc71bc7.png&quot; width=&quot;1710&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;mppX&quot;&gt;Вроде все основные элементы тут есть, еще осталось разве что модальное окно, которое мы будем показывать при клике на удаление, чтобы подтвердить действие, но думаю его рисовать не будем.&lt;/p&gt;
  &lt;p id=&quot;7OSS&quot;&gt;Если что, то вот какой элемент чем является:&lt;/p&gt;
  &lt;figure id=&quot;HtFU&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/08/53/08532679-5177-4c24-add7-474443efb577.png&quot; width=&quot;1710&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;wZ3x&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;K95B&quot;&gt;Базовая архитектура&lt;/h2&gt;
  &lt;p id=&quot;1vND&quot;&gt;Я тут не буду говорить про структуру папок и именование переменных, я хочу обсудить структуру приложения в целом.&lt;/p&gt;
  &lt;p id=&quot;PtlP&quot;&gt;Чтобы не устраивать ад пропсов (&lt;s&gt;а что если я хочу?&lt;/s&gt;) у нас в приложении мы будем использовать &lt;a href=&quot;https://ru.reactjs.org/docs/context.html&quot; target=&quot;_blank&quot;&gt;React Context&lt;/a&gt;, значит у нас будет что-то вроде основного компонента, который создает нам всю истину общаясь с бд и генерируя нужные колбеки, назовем его, возможно, банально, но &lt;code&gt;App.&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;p5Fs&quot;&gt;Для наглядности буду приводить картинки&lt;/p&gt;
  &lt;figure id=&quot;bIJg&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f1/86/f18633ca-99c4-4d4c-9ec2-d403ad7db88a.png&quot; width=&quot;1710&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;3bM7&quot;&gt;Дальше уже в этом контексте у нас будут существовать другие компоненты, некоторые из них будут &amp;quot;глупыми компонентами&amp;quot;, которые умеют работать только со своими пропсами и ни с чем больше, а другие же поумнее и будут ходить в контекст за нужной информацией.&lt;/p&gt;
  &lt;p id=&quot;NloE&quot;&gt;Не буду углубляться в детали, нам сейчас это не нужно, и приведу следующую картинку, которая сделает наш дальнейший план разработки немного более понятным (желтые - компоненты, которые умеют что-то делать с контексом):&lt;/p&gt;
  &lt;figure id=&quot;Q2gq&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/29/75/2975314b-7218-4367-8ff6-46dca5521653.png&quot; width=&quot;1630&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;gmnv&quot;&gt;И так, после проделанной работы наша доска проекта выглядит примерно вот так&lt;/p&gt;
  &lt;figure id=&quot;d3ow&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e6/fd/e6fd90e5-0da6-4709-a6b0-53d089f0fca9.png&quot; width=&quot;1698&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;msnU&quot;&gt;На этой стадии проекта мы сегодня закончим, в следующий раз создадим каркас и разберемся в какой последовательности нам с вами дальше предстоит выполнять работу!&lt;br /&gt;&lt;br /&gt;Если вам интересен такой формат разора работы над проектом, то очень жду ваших реакций и комментариев!&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;section&gt;
    &lt;p id=&quot;vLIj&quot;&gt;🤖 Чтобы не пропустить новые уроки подпишись на &lt;a href=&quot;https://t.me/travellerLogs&quot; target=&quot;_blank&quot;&gt;телеграм канал!&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;

</content></entry><entry><id>web_dev_sandbox:react_1</id><link rel="alternate" type="text/html" href="https://teletype.in/@web_dev_sandbox/react_1?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=web_dev_sandbox"></link><title>React является декларативным - что это значит?</title><published>2022-10-25T16:31:05.243Z</published><updated>2022-10-25T16:31:05.243Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/7e/fa/7efad26c-bef7-462b-97e4-d92fd0998121.png"></media:thumbnail><category term="react" label="React"></category><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/ab/f7/abf742f8-7dc0-41f9-acad-d235826fe6c4.png&quot;&gt;При изучении React вы, скорее всего не раз слышали, что он является декларативным. Но что означает декларативность и что противоположно декларативности? </summary><content type="html">
  &lt;p id=&quot;JNKk&quot;&gt;При изучении &lt;em&gt;React&lt;/em&gt; вы, скорее всего не раз слышали, что он является декларативным. Но что означает декларативность и что противоположно декларативности? &lt;/p&gt;
  &lt;figure id=&quot;GGj6&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ab/f7/abf742f8-7dc0-41f9-acad-d235826fe6c4.png&quot; width=&quot;1050&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;yR6w&quot;&gt;Декларативный vs императивный&lt;/h2&gt;
  &lt;p id=&quot;zZKw&quot;&gt;Противоположностью декларативности является императивность. Это не специфические для &lt;em&gt;React&lt;/em&gt; термины. Они применимы к программированию в целом.&lt;/p&gt;
  &lt;p id=&quot;E3Vt&quot;&gt;Если кратко, то с точки зрения пользовательских интерфейсов:&lt;/p&gt;
  &lt;ul id=&quot;LzeC&quot;&gt;
    &lt;li id=&quot;beEU&quot;&gt;императивный подход - это когда вы обеспечиваете пошаговую мутацию &lt;strong&gt;DOM&lt;/strong&gt; до достижения желаемого пользовательского интерфейса.&lt;/li&gt;
    &lt;li id=&quot;9uT6&quot;&gt;декларативный подход - это когда вы описываете конечное состояние желаемого пользовательского интерфейса.&lt;br /&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;Y3CS&quot;&gt;Давайте посмотрим на примеры&lt;/h2&gt;
  &lt;p id=&quot;n5j6&quot;&gt;Допустим, нам нужно создать такой пользовательский интерфейс:&lt;/p&gt;
  &lt;figure id=&quot;1DjP&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/5e/65/5e652493-fa1e-428b-a5c0-58b688194500.gif&quot; width=&quot;600&quot; /&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;HSHM&quot;&gt;Императивный подход&lt;/h3&gt;
  &lt;p id=&quot;xOdu&quot;&gt;Вот императивное решение.Для каждого взаимодействия мы предоставляем пошаговые мутации DOM для достижения желаемого состояния пользовательского интерфейса.&lt;/p&gt;
  &lt;pre id=&quot;9i0c&quot; data-lang=&quot;javascript&quot;&gt;const btn = document.querySelector(&amp;#x27;.btn&amp;#x27;);
const container = document.querySelector(&amp;#x27;.container&amp;#x27;);

const listner1 = () =&amp;gt; {
  btn.style.background = &amp;#x27;#DB2777&amp;#x27;;
  btn.innerText = &amp;#x27;Точно?&amp;#x27;;
  btn.removeEventListener(&amp;#x27;click&amp;#x27;, listner1);
  btn.addEventListener(&amp;#x27;click&amp;#x27;, listner2);
}

const listner2 = () =&amp;gt; {
  container.innerText = &amp;#x27;🦄&amp;#x27;;
  btn.style.display = &amp;#x27;none&amp;#x27;;
}

btn.addEventListener(&amp;#x27;click&amp;#x27;, listner1);&lt;/pre&gt;
  &lt;p id=&quot;PPIH&quot;&gt;Вот песочница с примером, чтобы можно было потыкаться:&lt;/p&gt;
  &lt;figure id=&quot;YGYP&quot; class=&quot;m_column&quot;&gt;
    &lt;iframe src=&quot;https://codepen.io/guvictory/embed/mdKdMKr&quot;&gt;&lt;/iframe&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;oooh&quot;&gt;Декларативный подход&lt;/h3&gt;
  &lt;p id=&quot;CbIS&quot;&gt;Вот пример декларативного решения &lt;em&gt;React&lt;/em&gt;.&lt;/p&gt;
  &lt;p id=&quot;ccNZ&quot;&gt;Мы не предоставляем пошаговых инструкций для достижения желаемого пользовательского интерфейса. Вместо этого мы описываем конечный пользовательский интерфейс, который мы хотим получить.&lt;/p&gt;
  &lt;pre id=&quot;ULhN&quot; data-lang=&quot;jsx&quot;&gt;const [scene, setScene] = useState(&amp;#x27;button&amp;#x27;);

if (scene === &amp;#x27;button&amp;#x27;) {
  return (
    &amp;lt;Button
      blue
      onClick={() =&amp;gt; setScene(&amp;#x27;question&amp;#x27;)}
    &amp;gt;
      Покажи единорожку
    &amp;lt;/Button&amp;gt;
  );
}

if (scene === &amp;#x27;question&amp;#x27;) {
  return (
    &amp;lt;Button
      pink
      onClick={() =&amp;gt; setScene(&amp;#x27;unicorn&amp;#x27;)}
    &amp;gt;
      Точно?
    &amp;lt;/Button&amp;gt;
  );
}

if (scene === &amp;#x27;unicorn&amp;#x27;) {
  return &amp;lt;span&amp;gt;🦄&amp;lt;/span&amp;gt;
}&lt;/pre&gt;
  &lt;p id=&quot;9EZO&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;8Clx&quot;&gt;Мы можем структурировать компонент по-другому. Это не делает его менее декларативным.&lt;/p&gt;
  &lt;pre id=&quot;WpQ8&quot; data-lang=&quot;jsx&quot;&gt;const [scene, setScene] = useState(&amp;#x27;button&amp;#x27;);

if (scene === &amp;#x27;button&amp;#x27; || scene === &amp;#x27;question&amp;#x27;) {
  return (
    &amp;lt;Button
      blue={scene === &amp;#x27;button&amp;#x27;}
      pink={scene === &amp;#x27;question&amp;#x27;}
      onClick={() =&amp;gt; setScene(scene === &amp;#x27;button&amp;#x27; ? &amp;#x27;question&amp;#x27; : &amp;#x27;unicorn&amp;#x27;)}
    &amp;gt;
      {scene === &amp;#x27;button&amp;#x27; ? &amp;#x27;Покажи единорожку&amp;#x27; : &amp;#x27;Точно?&amp;#x27;}
    &amp;lt;/Button&amp;gt;
  );
}


if (scene === &amp;#x27;unicorn&amp;#x27;) {
  return &amp;lt;span&amp;gt;🦄&amp;lt;/span&amp;gt;
}&lt;/pre&gt;
  &lt;p id=&quot;aHA3&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;NNsH&quot;&gt;Декларативным этот подход делает то, что мы описываем конечный пользовательский интерфейс для любого данного представления состояния. Это противоположно предоставлению ручных мутаций DOM для перехода между состояниями пользовательского интерфейса (императив).&lt;/p&gt;
  &lt;p id=&quot;Vtqz&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;pRkA&quot;&gt;На этом сегодня все, надеюсь вам это было полезно!&lt;/p&gt;
  &lt;section&gt;
    &lt;p id=&quot;vLIj&quot;&gt;🤖 Чтобы не пропустить новые уроки подпишись на &lt;a href=&quot;https://t.me/travellerLogs&quot; target=&quot;_blank&quot;&gt;телеграм канал!&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;

</content></entry><entry><id>web_dev_sandbox:react_deep_dive_1</id><link rel="alternate" type="text/html" href="https://teletype.in/@web_dev_sandbox/react_deep_dive_1?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=web_dev_sandbox"></link><title>Исследуем код React (часть 1)</title><published>2022-10-09T12:57:55.386Z</published><updated>2022-10-23T17:08:22.170Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/c7/60/c7609d24-fc35-45e7-bc5a-4cf362a19c4a.png"></media:thumbnail><category term="react" label="React"></category><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/24/f4/24f4ed21-c644-428e-a3fd-c293a2967ecf.jpeg&quot;&gt;Я всегда воспринимала React как черный ящик, который берет JSX и выводит что-то на экран, не задумываясь о том, как он это делает.</summary><content type="html">
  &lt;p id=&quot;vXpS&quot;&gt;Я всегда воспринимала &lt;em&gt;React&lt;/em&gt; как черный ящик, который берет &lt;em&gt;JSX&lt;/em&gt; и выводит что-то на экран, не задумываясь о том, как он это делает.&lt;/p&gt;
  &lt;p id=&quot;U8qG&quot;&gt;Конечно, я знаю то-то и то-то о виртуальном DOM и алгоритме свертки и т.д. &lt;em&gt;По крайней мере, в теории.&lt;/em&gt;&lt;/p&gt;
  &lt;p id=&quot;DHUC&quot;&gt;Но только в этом году мое любопытство наконец-то пересилило меня. Я открыла репозиторий &lt;em&gt;React&lt;/em&gt;, но на этот раз с намерением прочитать код....&lt;/p&gt;
  &lt;p id=&quot;wPsn&quot;&gt;Данный цикл статей подойдет не только тем, кто уже давно пользуется React, но и тем, кто только начинает. Понимать как что-то устроено под капотом всегда полезно, тем более что некоторые моменты, которые мы тут разберем не редко встречаются на собеседованиях.&lt;/p&gt;
  &lt;figure id=&quot;CCOZ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/24/f4/24f4ed21-c644-428e-a3fd-c293a2967ecf.jpeg&quot; width=&quot;2880&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;GXUJ&quot;&gt;Прежде чем вы продолжите чтение, я должна отметить, что это не должно быть исчерпывающим обзором того, как &lt;em&gt;React&lt;/em&gt; работает под капотом. На самом деле, некоторые из моих предположений на этот счет, вероятно, окажутся неверными &lt;/p&gt;
  &lt;p id=&quot;fwnd&quot;&gt;В этом цикле статей мы увидим, какие практики и паттерны основная команда &lt;em&gt;React&lt;/em&gt; применила к части программного обеспечения, используемого бесчисленным количеством инженеров. Надеюсь, мы сможем почерпнуть вдохновение из их решений.&lt;/p&gt;
  &lt;p id=&quot;h67j&quot;&gt;Ну что же, давайте начнем!&lt;/p&gt;
  &lt;p id=&quot;dzqN&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;sL2w&quot;&gt;И первое что мы видим... Монорепа&lt;/h2&gt;
  &lt;p id=&quot;U0lz&quot;&gt;Я открыла &lt;a href=&quot;https://github.com/facebook/react&quot; target=&quot;_blank&quot;&gt;репозиторий ректа&lt;/a&gt;, ожидая найти каталог &lt;em&gt;src&lt;/em&gt;. Вместо этого я увидела один каталог с названием &lt;em&gt;packages&lt;/em&gt;, сразу поняв, что передо мной &lt;strong&gt;монорепа&lt;/strong&gt;. &lt;/p&gt;
  &lt;p id=&quot;mAHz&quot;&gt;Если кто в танке, то &lt;strong&gt;монорепа&lt;/strong&gt; - это один репозиторий, в котором хранится несколько различных приложений или библиотек.&lt;/p&gt;
  &lt;p id=&quot;KiHw&quot;&gt;Репозиторий React содержит 30+ пакетов, включая &lt;em&gt;react&lt;/em&gt;, &lt;em&gt;react-dom&lt;/em&gt;, &lt;em&gt;react-server&lt;/em&gt;, &lt;em&gt;react-devtools&lt;/em&gt; и многие другие.&lt;/p&gt;
  &lt;p id=&quot;MLju&quot;&gt;Основное преимущество монорепы - более простая локальная настройка для больших проектов, состоящих из нескольких независимых частей, и лучшая возможность повторного использования кода между ними. Это достигается ценой более сложного развертывания и увеличения общей сложности кодовой базы.&lt;/p&gt;
  &lt;p id=&quot;DH6W&quot;&gt;У меня никогда не было возможности поговорить о своих обидах на монорепы, поэтому я могу воспользоваться этой возможностью. &lt;/p&gt;
  &lt;p id=&quot;yEWU&quot;&gt;За последний год я работала в яндексе, в сервисе, который хранит свой код в огромной фронтовой монорепе. Когда все разделено между репозиториями, вы вынуждены внедрять изменения постепенно и больше думать о дизайне.&lt;/p&gt;
  &lt;p id=&quot;iGmo&quot;&gt;Я обнаружила, что продуктивный рабочий процесс с монорепой сложнее реализовать, потому что ваше локальное окружение отличается от того, которое работает в продакшене. Это выстреливало мне в ногу больше раз, чем я смею признаться.&lt;/p&gt;
  &lt;p id=&quot;WQRN&quot;&gt;Однако это не критика архитектуры &lt;em&gt;React&lt;/em&gt;. Я уверена, что мейнтейнеры разобрались в своих процессах.&lt;/p&gt;
  &lt;p id=&quot;QWWH&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;PrHr&quot;&gt;С чего бы начать?&lt;/h2&gt;
  &lt;p id=&quot;kI8v&quot;&gt;Чтение незнакомого кода вызывает недоумение. Тем более, если вы не знаете никого, кто мог бы вам в этом помочь. Поэтому мы должны начать с чего-то, чтобы понять кодовую базу и опираться на нее, обращая внимание на паттерны, которые мы обнаруживаем по пути.&lt;/p&gt;
  &lt;p id=&quot;gbS5&quot;&gt;Независимо от программного обеспечения, при исследовании новой для меня кодовой базы, я всегда беру один из его публичных &lt;em&gt;API&lt;/em&gt; и начинаю разбираться с него.&lt;/p&gt;
  &lt;p id=&quot;5Bvg&quot;&gt;&lt;strong&gt;Что такое такое публичные API React?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;lzHd&quot;&gt;Например хуки, такие как &lt;code&gt;useState&lt;/code&gt; и &lt;code&gt;useEffect&lt;/code&gt;, являются частью &lt;em&gt;API&lt;/em&gt;. Но, начав с них, мы не сможем понять, что происходит, поскольку у нас не будет контекста того, как работают компоненты или рендеринг.&lt;/p&gt;
  &lt;p id=&quot;BT9n&quot;&gt;Вместо этого мы начнем с одного из публичных методов &lt;em&gt;React&lt;/em&gt;, который вызывается только один раз в каждом приложении.&lt;/p&gt;
  &lt;pre id=&quot;tekb&quot; data-lang=&quot;jsx&quot;&gt;import ReactDOM from &amp;#x27;react-dom&amp;#x27;;

const root = ReactDOM.createRoot(container);
root.render(element);&lt;/pre&gt;
  &lt;p id=&quot;gcX0&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;oGOC&quot;&gt;Это синтаксис для подключения нашего приложения к &lt;em&gt;DOM&lt;/em&gt;, начиная с &lt;strong&gt;React 18&lt;/strong&gt;. Прочитав реализацию этих функций и отследив операции, которые они выполняют, мы можем начать разбираться с кодовой базой.&lt;/p&gt;
  &lt;p id=&quot;q5Th&quot;&gt;Возможно, вы заметили, что функция, которую мы будем изучать, не является частью основной библиотеки. Она является частью &lt;em&gt;react-dom&lt;/em&gt;, которая представляет собой привязку браузера к &lt;em&gt;React&lt;/em&gt;, соединяющую его с &lt;em&gt;DOM&lt;/em&gt;.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;zcHn&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;Jytn&quot;&gt;В ходе этого цикла статей мы с вами разберемся как устроена эта привязка, а так же рассмотрим следующие элементы исходного кода React:&lt;/p&gt;
  &lt;ul id=&quot;zQm0&quot;&gt;
    &lt;li id=&quot;uuIU&quot;&gt;Как происходит подключение к &lt;code&gt;Reconciler&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;hpEa&quot;&gt;Что скрывает в себе &lt;code&gt;Component&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;Rlnz&quot;&gt;Как именно настроено взаимодействие между &lt;code&gt;Renderer&lt;/code&gt; и &lt;code&gt;Reconciler&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;6BF4&quot;&gt;Посмотрим на основные методы &lt;code&gt;Renderer&lt;/code&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;p0SN&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;G5TQ&quot;&gt;На этом сегодня все, надеюсь я вас немного заинтересовала и вы захотите прочитать этот цикл статей полностью!&lt;/p&gt;
  &lt;section&gt;
    &lt;p id=&quot;vLIj&quot;&gt;🤖 Чтобы не пропустить новые уроки подпишись на &lt;a href=&quot;https://t.me/travellerLogs&quot; target=&quot;_blank&quot;&gt;телеграм канал!&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;

</content></entry><entry><id>web_dev_sandbox:ui_ux_tricks_11</id><link rel="alternate" type="text/html" href="https://teletype.in/@web_dev_sandbox/ui_ux_tricks_11?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=web_dev_sandbox"></link><title>React и DOM дерево</title><published>2022-10-08T12:15:07.875Z</published><updated>2022-10-08T12:15:07.875Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/ea/e6/eae6d79a-48a8-4153-89c1-f8e36eed48cb.png"></media:thumbnail><category term="react" label="React"></category><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/3b/60/3b609808-d50e-4285-b1fd-716058bcdc20.png&quot;&gt;Всякий раз, когда я сталкиваюсь с проблемами в работе с React, это происходит потому, что я не очень хорошо понимаю, как он работает на самом деле.</summary><content type="html">
  &lt;p id=&quot;P3o2&quot;&gt;Всякий раз, когда я сталкиваюсь с проблемами в работе с &lt;em&gt;React&lt;/em&gt;, это происходит потому, что я не очень хорошо понимаю, как он работает на самом деле.&lt;/p&gt;
  &lt;p id=&quot;41r1&quot;&gt;Вот краткое объяснение:&lt;/p&gt;
  &lt;figure id=&quot;Kr3R&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3b/60/3b609808-d50e-4285-b1fd-716058bcdc20.png&quot; width=&quot;2024&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;bPrq&quot;&gt;Чтобы понять, как работает React, нам нужно понять проблему, для решения которой он был разработан.&lt;/p&gt;
  &lt;p id=&quot;6dSi&quot;&gt;Представьте, что сейчас 2013 год, и вы хотите заставить баннер появляться, когда пользователь нажимает на кнопку, просто используя JS.&lt;/p&gt;
  &lt;figure id=&quot;4VEb&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/45/ff/45ffa0ef-5557-46dc-a35c-c145e84efcab.png&quot; width=&quot;2024&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;w05H&quot;&gt;Для этого нужно сделать &lt;strong&gt;три&lt;/strong&gt; вещи:&lt;/p&gt;
  &lt;ol id=&quot;8rkO&quot;&gt;
    &lt;li id=&quot;2kZJ&quot;&gt;Отследить событие нажатия на кнопке&lt;/li&gt;
    &lt;li id=&quot;qHoa&quot;&gt;Найти место в &lt;em&gt;DOM&lt;/em&gt;, куда вы хотите добавить баннер&lt;/li&gt;
    &lt;li id=&quot;32Nb&quot;&gt;Создать баннер и обновить &lt;em&gt;DOM&lt;/em&gt; в этот момент&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;UwXM&quot;&gt;И тут есть одна проблема - каждый раз, когда вы обновляете &lt;em&gt;DOM&lt;/em&gt;, это вызывает обновление пользовательского интерфейса, поскольку браузер рисует новую структуру дерева.&lt;/p&gt;
  &lt;p id=&quot;ksGH&quot;&gt;Эти обновления происходят медленно, поэтому их нужно свести к минимуму.&lt;/p&gt;
  &lt;p id=&quot;wRvL&quot;&gt;Но в приложении с большим количеством интерактивности у вас нет контроля над тем, когда и как часто происходят эти перетоки.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;Qzdr&quot;&gt; Два потока событий могут произойти один за другим и на мгновение за&lt;strong&gt;блокировать пользовательский интерфейс&lt;/strong&gt; из-за перерисовок.&lt;/p&gt;
  &lt;/section&gt;
  &lt;figure id=&quot;w83q&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/2f/63/2f631d6b-6d9d-4a2a-ae07-9ccc2d2389ff.png&quot; width=&quot;2024&quot; /&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;Ndzq&quot;&gt;У &lt;em&gt;React&lt;/em&gt; есть классное решение из коробки: он хранит копию &lt;em&gt;DOM&lt;/em&gt; в памяти браузера.&lt;/p&gt;
  &lt;p id=&quot;G6ze&quot;&gt;Это называется виртуальным &lt;em&gt;DOM&lt;/em&gt; и является основой того, что делает &lt;em&gt;React&lt;/em&gt; (относительно) быстрым.&lt;/p&gt;
  &lt;p id=&quot;42x0&quot;&gt;Любые изменения в вашем приложении перехватываются &lt;em&gt;React&lt;/em&gt; и сначала применяются к этому виртуальному &lt;em&gt;DOM&lt;/em&gt;.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;QsWB&quot;&gt;🤖 Эти изменения происходят &lt;strong&gt;быстро&lt;/strong&gt;, потому что они происходят виртуально и не вызывают никаких изменений пользовательского интерфейса.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;f5qJ&quot;&gt;Затем &lt;em&gt;React&lt;/em&gt; сравнивает новую версию &lt;em&gt;DOM&lt;/em&gt; с текущей версией (все еще находящейся в памяти). &lt;/p&gt;
  &lt;figure id=&quot;Cbro&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d8/46/d846050e-cb28-48f3-bfa8-326d9b5acca6.png&quot; width=&quot;1488&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;9wdM&quot;&gt;Этот процесс называется &lt;strong&gt;diffing&lt;/strong&gt;, и он использует целую кучу хитроумных приемов, чтобы определить, что именно изменилось.&lt;/p&gt;
  &lt;p id=&quot;0hTE&quot;&gt;Каждая часть дерева, в которой произошли изменения, помечается как &lt;strong&gt;загрязненная&lt;/strong&gt;, и, как правило, все ее дочерние части тоже.&lt;/p&gt;
  &lt;p id=&quot;nSRl&quot;&gt;Затем все эти изменения собираются вместе и применяются одновременно.&lt;/p&gt;
  &lt;p id=&quot;U8eE&quot;&gt;Прелесть здесь в том, что делаются только необходимые обновления &lt;em&gt;DOM&lt;/em&gt;.&lt;/p&gt;
  &lt;p id=&quot;4qPB&quot;&gt;&lt;strong&gt;Но это не волшебство.&lt;/strong&gt;&lt;br /&gt;Один из подводных камней заключается в том, что вы можете иногда делать вещи, которые непреднамеренно помечают компоненты как грязные, что приводит к ненужному повторному перерисовыванию целых частей дерева.&lt;/p&gt;
  &lt;figure id=&quot;tOrN&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/43/45/4345793f-0d96-4ca7-9618-8b2d7268328f.png&quot; width=&quot;1488&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Wthf&quot;&gt;Это может показаться не очень важным в случае не особо больших компонентов, но помните, что этот процесс создания виртуального &lt;em&gt;DOM&lt;/em&gt; повторно выполняет перерисовку всех ваших компонент.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;Hqc3&quot;&gt; Вызовы функций, объявления переменных, циклы по массивам и т.д. - все это выполняется заново! Это падение производительности со временем превращается в &lt;strong&gt;&amp;quot;смерть от тысячи порезов бумаги&amp;quot;&lt;/strong&gt;.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;fJLi&quot;&gt;Именно поэтому в &lt;em&gt;React&lt;/em&gt; есть такие инструменты, как &lt;code&gt;memo, useMemo, useCallback&lt;/code&gt; - они предоставляют &lt;em&gt;React&lt;/em&gt; больше информации о том, следует ли обновлять определенный компонент или нет. Немного подробнее об этом писала &lt;a href=&quot;https://blog.travellerlogs.ru/ui_ux_tricks_5#kCOW&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt;.&lt;/p&gt;
  &lt;figure id=&quot;UwWD&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/27/91/27910502-1505-42ab-bb78-bad22a233fb3.png&quot; width=&quot;1488&quot; /&gt;
  &lt;/figure&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;pRkA&quot;&gt;На этом сегодня все, надеюсь вам это было полезно!&lt;/p&gt;
  &lt;section&gt;
    &lt;p id=&quot;vLIj&quot;&gt;🤖 Чтобы не пропустить новые уроки подпишись на &lt;a href=&quot;https://t.me/travellerLogs&quot; target=&quot;_blank&quot;&gt;телеграм канал!&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;

</content></entry><entry><id>web_dev_sandbox:threejs_cookbook__lesson_14</id><link rel="alternate" type="text/html" href="https://teletype.in/@web_dev_sandbox/threejs_cookbook__lesson_14?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=web_dev_sandbox"></link><title>Текстуры (часть 3)</title><published>2022-10-05T07:34:10.176Z</published><updated>2022-10-08T10:29:34.045Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/5a/80/5a80f188-5714-49bb-8b60-6e17a0b895a4.png"></media:thumbnail><category term="three-js" label="Three.js"></category><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/aa/88/aa8883d5-8f98-4358-83fb-ba83fb7949fc.jpeg&quot;&gt;В прошлой статье мы разбирали как мы можем модифицировать наши текстуры на объектах. А сейчас мы пройдем последнюю часть про текстуры, освоим фильтрацию, мипмэппинг и оптимизацию!</summary><content type="html">
  &lt;p id=&quot;gApn&quot;&gt;&lt;a href=&quot;/threejs_cookbook__lesson_13&quot;&gt;В прошлой статье&lt;/a&gt; мы разбирали как мы можем &lt;strong&gt;модифицировать&lt;/strong&gt; наши текстуры на объектах. А сейчас мы пройдем последнюю часть про текстуры, освоим фильтрацию, мипмэппинг и оптимизацию!&lt;/p&gt;
  &lt;figure id=&quot;pSXW&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/aa/88/aa8883d5-8f98-4358-83fb-ba83fb7949fc.jpeg&quot; width=&quot;1280&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;tR4Y&quot;&gt;Если вы посмотрите на верхнюю грань куба, когда эта грань почти скрыта, вы увидите очень размытую текстуру.&lt;/p&gt;
  &lt;figure id=&quot;M8RK&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e9/c6/e9c617e7-730e-4b58-85a2-cd913865beff.png&quot; width=&quot;1412&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;v6zy&quot;&gt; Это связано с фильтрацией и мипмаппингом.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;tj4n&quot;&gt;&lt;strong&gt;Mipmapping&lt;/strong&gt; (или &amp;quot;mip mapping&amp;quot; с пробелом) - это техника, которая заключается в создании наполовину меньшей версии текстуры снова и снова, пока не получится текстура 1x1. Все эти варианты текстуры отправляются на GPU, и GPU выбирает наиболее подходящую версию текстуры.&lt;/p&gt;
  &lt;p id=&quot;HONG&quot;&gt;&lt;code&gt;Three.js&lt;/code&gt; и GPU уже обрабатывают все это, и вы можете просто установить, какой алгоритм фильтрации использовать. Существует два типа алгоритмов фильтрации: фильтр минификации и фильтр увеличения.&lt;/p&gt;
  &lt;p id=&quot;rEUE&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;uOFu&quot;&gt;Фильтр минификации&lt;/h2&gt;
  &lt;p id=&quot;AlRc&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;s5Zm&quot;&gt;Фильтр минификации срабатывает, когда пиксели текстуры меньше пикселей рендера. Другими словами, текстура слишком велика для поверхности, которую она покрывает.&lt;/p&gt;
  &lt;p id=&quot;sKQc&quot;&gt;Вы можете изменить фильтр минификации текстуры с помощью свойства &lt;code&gt;minFilter&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;rtjK&quot;&gt;Вот какие значения существуют:&lt;/p&gt;
  &lt;ul id=&quot;B1t4&quot;&gt;
    &lt;li id=&quot;mhKo&quot;&gt;&lt;code&gt;THREE.NearestFilter&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;i7HU&quot;&gt;&lt;code&gt;THREE.LinearFilter&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;6Nmw&quot;&gt;&lt;code&gt;THREE.LinearMipmapNearestFilter&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;NZ5h&quot;&gt;&lt;code&gt;THREE.LinearMipmapLinearFilter&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;JlVS&quot;&gt;&lt;code&gt;THREE.NearestMipmapNearestFilter&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;Ku1b&quot;&gt;&lt;code&gt;THREE.NearestMipmapLinearFilter&lt;/code&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;ZcVx&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;MhLS&quot;&gt;&lt;strong&gt;По умолчанию&lt;/strong&gt; используется фильтр &lt;code&gt;THREE.LinearMipmapLinearFilter&lt;/code&gt;. Если вам не нравится то, как выглядит ваша текстура, попробуйте другие фильтры.&lt;/p&gt;
  &lt;p id=&quot;MJkS&quot;&gt;Мы не будем рассматривать каждый из них, но мы протестируем &lt;code&gt;THREE.LinearFilter&lt;/code&gt;, который дает совсем другой результат:&lt;/p&gt;
  &lt;pre id=&quot;yi4j&quot; data-lang=&quot;javascript&quot;&gt;colorTexture.minFilter = THREE.LinearFilter;&lt;/pre&gt;
  &lt;figure id=&quot;2q7s&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ef/f4/eff46603-d875-4223-86e8-7e9efd941534.png&quot; width=&quot;1412&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;YxSy&quot;&gt;Если вы используете устройство с соотношением пикселей больше единицы, вы не увидите особой разницы. Если нет, расположите камеру так, чтобы это грань куба была почти скрыта, и вы должны получить больше деталей и странных артефактов.&lt;/p&gt;
  &lt;p id=&quot;ujeD&quot;&gt;Артефакты, которые некоторого размытия, называются &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%9C%D1%83%D0%B0%D1%80%D0%BE%D0%B2%D1%8B%D0%B9_%D1%83%D0%B7%D0%BE%D1%80&quot; target=&quot;_blank&quot;&gt;муаровыми узорами&lt;/a&gt;, и обычно их лучше избегать.&lt;/p&gt;
  &lt;p id=&quot;42dA&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;RBkm&quot;&gt;Фильтр увеличения &lt;/h2&gt;
  &lt;p id=&quot;gFFt&quot;&gt;Фильтр увеличения работает так же, как и фильтр уменьшения, но когда пикселей текстуры больше, чем пикселей рендера. Другими словами, текстура слишком мала для поверхности, которую она покрывает.&lt;/p&gt;
  &lt;p id=&quot;pvch&quot;&gt;Вы можете увидеть результат, используя текстуру checkerboard-8x8.png, которая расположена в папке &lt;code&gt;static/textures/&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;gJvw&quot; data-lang=&quot;javascript&quot;&gt;const colorTexture = textureLoader.load(&amp;#x27;/textures/checkerboard-8x8.png&amp;#x27;);&lt;/pre&gt;
  &lt;figure id=&quot;lRII&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/55/0b/550b2039-e125-412e-a28d-c93c18e66dec.png&quot; width=&quot;1412&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;yXGU&quot;&gt;Текстура становится размытой, потому что это &lt;strong&gt;очень маленькая текстура&lt;/strong&gt; на &lt;strong&gt;очень большой поверхности&lt;/strong&gt;.&lt;/p&gt;
  &lt;p id=&quot;gfos&quot;&gt;Хотя вы можете подумать, что это выглядит ужасно, это, вероятно, к лучшему. &lt;/p&gt;
  &lt;p id=&quot;J8LM&quot;&gt;Можно изменить фильтр увеличения текстуры с помощью свойства &lt;code&gt;magFilter&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;tzTa&quot;&gt;Есть только два возможных значения:&lt;/p&gt;
  &lt;ul id=&quot;nTDk&quot;&gt;
    &lt;li id=&quot;eBXh&quot;&gt;&lt;code&gt;THREE.NearestFilter&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;Upqy&quot;&gt;&lt;code&gt;THREE.LinearFilter&lt;/code&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;bp8h&quot;&gt;По умолчанию используется &lt;code&gt;THREE.LinearFilter&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;9Q0O&quot;&gt;Если вы протестируете &lt;code&gt;THREE.NearestFilter&lt;/code&gt;, вы увидите, что базовое изображение сохраняется, и вы получите пикселизированную текстуру:&lt;/p&gt;
  &lt;figure id=&quot;sBaa&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b2/06/b206ebe0-3b5c-46ea-a503-aab5a6393de4.png&quot; width=&quot;1412&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;HK1z&quot;&gt;Это может быть полезно, если вы хотите создать стиль с пиксельными текстурами.&lt;/p&gt;
  &lt;p id=&quot;bqqY&quot;&gt;Вы можете увидеть результат, используя текстуру &lt;code&gt;minecraft.png&lt;/code&gt;, расположенную в папке &lt;code&gt;static/textures/&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;Yc56&quot; data-lang=&quot;javascript&quot;&gt;const colorTexture = textureLoader.load(&amp;#x27;/textures/minecraft.png&amp;#x27;);&lt;/pre&gt;
  &lt;figure id=&quot;DIxX&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/79/5a/795aff8d-e532-45cd-9c25-20a6f37441bd.png&quot; width=&quot;1412&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;SpGP&quot;&gt;И последнее слово обо всех этих фильтрах: &lt;code&gt;THREE.NearestFilter&lt;/code&gt; дешевле других, и вы должны получить лучшие показатели скорости отрисовки при его использовании.&lt;/p&gt;
  &lt;p id=&quot;otIu&quot;&gt;Используйте мипмапы только для свойства &lt;code&gt;minFilter&lt;/code&gt;. Если вы используете &lt;code&gt;THREE.NearestFilter&lt;/code&gt;, вам не нужны мипмапы, и вы можете отключить их с помощью &lt;code&gt;colorTexture.generateMipmaps = false&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;2Vdt&quot; data-lang=&quot;javascript&quot;&gt;colorTexture.generateMipmaps = false;
colorTexture.minFilter = THREE.NearestFilter;&lt;/pre&gt;
  &lt;p id=&quot;BkEz&quot;&gt;Это немного разгрузит графический процессор.&lt;/p&gt;
  &lt;p id=&quot;MMn1&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;H4mp&quot;&gt;Формат и оптимизация текстур&lt;/h2&gt;
  &lt;p id=&quot;CxiA&quot;&gt;При создании текстуры, важно помнить о трех важнейших элементах:&lt;/p&gt;
  &lt;ul id=&quot;01EL&quot;&gt;
    &lt;li id=&quot;u2H3&quot;&gt;Вес&lt;/li&gt;
    &lt;li id=&quot;Rwlz&quot;&gt;Размер (или разрешение)&lt;/li&gt;
    &lt;li id=&quot;Zgpo&quot;&gt;Данные&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h3 id=&quot;y9gZ&quot;&gt;Вес&lt;/h3&gt;
  &lt;p id=&quot;0b5K&quot;&gt;Не забывайте, что пользователям, заходящим на ваш сайт, придется скачивать эти текстуры. Вы можете использовать большинство типов изображений, которые мы используем в Интернете, например .&lt;em&gt;jpg&lt;/em&gt; (сжатие с потерями, но обычно легче) или .&lt;em&gt;png&lt;/em&gt; (сжатие без потерь, но обычно тяжелее).&lt;/p&gt;
  &lt;p id=&quot;Tf1C&quot;&gt;Попробуйте применить обычные методы, чтобы получить приемлемое изображение, но как можно более легкое. Для этого можно воспользоваться утилитами или сервисами для сжатия.&lt;/p&gt;
  &lt;p id=&quot;e0jw&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;BSqs&quot;&gt;Размер&lt;/h3&gt;
  &lt;p id=&quot;hLwf&quot;&gt;Так как каждый пиксель используемых текстур должен храниться на &lt;em&gt;GPU&lt;/em&gt; независимо от веса изображения. А &lt;em&gt;GPU&lt;/em&gt;, как и ваш жесткий диск, имеет ограничения по объему памяти. Это еще хуже, потому что автоматически создаваемый мипмэппинг увеличивает количество пикселей, которые необходимо хранить.&lt;/p&gt;
  &lt;p id=&quot;ytqX&quot;&gt;Старайтесь максимально уменьшить размер ваших изображений.&lt;/p&gt;
  &lt;p id=&quot;kRhq&quot;&gt;Если вы помните, что мы говорили о мипмаппинге, &lt;code&gt;Three.js&lt;/code&gt; будет создавать уменьшенную вдвое версию текстуры несколько раз, пока не получит текстуру 1x1. Поэтому ширина и высота вашей текстуры должны быть кратна 2. Это необходимо для того, чтобы &lt;code&gt;Three.js&lt;/code&gt; мог разделить размер текстуры на 2.&lt;/p&gt;
  &lt;p id=&quot;4FT6&quot;&gt;Некоторые примеры: 512x512, 1024x1024 или 512x2048.&lt;/p&gt;
  &lt;p id=&quot;mrlJ&quot;&gt;512, 1024 и 2048 можно делить на 2, пока не получится 1.&lt;/p&gt;
  &lt;p id=&quot;zkf5&quot;&gt;Если вы используете текстуру с шириной или высотой, отличными от числа, кратного двум, &lt;code&gt;Three.js&lt;/code&gt; попытается растянуть ее до ближайшего числа, кратного 2, что может привести к плохому визуальному результату, и вы также получите предупреждение в консоли.&lt;/p&gt;
  &lt;p id=&quot;MK1X&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;GtwE&quot;&gt;Данные&lt;/h3&gt;
  &lt;p id=&quot;Z0WZ&quot;&gt;Мы еще не рассмотрели подобные примеры, потому что нам нужно сначала пройти другие вещи, но текстуры поддерживают прозрачность. Как вы, возможно, знаете, файлы &lt;em&gt;jpg&lt;/em&gt; не имеют альфа-канала, поэтому вы можете предпочесть использовать &lt;em&gt;png&lt;/em&gt;.&lt;/p&gt;
  &lt;p id=&quot;KKbz&quot;&gt;Или вы можете использовать альфа-карту, как мы увидим в одном из следующих уроков.&lt;/p&gt;
  &lt;h2 id=&quot;ABwW&quot;&gt;Где найти текстуры &lt;br /&gt;&lt;/h2&gt;
  &lt;p id=&quot;qKcw&quot;&gt;К сожалению, всегда трудно найти идеальные текстуры. Существует множество сайтов, но текстуры не всегда подходят, и, возможно, вам придется заплатить.&lt;/p&gt;
  &lt;p id=&quot;cuKh&quot;&gt;Возможно, стоит начать с поиска в Интернете. Вот несколько сайтов, на которых я часто бываю.&lt;/p&gt;
  &lt;ul id=&quot;D6MU&quot;&gt;
    &lt;li id=&quot;Lj9w&quot;&gt;&lt;a href=&quot;http://3dtextures.me/&quot; target=&quot;_blank&quot;&gt;3dtextures.me&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;HxHp&quot;&gt;&lt;a href=&quot;http://arroway-textures.ch/&quot; target=&quot;_blank&quot;&gt;arroway-textures.ch&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;j8TT&quot;&gt;Вы также можете создавать свои собственные текстуры, используя фотографии и 2D-программы, такие как Photoshop, или даже процедурные текстуры с помощью программ, таких как &lt;a href=&quot;https://www.substance3d.com/products/substance-designer/&quot; target=&quot;_blank&quot;&gt;Substance Designer&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;iGli&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;G5TQ&quot;&gt;На этом сегодня все, надеюсь вам это было полезно!&lt;/p&gt;
  &lt;section&gt;
    &lt;p id=&quot;vLIj&quot;&gt;🤖 Чтобы не пропустить новые уроки подпишись на &lt;a href=&quot;https://t.me/travellerLogs&quot; target=&quot;_blank&quot;&gt;телеграм канал!&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;

</content></entry><entry><id>web_dev_sandbox:threejs_cookbook__lesson_13</id><link rel="alternate" type="text/html" href="https://teletype.in/@web_dev_sandbox/threejs_cookbook__lesson_13?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=web_dev_sandbox"></link><title>Текстуры (часть 2)</title><published>2022-10-04T09:22:51.616Z</published><updated>2022-10-04T09:24:48.940Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/38/68/3868e4e9-b173-4765-87a2-3e8f7037ec85.png"></media:thumbnail><category term="three-js" label="Three.js"></category><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/91/e6/91e65b8e-0dd0-4835-8fc8-45ae8b4fbecb.jpeg&quot;&gt;В прошлой статье мы начали разбирать что такое текстуры и как мы можем их добавить в нашем коде. Сегодня мы продолжим тему текстур и научимся их модифицировать!</summary><content type="html">
  &lt;p id=&quot;oalV&quot;&gt;&lt;a href=&quot;https://blog.travellerlogs.ru/threejs_cookbook__lesson_12&quot; target=&quot;_blank&quot;&gt;В прошлой статье&lt;/a&gt; мы начали разбирать что такое текстуры и как мы можем их добавить в нашем коде. Сегодня мы продолжим тему текстур и научимся их модифицировать!&lt;/p&gt;
  &lt;figure id=&quot;p6nE&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/91/e6/91e65b8e-0dd0-4835-8fc8-45ae8b4fbecb.jpeg&quot; width=&quot;1280&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;rBJS&quot;&gt;Как разворачиваются текстуры?&lt;/h2&gt;
  &lt;p id=&quot;ry48&quot;&gt;Если размещение текстуры на кубе вполне логично, то с другими геометриями все может быть немного сложнее.&lt;br /&gt;Давайте попробуем разместить нашу текстуру на другие геометрии:&lt;/p&gt;
  &lt;figure id=&quot;I5hc&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/de/5b/de5b2f4d-d062-429e-a07f-22399b016532.png&quot; width=&quot;1518&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;eH3R&quot;&gt;Как вы можете видеть, текстура растягивается или сжимается различными способами, чтобы покрыть геометрию.&lt;br /&gt;Это называется UV-развёрткой. Вы можете представить это как разворачивание оригами или конфетной обертки, чтобы сделать ее плоской.&lt;/p&gt;
  &lt;p id=&quot;KzMz&quot;&gt;Каждая вершина будет иметь 2D координаты на плоскости (обычно квадратной).&lt;/p&gt;
  &lt;figure id=&quot;T6OF&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c4/bd/c4bded8b-6540-4893-b796-22c67af3c0b1.jpeg&quot; width=&quot;1280&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;1aPA&quot;&gt;Вы можете увидеть эти UV координаты в свойстве &lt;code&gt;geometry.attributes.uv&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;pqPp&quot; data-lang=&quot;javascript&quot;&gt;console.log(geometry.attributes.uv);&lt;/pre&gt;
  &lt;p id=&quot;JtLH&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;l7cl&quot;&gt;Эти UV-координаты генерируются &lt;code&gt;Three.js&lt;/code&gt; при использовании примитивов. Если вы создаете собственную геометрию и хотите наложить на нее текстуру, вам придется указать UV-координаты.&lt;/p&gt;
  &lt;p id=&quot;756E&quot;&gt;&lt;br /&gt;Если вы создаете геометрию с помощью 3D-программы, вам также придется выполнить развертку UV-координат.&lt;/p&gt;
  &lt;figure id=&quot;ZgIZ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c7/f1/c7f1441d-9e17-434a-9381-e13be1966800.png&quot; width=&quot;728&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;aXrP&quot;&gt; Не волнуйтесь, большинство 3D-программ также имеют функцию для обеспечения автоматического разворачивания, которая должна справиться с этой задачей.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;gPsI&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;ESeF&quot;&gt;Преобразование текстур&lt;/h2&gt;
  &lt;p id=&quot;ePQP&quot;&gt;Давайте вернемся к нашему кубу с одной текстурой и посмотрим, какие преобразования мы можем применить к этой текстуре.&lt;/p&gt;
  &lt;p id=&quot;3oEy&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;eErK&quot;&gt;Повтор&lt;/h3&gt;
  &lt;p id=&quot;BzYy&quot;&gt;Вы можете сделать текстуру повторяемой с помощью свойства &lt;code&gt;repeat&lt;/code&gt;, тип этого свойств - &lt;code&gt;Vector2&lt;/code&gt;, что означает, что у него есть свойства &lt;code&gt;x&lt;/code&gt; и &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;l5NW&quot;&gt;Попробуем изменить эти свойства:&lt;/p&gt;
  &lt;pre id=&quot;scDx&quot; data-lang=&quot;javascript&quot;&gt;const colorTexture = textureLoader.load(&amp;#x27;/textures/door/color.jpg&amp;#x27;);
colorTexture.repeat.x = 2;
colorTexture.repeat.y = 2;&lt;/pre&gt;
  &lt;figure id=&quot;6I6p&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/66/d7/66d7f261-1149-48e5-87dd-fd36cc96e754.png&quot; width=&quot;1218&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;90td&quot;&gt;Как видите, текстура не повторяется, но она стала меньше, а последний пиксель кажется супер растянутым.&lt;/p&gt;
  &lt;p id=&quot;kRhz&quot;&gt;Это связано с тем, что текстура по умолчанию не будет повторяться. Чтобы изменить это, необходимо обновить свойства &lt;code&gt;wrapS&lt;/code&gt; и &lt;code&gt;wrapT&lt;/code&gt; с помощью константы &lt;code&gt;THREE.RepeatWrapping&lt;/code&gt;.&lt;/p&gt;
  &lt;ul id=&quot;SJgQ&quot;&gt;
    &lt;li id=&quot;1U3q&quot;&gt;&lt;code&gt;wrapS&lt;/code&gt; для оси &lt;code&gt;x&lt;/code&gt; &lt;/li&gt;
    &lt;li id=&quot;dPA0&quot;&gt;&lt;code&gt;wrapT&lt;/code&gt; для оси &lt;code&gt;y&lt;/code&gt; &lt;/li&gt;
  &lt;/ul&gt;
  &lt;pre id=&quot;60BZ&quot; data-lang=&quot;javascript&quot;&gt;colorTexture.wrapS = THREE.RepeatWrapping;
colorTexture.wrapT = THREE.RepeatWrapping;&lt;/pre&gt;
  &lt;figure id=&quot;4zr4&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/95/04/95041411-ca4e-4abb-a322-a7316744f897.png&quot; width=&quot;1218&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;A24S&quot;&gt;Также можете чередовать направления текстуры с помощью:&lt;/p&gt;
  &lt;pre id=&quot;dhef&quot; data-lang=&quot;javascript&quot;&gt;colorTexture.wrapS = THREE.MirroredRepeatWrapping;
colorTexture.wrapT = THREE.MirroredRepeatWrapping;&lt;/pre&gt;
  &lt;figure id=&quot;kNz0&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ad/a3/ada3cc72-2bb8-496c-a63d-6f5433dea313.png&quot; width=&quot;1218&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ismt&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;CEEd&quot;&gt;Вращение&lt;/h3&gt;
  &lt;p id=&quot;NtWe&quot;&gt;Повернуть текстуру можно с помощью свойства &lt;code&gt;rotation&lt;/code&gt;, которое представляет собой простое число, соответствующее углу в радианах:&lt;/p&gt;
  &lt;pre id=&quot;uid6&quot; data-lang=&quot;javascript&quot;&gt;colorTexture.rotation = Math.PI * 0.25;&lt;/pre&gt;
  &lt;figure id=&quot;Aff8&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/dc/42/dc42ca44-d65d-4407-af89-52c48fb100b5.png&quot; width=&quot;1218&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;qX9t&quot;&gt;Если убрать свойство &lt;code&gt;repeat&lt;/code&gt;, то можно увидеть, что вращение происходит вокруг левого нижнего угла куба:&lt;/p&gt;
  &lt;figure id=&quot;v3eF&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/83/9c/839c59eb-64f2-4857-9ca1-1ddf5513a1da.png&quot; width=&quot;1218&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;r9dN&quot;&gt;На самом деле это нулевые координаты. Если вы хотите изменить точку вращения, вы можете сделать это с помощью свойства &lt;code&gt;center&lt;/code&gt;, которое также является &lt;code&gt;Vector2&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;jspC&quot; data-lang=&quot;javascript&quot;&gt;colorTexture.rotation = Math.PI * 0.25;
colorTexture.center.x = 0.5;
colorTexture.center.y = 0.5;&lt;/pre&gt;
  &lt;p id=&quot;3SXD&quot;&gt;Теперь текстура будет вращаться вокруг центра.&lt;/p&gt;
  &lt;figure id=&quot;prtZ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7b/85/7b8512a5-ad4e-4433-86c0-d64d75bed24a.png&quot; width=&quot;1218&quot; /&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;JqCI&quot;&gt;Смещение &lt;/h3&gt;
  &lt;p id=&quot;nHCz&quot;&gt;Вы можете сместить текстуру с помощью свойства &lt;code&gt;offset&lt;/code&gt;, которое также является &lt;code&gt;Vector2&lt;/code&gt; со свойствами &lt;code&gt;x&lt;/code&gt; и &lt;code&gt;y&lt;/code&gt;. Изменение этих свойств просто сместит UV-координаты:&lt;/p&gt;
  &lt;pre id=&quot;KK1Q&quot; data-lang=&quot;javascript&quot;&gt;colorTexture.offset.x = 0.5;
colorTexture.offset.y = 0.5;&lt;/pre&gt;
  &lt;figure id=&quot;Bodk&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/19/9e/199e8fb0-48c6-4d5f-b268-cc0186161a57.png&quot; width=&quot;1218&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;cgcw&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;G5TQ&quot;&gt;На этом сегодня все, надеюсь вам это было полезно!&lt;/p&gt;
  &lt;section&gt;
    &lt;p id=&quot;vLIj&quot;&gt;🤖 Чтобы не пропустить новые уроки подпишись на &lt;a href=&quot;https://t.me/travellerLogs&quot; target=&quot;_blank&quot;&gt;телеграм канал!&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;section&gt;
    &lt;p id=&quot;PWzK&quot;&gt;🚀 Код для данного урока вы можете &lt;a href=&quot;https://github.com/GuVictory/threejs-cookbook/tree/v0.13&quot; target=&quot;_blank&quot;&gt;найти тут.&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;

</content></entry><entry><id>web_dev_sandbox:threejs_cookbook__lesson_12</id><link rel="alternate" type="text/html" href="https://teletype.in/@web_dev_sandbox/threejs_cookbook__lesson_12?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=web_dev_sandbox"></link><title>Текстуры (часть 1)</title><published>2022-10-02T11:17:02.625Z</published><updated>2022-10-04T09:23:26.675Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/26/85/2685c283-502e-4977-8f13-b7c7758e8b4b.png"></media:thumbnail><category term="three-js" label="Three.js"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/42/8b/428bea8e-cd40-48cf-97fc-7b1b12ced1cc.jpeg&quot;&gt;Вам уже надоел ваш одноцветный куб? Пришло время добавить текстуры!</summary><content type="html">
  &lt;p id=&quot;onfM&quot;&gt;Вам уже надоел ваш одноцветный куб? Пришло время добавить текстуры!&lt;/p&gt;
  &lt;p id=&quot;oVX6&quot;&gt;Но сначала давайте узнаем, что это такое и что мы можем с ними делать.&lt;/p&gt;
  &lt;figure id=&quot;4aU1&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/42/8b/428bea8e-cd40-48cf-97fc-7b1b12ced1cc.jpeg&quot; width=&quot;1280&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;BSM6&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;t7MO&quot;&gt;Что такое текстуры&lt;/h2&gt;
  &lt;p id=&quot;w2d2&quot;&gt;Текстуры - это изображения, которые покрывают поверхность ваших геометрических фигур. Многие типы текстур могут по-разному влиять на внешний вид вашей геометрии. Речь идет не только о цвете.&lt;/p&gt;
  &lt;p id=&quot;r8AE&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;bnZz&quot;&gt;Тут я расскажу про типы текстур, ссылаясь на &lt;a href=&quot;https://3dtextures.me/2019/04/16/door-wood-001/&quot; target=&quot;_blank&quot;&gt;достаточно популярную текстуру двери&lt;/a&gt; от João Paulo.&lt;/p&gt;
  &lt;p id=&quot;8mT3&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;sysR&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/6c/89/6c89ef4b-5832-4f9f-9b61-5e5578c6cc51.png&quot; width=&quot;1110&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;8V2F&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;C6Nl&quot;&gt;Цвет или текстура альбедо&lt;/h2&gt;
  &lt;p id=&quot;3t8G&quot;&gt;Текстура альбедо - самая понятная. Она просто берет только изображение текстуры и применяет их к созданной вами геометрии геометрии.&lt;/p&gt;
  &lt;figure id=&quot;AZl3&quot; class=&quot;m_custom&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f7/aa/f7aa0052-8d7d-47fa-a2b2-6ac8f6484e08.jpeg&quot; width=&quot;436&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;hpwT&quot;&gt;&lt;/h2&gt;
  &lt;h2 id=&quot;Vg6P&quot;&gt;Альфа-текстура&lt;/h2&gt;
  &lt;p id=&quot;Ngpy&quot;&gt;Альфа-текстура - это полутоновое изображение, где белый цвет будет виден, а черный - нет.&lt;/p&gt;
  &lt;figure id=&quot;veKv&quot; class=&quot;m_custom&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e5/2e/e52ec92d-b603-4a1b-a03f-f350900d030a.jpeg&quot; width=&quot;440&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;zXJH&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;mpZ7&quot;&gt;Текстура высоты &lt;/h2&gt;
  &lt;p id=&quot;93Aj&quot;&gt;Текстура высоты - это полутоновое изображение, которое будет перемещать вершины для создания некоторого рельефа. Вам нужно будет добавлять дополнительные подразделы материала, чтобы работать с данной текстурой.&lt;/p&gt;
  &lt;figure id=&quot;y7Ae&quot; class=&quot;m_custom&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ec/1d/ec1d199a-b023-484c-90c3-b2df75ea4081.png&quot; width=&quot;432.00000000000006&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;HwBd&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;HZhD&quot;&gt;Текстура нормалей&lt;/h2&gt;
  &lt;p id=&quot;FYog&quot;&gt;Текстура нормалей добавит мелких деталей. Она не перемещает вершины, но преломляет свет, заставляя думать, что грани поверхности ориентированы по-другому. Такие текстуры очень полезны для добавления деталей с хорошей производительностью.&lt;/p&gt;
  &lt;figure id=&quot;JFAq&quot; class=&quot;m_custom&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/fc/2c/fc2c58c9-61d3-4c18-bdac-d3fddcf6ded5.jpeg&quot; width=&quot;427&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;fI7u&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;caDd&quot;&gt;Ambient occlusion&lt;/h2&gt;
  &lt;p id=&quot;lk77&quot;&gt;Текстура ambient occlusion - это полутоновое изображение, которое будет имитировать тени в щелях поверхности. Хотя она и не является физически точной, она, безусловно, помогает создать контраст.&lt;/p&gt;
  &lt;figure id=&quot;Cvrd&quot; class=&quot;m_custom&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3b/c5/3bc5a4d5-2431-4a5b-8438-5d71a899f0b1.jpeg&quot; width=&quot;431&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;pXE6&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;clta&quot;&gt;Текстура металлизации&lt;/h2&gt;
  &lt;p id=&quot;2P01&quot;&gt;Текстура металлизации - это изображение в сером спектре, которое определяет, какая часть является металлической (белой), а какая неметаллической (черной). Эта информация поможет создать отражение.&lt;/p&gt;
  &lt;figure id=&quot;UcVZ&quot; class=&quot;m_custom&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b5/a2/b5a23570-e422-40cb-a147-4753836bcd6a.jpeg&quot; width=&quot;425.00000000000006&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;mfP0&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;ME5K&quot;&gt;Текстура шероховатости&lt;/h2&gt;
  &lt;p id=&quot;4lXM&quot;&gt;Шероховатость - это изображение в в сером спектре, которое идет вместе с металлизацией, и которое определяет, какая часть шероховатая (белая), а какая гладкая (черная).&lt;/p&gt;
  &lt;p id=&quot;hEVM&quot;&gt;Давайте приведу пример. Тканный шарф очень шершавый, и вы не увидите отражения света на нем, в то время как поверхность воды очень гладкая, и вы можете увидеть отражение света на ней.&lt;/p&gt;
  &lt;p id=&quot;el8k&quot;&gt;Здесь дерево однородное, потому что на нем есть прозрачный слой.&lt;/p&gt;
  &lt;figure id=&quot;ZEF1&quot; class=&quot;m_custom&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/4d/83/4d83e2ac-faee-47e6-83a1-35590c9c6ebf.jpeg&quot; width=&quot;457&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;upsU&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;p0mt&quot;&gt;Отрисовка на основе физических характеристик&lt;/h2&gt;
  &lt;p id=&quot;vRNn&quot;&gt;Эти текстуры (особенно металлизация и шероховатость) соответствуют тому, что называется принципами &lt;strong&gt;PBR&lt;/strong&gt;.&lt;/p&gt;
  &lt;p id=&quot;wVUQ&quot;&gt;&lt;strong&gt;PBR&lt;/strong&gt; расшифровывается как Physically Based Rendering (отрисовка на основе физических характеристик). Этот метод объединяет множество техник, которые направлены на получение реалистичных результатов.&lt;/p&gt;
  &lt;p id=&quot;uC3o&quot;&gt;Хотя существует множество других техник, &lt;strong&gt;PBR&lt;/strong&gt; становится стандартом для реалистичного рендеринга, и многие программы, движки и библиотеки используют его.&lt;/p&gt;
  &lt;p id=&quot;Nzoh&quot;&gt;Сейчас мы просто сосредоточимся на том, как загружать текстуры, как их использовать, какие преобразования мы можем применять и как их оптимизировать. Более подробно о &lt;strong&gt;PBR&lt;/strong&gt; мы поговорим в последующих уроках.&lt;/p&gt;
  &lt;p id=&quot;9c3S&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;aKnp&quot;&gt;Как загружать текстуры&lt;/h2&gt;
  &lt;h3 id=&quot;OAv4&quot;&gt;Получение URL изображения&lt;/h3&gt;
  &lt;p id=&quot;OMTI&quot;&gt;Чтобы загрузить текстуру, нам нужен URL-адрес файла изображения.&lt;/p&gt;
  &lt;p id=&quot;pQ7E&quot;&gt;Поскольку мы используем Webpack, есть два способа получить его.&lt;/p&gt;
  &lt;p id=&quot;fsl0&quot;&gt;Можно поместить текстуру изображения в папку &lt;code&gt;/src/&lt;/code&gt; и импортировать ее, как мы импортировали бы зависимость JavaScript:&lt;/p&gt;
  &lt;pre id=&quot;JzQ7&quot; data-lang=&quot;javascript&quot;&gt;import imageSource from &amp;#x27;./image.png&amp;#x27;;

console.log(imageSource);&lt;/pre&gt;
  &lt;p id=&quot;48qO&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;Zl6e&quot;&gt;Или можно поместить это изображение в папку &lt;code&gt;/static/&lt;/code&gt; и получить к нему доступ, просто добавив путь к изображению (без &lt;code&gt;/static&lt;/code&gt;) в &lt;code&gt;URL&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;jhKH&quot; data-lang=&quot;javascript&quot;&gt;const imageSource = &amp;#x27;/image.png&amp;#x27;;

console.log(imageSource);&lt;/pre&gt;
  &lt;p id=&quot;4VH3&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;3bq9&quot;&gt; Будьте внимательны, эта папка &lt;code&gt;/static/&lt;/code&gt; работает только благодаря конфигурации шаблона &lt;code&gt;Webpack&lt;/code&gt;. Если вы используете другие типы бандлеров, вам, возможно, придется адаптировать свой проект.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;gDNY&quot;&gt;Мы будем использовать папку &lt;code&gt;/static/&lt;/code&gt; до конца курса.&lt;/p&gt;
  &lt;p id=&quot;n1d6&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;3vqV&quot;&gt;Загружаем изображение&lt;/h2&gt;
  &lt;p id=&quot;IGGa&quot;&gt;Текстуры дверей, которые мы только что видели, &lt;a href=&quot;https://github.com/GuVictory/threejs-cookbook/tree/v0.12&quot; target=&quot;_blank&quot;&gt;можно найти в репозитории проекта&lt;/a&gt; в папке &lt;code&gt;/static/textures&lt;/code&gt;, и существует несколько способов их загрузки.&lt;/p&gt;
  &lt;h3 id=&quot;FhlB&quot;&gt;Используем нативный JavaScript&lt;/h3&gt;
  &lt;p id=&quot;cIWi&quot;&gt;В &lt;code&gt;JavaScript&lt;/code&gt; сначала нужно создать объект класса &lt;code&gt;Image&lt;/code&gt;, прослушать событие &lt;code&gt;load&lt;/code&gt;, а затем изменить его свойство &lt;code&gt;src&lt;/code&gt;, чтобы начать загрузку изображения:&lt;/p&gt;
  &lt;pre id=&quot;jSy1&quot; data-lang=&quot;javascript&quot;&gt;const image = new Image();

image.onload = () =&amp;gt; {
    console.log(&amp;#x27;image loaded&amp;#x27;);
};

image.src = &amp;#x27;/textures/door/color.jpg&amp;#x27;;&lt;/pre&gt;
  &lt;p id=&quot;VI8y&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;q8OL&quot;&gt;Мы не можем использовать это изображение напрямую. Сначала нам нужно создать текстуру из этого изображения.&lt;/p&gt;
  &lt;p id=&quot;yiSr&quot;&gt;Это связано с тем, что &lt;strong&gt;WebGL&lt;/strong&gt; нужен очень специфический формат, понятный &lt;strong&gt;GPU&lt;/strong&gt;, а также с тем, что к текстурам будут применены некоторые изменения, например, &lt;strong&gt;mipmapping&lt;/strong&gt;, но об этом мы узнаем чуть позже.&lt;/p&gt;
  &lt;p id=&quot;reQB&quot;&gt;Создайте текстуру с помощью класса &lt;a href=&quot;https://threejs.org/docs/#api/en/textures/Texture&quot; target=&quot;_blank&quot;&gt;Texture&lt;/a&gt;:&lt;/p&gt;
  &lt;pre id=&quot;QHvi&quot; data-lang=&quot;javascript&quot;&gt;const image = new Image();

image.addEventListener(&amp;#x27;load&amp;#x27;, () =&amp;gt; {
    const texture = new THREE.Texture(image);
});

image.src = &amp;#x27;/textures/door/color.jpg&amp;#x27;;&lt;/pre&gt;
  &lt;p id=&quot;FDgb&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;704I&quot;&gt;Теперь нам нужно использовать эту текстуру в материале. К сожалению, переменная &lt;code&gt;texture&lt;/code&gt; была объявлена в функции, и мы не можем получить к ней доступ вне этой функции. Это ограничение &lt;code&gt;JavaScript&lt;/code&gt;, называемое областью видимости.&lt;/p&gt;
  &lt;p id=&quot;y7gO&quot;&gt;Мы могли бы создать наш куб внутри функции, но есть лучшее решение, заключающееся в создании текстуры вне функции и последующем ее обновлении после загрузки изображения путем установки свойства &lt;code&gt;needsUpdate&lt;/code&gt; в &lt;code&gt;true&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;f9v8&quot; data-lang=&quot;javascript&quot;&gt;const image = new Image();
const texture = new THREE.Texture(image);

image.addEventListener(&amp;#x27;load&amp;#x27;, () =&amp;gt; {
    texture.needsUpdate = true;
});

image.src = &amp;#x27;/textures/door/color.jpg&amp;#x27;;&lt;/pre&gt;
  &lt;p id=&quot;Oq1d&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;dmfo&quot;&gt;Делая это, вы можете сразу же использовать переменную &lt;code&gt;texture&lt;/code&gt;, и изображение будет прозрачным, пока оно не загрузится.&lt;/p&gt;
  &lt;p id=&quot;c9WT&quot;&gt;Чтобы увидеть текстуру на кубе, замените свойство &lt;code&gt;color&lt;/code&gt; на &lt;code&gt;map&lt;/code&gt; и используйте &lt;code&gt;texture&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;6FZW&quot; data-lang=&quot;javascript&quot;&gt;const material = new THREE.MeshBasicMaterial({ map: texture });&lt;/pre&gt;
  &lt;p id=&quot;ElvY&quot;&gt;Вы должны увидеть текстуру двери на каждой стороне вашего куба:&lt;/p&gt;
  &lt;figure id=&quot;IUA4&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/13/2a/132a0278-ac14-4e08-9b8b-9566f37823ba.png&quot; width=&quot;1110&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;BUoX&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;0pdx&quot;&gt;Используя TextureLoader&lt;/h3&gt;
  &lt;p id=&quot;5CCI&quot;&gt;Нативная загрузка JavaScript не так сложна, но есть еще более простой способ с &lt;a href=&quot;https://threejs.org/docs/index.html#api/en/loaders/TextureLoader&quot; target=&quot;_blank&quot;&gt;TextureLoader&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;Coh5&quot;&gt;Создайте переменную класса &lt;a href=&quot;https://threejs.org/docs/index.html#api/en/loaders/TextureLoader&quot; target=&quot;_blank&quot;&gt;TextureLoader&lt;/a&gt; и используйте его метод &lt;code&gt;.load(...)&lt;/code&gt; для создания текстуры:&lt;/p&gt;
  &lt;pre id=&quot;GrLl&quot; data-lang=&quot;javascript&quot;&gt;const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load(&amp;#x27;/textures/door/color.jpg&amp;#x27;);&lt;/pre&gt;
  &lt;p id=&quot;4wOG&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;ZbcU&quot;&gt;Под капотом &lt;strong&gt;Three.js&lt;/strong&gt; будет делать то же, что и мы делали раньше - загружать изображение и обновлять текстуру, когда она будет готова.&lt;/p&gt;
  &lt;p id=&quot;f23d&quot;&gt;Вы можете загрузить столько текстур, сколько хотите, используя только один объект &lt;a href=&quot;https://threejs.org/docs/index.html#api/en/loaders/TextureLoader&quot; target=&quot;_blank&quot;&gt;TextureLoader&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;OjBd&quot;&gt;Можно прокинуть три колбека в метод &lt;code&gt;.load(...)&lt;/code&gt;  после строки, которая описывает путь до файла. Эти методы будут вызываться при следующих событиях:&lt;/p&gt;
  &lt;ul id=&quot;AgUM&quot;&gt;
    &lt;li id=&quot;AUOz&quot;&gt;&lt;code&gt;load&lt;/code&gt; при успешной загрузке изображения&lt;/li&gt;
    &lt;li id=&quot;nopv&quot;&gt;&lt;code&gt;progress&lt;/code&gt;, если загрузка идет успешно&lt;/li&gt;
    &lt;li id=&quot;UUO7&quot;&gt;&lt;code&gt;error&lt;/code&gt;, если что-то пошло не так&lt;/li&gt;
  &lt;/ul&gt;
  &lt;pre id=&quot;G3yP&quot; data-lang=&quot;javascript&quot;&gt;const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load(
    &amp;#x27;/textures/door/color.jpg&amp;#x27;,
    () =&amp;gt; {
        console.log(&amp;#x27;loading finished&amp;#x27;);
    },
    () =&amp;gt; {
        console.log(&amp;#x27;loading progressing&amp;#x27;);
    },
    () =&amp;gt; {
        console.log(&amp;#x27;loading error&amp;#x27;);
    }
);&lt;/pre&gt;
  &lt;p id=&quot;E5CM&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;eB69&quot;&gt;Если текстура не работает, может быть полезно добавить эти колбеки, чтобы увидеть, что происходит, и выявить ошибки.&lt;/p&gt;
  &lt;p id=&quot;g7mn&quot;&gt;&lt;/p&gt;
  &lt;h3 id=&quot;Whli&quot;&gt;Используя LoadingManager&lt;/h3&gt;
  &lt;p id=&quot;bWvx&quot;&gt;Наконец, если у вас есть несколько изображений для загрузки и вы хотите взаимно распределить события, например, получить уведомление, когда все изображения загружены, вы можете использовать &lt;a href=&quot;https://threejs.org/docs/index.html#api/en/loaders/managers/LoadingManager&quot; target=&quot;_blank&quot;&gt;LoadingManager&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;FaxR&quot;&gt;Создайте экземпляр класса &lt;a href=&quot;https://threejs.org/docs/index.html#api/en/loaders/managers/LoadingManager&quot; target=&quot;_blank&quot;&gt;LoadingManager&lt;/a&gt; и передайте его в &lt;a href=&quot;https://threejs.org/docs/index.html#api/en/loaders/TextureLoader&quot; target=&quot;_blank&quot;&gt;TextureLoader&lt;/a&gt;:&lt;/p&gt;
  &lt;pre id=&quot;epVt&quot; data-lang=&quot;javascript&quot;&gt;const loadingManager = new THREE.LoadingManager();
const textureLoader = new THREE.TextureLoader(loadingManager);&lt;/pre&gt;
  &lt;p id=&quot;kvK6&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;4amP&quot;&gt;Можно прослушивать различные события, заменив следующие свойства своими собственными функциями &lt;code&gt;onStart&lt;/code&gt;, &lt;code&gt;onLoad&lt;/code&gt;, &lt;code&gt;onProgress&lt;/code&gt; и &lt;code&gt;onError&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;OA7t&quot; data-lang=&quot;javascript&quot;&gt;const loadingManager = new THREE.LoadingManager();

loadingManager.onStart = () =&amp;gt; {
    console.log(&amp;#x27;loading started&amp;#x27;);
};

loadingManager.onLoad = () =&amp;gt; {
    console.log(&amp;#x27;loading finished&amp;#x27;);
};

loadingManager.onProgress = () =&amp;gt; {
    console.log(&amp;#x27;loading progressing&amp;#x27;);
};

loadingManager.onError = () =&amp;gt; {
    console.log(&amp;#x27;loading error&amp;#x27;);
};

const textureLoader = new THREE.TextureLoader(loadingManager);&lt;/pre&gt;
  &lt;p id=&quot;pqqo&quot;&gt;Потом вы можете начать загрузку всех необходимых изображений:&lt;/p&gt;
  &lt;pre id=&quot;L3CD&quot; data-lang=&quot;javascript&quot;&gt;// ...
const colorTexture = textureLoader.load(&amp;#x27;/textures/door/color.jpg&amp;#x27;);
const alphaTexture = textureLoader.load(&amp;#x27;/textures/door/alpha.jpg&amp;#x27;);
const heightTexture = textureLoader.load(&amp;#x27;/textures/door/height.jpg&amp;#x27;);
const normalTexture = textureLoader.load(&amp;#x27;/textures/door/normal.jpg&amp;#x27;);
// ...&lt;/pre&gt;
  &lt;p id=&quot;O2TJ&quot;&gt;Как вы можете видеть здесь, мы переименовали переменную &lt;code&gt;texture&lt;/code&gt; в &lt;code&gt;colorTexture&lt;/code&gt;, поэтому не забудьте изменить ее и в материале:&lt;/p&gt;
  &lt;pre id=&quot;OFkM&quot; data-lang=&quot;javascript&quot;&gt;const material = new THREE.MeshBasicMaterial({ map: colorTexture });&lt;/pre&gt;
  &lt;p id=&quot;K9YB&quot;&gt;&lt;a href=&quot;https://threejs.org/docs/index.html#api/en/loaders/managers/LoadingManager&quot; target=&quot;_blank&quot;&gt;LoadingManager&lt;/a&gt; очень полезен, если вы хотите показать загрузчик и скрыть его только тогда, когда вся статика загружена. Как мы увидим в одном из следующих уроков, его можно использовать и с другими типами загрузчиков.&lt;/p&gt;
  &lt;p id=&quot;dda3&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;JqCI&quot;&gt;На этом сегодня все, надеюсь вам это было полезно!&lt;/p&gt;
  &lt;section&gt;
    &lt;p id=&quot;vLIj&quot;&gt;🤖 Чтобы не пропустить новые уроки подпишись на &lt;a href=&quot;https://t.me/travellerLogs&quot; target=&quot;_blank&quot;&gt;телеграм канал!&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;section&gt;
    &lt;p id=&quot;PWzK&quot;&gt;🚀 Код для данного урока вы можете &lt;a href=&quot;https://github.com/GuVictory/threejs-cookbook/tree/v0.12&quot; target=&quot;_blank&quot;&gt;найти тут.&lt;/a&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;l4au&quot; data-align=&quot;right&quot;&gt;&lt;a href=&quot;https://blog.travellerlogs.ru/threejs_cookbook__lesson_13&quot; target=&quot;_blank&quot;&gt;Текстуры (часть 2) -&amp;gt;&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>web_dev_sandbox:threejs_cookbook__lesson_4</id><link rel="alternate" type="text/html" href="https://teletype.in/@web_dev_sandbox/threejs_cookbook__lesson_4?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=web_dev_sandbox"></link><title>Трансформация объектов (часть 1)</title><published>2022-09-27T17:57:27.372Z</published><updated>2022-10-04T08:02:50.730Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/81/96/81966e35-0f59-44b3-aaac-97278f91337b.png"></media:thumbnail><category term="three-js" label="Three.js"></category><tt:hashtag>javascript</tt:hashtag><tt:hashtag>three_js</tt:hashtag><tt:hashtag>3d_графика</tt:hashtag><tt:hashtag>анимация</tt:hashtag><tt:hashtag>программирование</tt:hashtag><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/33/a4/33a4bae0-379c-4e41-8171-d3935d104faa.jpeg&quot;&gt;Перед тем как начать</summary><content type="html">
  &lt;section style=&quot;background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;UgzA&quot;&gt;&lt;strong&gt;Перед тем как начать&lt;/strong&gt;&lt;/p&gt;
    &lt;p id=&quot;03e1&quot;&gt;&lt;a href=&quot;https://blog.travellerlogs.ru/threejs_cookbook__lesson_3&quot; target=&quot;_blank&quot;&gt;В предыдущем уроке&lt;/a&gt; мы настроили полноценную сборку проекта с &lt;em&gt;three.js&lt;/em&gt; при помощи &lt;em&gt;webpack&lt;/em&gt;, если вы это пропустили, то советую вернуться!&lt;/p&gt;
  &lt;/section&gt;
  &lt;figure id=&quot;A5Xd&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/33/a4/33a4bae0-379c-4e41-8171-d3935d104faa.jpeg&quot; width=&quot;1280&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;SMsf&quot;&gt;Теперь, когда у нас все готово, мы можем изучить функциональные возможности three.js. Сегодня мы рассмотрим как перемещать и масштабировать объекты...&lt;/p&gt;
  &lt;p id=&quot;FBSe&quot;&gt;Перед анимацией нашей сцены нам необходимо знать, как трансформировать объекты в нашей сцене. Мы уже сделали это с камерой, переместив ее назад с помощью строчки &lt;em&gt;camera.position.z = 3&lt;/em&gt;.&lt;/p&gt;
  &lt;p id=&quot;NQcO&quot;&gt;Существует 4 свойства для преобразования объектов в нашей сцене:&lt;/p&gt;
  &lt;ul id=&quot;RCPE&quot;&gt;
    &lt;li id=&quot;UWbT&quot;&gt;&lt;em&gt;position&lt;/em&gt; (для перемещения)&lt;/li&gt;
    &lt;li id=&quot;QYde&quot;&gt;&lt;em&gt;scale&lt;/em&gt; (для изменения размера)&lt;/li&gt;
    &lt;li id=&quot;ZpSc&quot;&gt;&lt;em&gt;rotation&lt;/em&gt; (для вращения)&lt;/li&gt;
    &lt;li id=&quot;2siY&quot;&gt;&lt;em&gt;quaternion&lt;/em&gt; (тоже для вращения, но об этом позже 😏)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;ZPPx&quot;&gt;Все классы, которые наследуются от класса &lt;a href=&quot;https://threejs.org/docs/#api/en/core/Object3D&quot; target=&quot;_blank&quot;&gt;Object3D&lt;/a&gt;, обладают такими свойствами, как &lt;a href=&quot;https://threejs.org/docs/#api/en/cameras/PerspectiveCamera&quot; target=&quot;_blank&quot;&gt;PerspectiveCamera&lt;/a&gt; или &lt;a href=&quot;https://threejs.org/docs/#api/en/objects/Mesh&quot; target=&quot;_blank&quot;&gt;Mesh&lt;/a&gt;, а также классы, которые мы еще не рассматривали.&lt;/p&gt;
  &lt;p id=&quot;yHPo&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;pm6z&quot;&gt;Подготовка&lt;/h2&gt;
  &lt;p id=&quot;KUtN&quot;&gt;Если у вас нет кода всего проекта, то вы можете найти его в &lt;a href=&quot;https://github.com/GuVictory/threejs-cookbook/tree/v0.4&quot; target=&quot;_blank&quot;&gt;репозитории&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;Epuo&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;xqCy&quot;&gt;Перемещение объектов&lt;/h2&gt;
  &lt;p id=&quot;gqbL&quot;&gt;&lt;em&gt;position &lt;/em&gt;обладает тремя основными свойствами-&lt;em&gt; x, y &lt;/em&gt;и&lt;em&gt; z. &lt;/em&gt;Это свойства необходимы для позиционирования чего-либо в трехмерном пространстве.&lt;/p&gt;
  &lt;p id=&quot;5aHa&quot;&gt;Направление каждой оси является произвольным, и может меняться в зависимости от окружающей среды. В &lt;em&gt;three.js&lt;/em&gt; обычно считают, что ось &lt;em&gt;y&lt;/em&gt;направлена вверх, ось &lt;em&gt;z&lt;/em&gt; - назад, а ось &lt;em&gt;x&lt;/em&gt; - вправо.&lt;/p&gt;
  &lt;p id=&quot;kssZ&quot;&gt;Что касается масштаба единицы измерения, то это зависит от вас. Это может быть 1 сантиметр, 1 метр или даже 1 километр. Я рекомендую вам адаптировать единицу к тому, что вы хотите построить.&lt;/p&gt;
  &lt;p id=&quot;XM4d&quot;&gt;Например, если вы собираетесь создать дом, то, вероятно, вам следует считать, что 1 единица - это 1 метр.&lt;/p&gt;
  &lt;p id=&quot;ouPQ&quot;&gt;Давайте переместим наш куб:&lt;/p&gt;
  &lt;pre id=&quot;X2tO&quot; data-lang=&quot;javascript&quot;&gt;mesh.position.x = -1;
mesh.position.y = -0.8;
mesh.position.z = 0.4;&lt;/pre&gt;
  &lt;p id=&quot;jth4&quot;&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;8AS5&quot;&gt;🤖 Обязательно меняйте положение куба до вызова метода &lt;em&gt;render(...)&lt;/em&gt;, иначе вы отрендерите сетку до ее перемещения.&lt;/p&gt;
  &lt;/section&gt;
  &lt;figure id=&quot;y78n&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e1/d8/e1d800eb-b4d0-4518-bd97-daf029f2392d.png&quot; width=&quot;1184&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ohjY&quot;&gt;Вы можете поиграть со свойством position и попытаться угадать, куда попадет куб (старайтесь, чтобы он находился на экране).&lt;/p&gt;
  &lt;p id=&quot;UDTr&quot;&gt;Свойство &lt;em&gt;position&lt;/em&gt; - это экземпляр класса &lt;a href=&quot;https://threejs.org/docs/#api/en/math/Vector3&quot; target=&quot;_blank&quot;&gt;Vector3&lt;/a&gt;. Этот класс имеет не только свойства &lt;em&gt;x&lt;/em&gt;, &lt;em&gt;y&lt;/em&gt; и &lt;em&gt;z&lt;/em&gt;, но еще и множество полезных методов.&lt;/p&gt;
  &lt;p id=&quot;Frby&quot;&gt;Вы можете получить длину вектора:&lt;/p&gt;
  &lt;pre id=&quot;qUKI&quot; data-lang=&quot;javascript&quot;&gt;console.log(mesh.position.length());&lt;/pre&gt;
  &lt;p id=&quot;2opR&quot;&gt;Вы можете получить расстояние от другого &lt;a href=&quot;https://threejs.org/docs/#api/en/math/Vector3&quot; target=&quot;_blank&quot;&gt;Vector3&lt;/a&gt; (убедитесь, что используете этот код после создания камеры):&lt;/p&gt;
  &lt;pre id=&quot;SpOM&quot; data-lang=&quot;javascript&quot;&gt;console.log(mesh.position.distanceTo(camera.position));&lt;/pre&gt;
  &lt;p id=&quot;7liG&quot;&gt;Можно нормализовать значение вектора (это означает, что вы уменьшите длину вектора до 1 единицы, но сохраните его направление):&lt;/p&gt;
  &lt;pre id=&quot;oRG7&quot; data-lang=&quot;javascript&quot;&gt;console.log(mesh.position.normalize());&lt;/pre&gt;
  &lt;p id=&quot;SGf4&quot;&gt;Для перемещения объекта, вместо того чтобы изменять &lt;em&gt;x&lt;/em&gt;, &lt;em&gt;y&lt;/em&gt; и &lt;em&gt;z&lt;/em&gt; по отдельности, можно также использовать метод &lt;em&gt;set(...)&lt;/em&gt;:&lt;/p&gt;
  &lt;pre id=&quot;5VRy&quot; data-lang=&quot;javascript&quot;&gt;mesh.position.set(-1, -0.8, 0.4);&lt;/pre&gt;
  &lt;p id=&quot;UnoI&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;Yaww&quot;&gt;Добавляем визуализацию осей&lt;/h2&gt;
  &lt;p id=&quot;sZ61&quot;&gt;Прежде чем мы продолжим, хочу отметить, что знать, куда направлена каждая ось, сложно, особенно когда мы начинаем перемещать камеру.&lt;/p&gt;
  &lt;p id=&quot;hRii&quot;&gt;Одним из хороших решений является использование &lt;em&gt;three.js&lt;/em&gt; &lt;a href=&quot;https://threejs.org/docs/#api/en/helpers/AxesHelper&quot; target=&quot;_blank&quot;&gt;AxesHelper&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;aPyj&quot;&gt;&lt;a href=&quot;https://threejs.org/docs/#api/en/helpers/AxesHelper&quot; target=&quot;_blank&quot;&gt;AxesHelper&lt;/a&gt; отобразит 3 линии, соответствующие осям &lt;em&gt;x&lt;/em&gt;, &lt;em&gt;y&lt;/em&gt; и &lt;em&gt;z&lt;/em&gt;, каждая из которых начинается в центре сцены и идет в соответствующем направлении.&lt;/p&gt;
  &lt;p id=&quot;TEI1&quot;&gt;Чтобы создать &lt;a href=&quot;https://threejs.org/docs/#api/en/helpers/AxesHelper&quot; target=&quot;_blank&quot;&gt;AxesHelper&lt;/a&gt;, создайте объект и добавьте на сцену. В качестве единственного параметра можно указать длину, с которой нужно отрисовать оси. Мы будем использовать 3:&lt;/p&gt;
  &lt;pre id=&quot;f6aW&quot; data-lang=&quot;javascript&quot;&gt;// Отрисовка осей координат
const axesHelper = new THREE.AxesHelper(3); scene.add(axesHelper);&lt;/pre&gt;
  &lt;figure id=&quot;fYeW&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b1/61/b1611a54-2bd1-489e-a4bd-b26189d0fa12.png&quot; width=&quot;1184&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;2xdj&quot;&gt;Вы должны увидеть зеленую и красную линии.&lt;/p&gt;
  &lt;p id=&quot;J8pq&quot;&gt;Зеленая линия соответствует оси &lt;em&gt;y&lt;/em&gt;. Красная линия соответствует оси &lt;em&gt;x&lt;/em&gt;, а синяя линия соответствует оси &lt;em&gt;z&lt;/em&gt;, но мы ее не видим, потому что она идеально выровнена относительно камеры.&lt;/p&gt;
  &lt;p id=&quot;zUT9&quot;&gt;Мы не будем использовать &lt;a href=&quot;https://threejs.org/docs/#api/en/helpers/AxesHelper&quot; target=&quot;_blank&quot;&gt;AxesHelper&lt;/a&gt; в следующих уроках, но не стесняйтесь добавить его, если вам нужно понять куда смотрят оси.&lt;/p&gt;
  &lt;h2 id=&quot;ci12&quot;&gt;&lt;/h2&gt;
  &lt;h2 id=&quot;LuZR&quot;&gt;Масштабирование объектов&lt;/h2&gt;
  &lt;p id=&quot;6TGE&quot;&gt;scale также является объектом класса &lt;a href=&quot;https://threejs.org/docs/#api/en/math/Vector3&quot; target=&quot;_blank&quot;&gt;Vector3&lt;/a&gt;. По умолчанию &lt;em&gt;x&lt;/em&gt;, &lt;em&gt;y&lt;/em&gt; и &lt;em&gt;z&lt;/em&gt; равны 1, что означает, что к объекту не применяется масштабирование. Если вы поставите значение &lt;em&gt;0,5&lt;/em&gt;, объект будет иметь половину своего размера по этой оси, а если вы поставите значение &lt;em&gt;2&lt;/em&gt;, он будет вдвое больше своего первоначального размера по этой оси.&lt;/p&gt;
  &lt;p id=&quot;iv8N&quot;&gt;Если вы измените эти значения, объект начнет масштабироваться соответствующим образом. Давайте закомментируем изменения положения и добавьте новые масштабы:&lt;/p&gt;
  &lt;pre id=&quot;nWhC&quot; data-lang=&quot;javascript&quot;&gt;mesh.scale.x = 0.5;
mesh.scale.y = 2;
mesh.scale.z = 0.7;&lt;/pre&gt;
  &lt;figure id=&quot;Q1Je&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/af/6c/af6c42e1-f304-429d-bbf5-79426f58032b.png&quot; width=&quot;1184&quot; /&gt;
  &lt;/figure&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;samD&quot;&gt;🤖 При изменении масштаба можно использовать отрицательные значения, но в дальнейшем это может привести к ошибкам, поскольку оси не будут ориентированы в логическом направлении. Старайтесь избегать этого.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;c0on&quot;&gt;Поскольку &lt;em&gt;scale&lt;/em&gt; это &lt;a href=&quot;https://threejs.org/docs/#api/en/math/Vector3&quot; target=&quot;_blank&quot;&gt;Vector3&lt;/a&gt;, мы можем использовать все &lt;a href=&quot;#UDTr&quot;&gt;ранее упомянутые методы этого класса&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;0YZ3&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;r5ZI&quot; data-align=&quot;right&quot;&gt;&lt;a href=&quot;https://blog.travellerlogs.ru/threejs_cookbook__lesson_5&quot; target=&quot;_blank&quot;&gt;Трансформация объектов (часть 2) -&amp;gt;&lt;/a&gt;&lt;/p&gt;
  &lt;tt-tags id=&quot;IVvM&quot;&gt;
    &lt;tt-tag name=&quot;javascript&quot;&gt;#javascript&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;three_js&quot;&gt;#three_js&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;3d_графика&quot;&gt;#3d_графика&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;анимация&quot;&gt;#анимация&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;программирование&quot;&gt;#программирование&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>web_dev_sandbox:emmet</id><link rel="alternate" type="text/html" href="https://teletype.in/@web_dev_sandbox/emmet?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=web_dev_sandbox"></link><title>Гайд по Emmet</title><published>2022-06-06T07:39:32.664Z</published><updated>2022-06-07T05:36:27.252Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/5b/cf/5bcf8d7f-6717-4f3f-a123-375de4d9d12e.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/34/74/3474b61a-7314-46eb-9f10-3e388d44e40f.png&quot;&gt;Emmet - довольно классный инструмент, который помогает вам писать HTML очень и очень быстро. Это похоже на волшебство. Emmet - это не что-то новое, он существует уже много лет, и для каждого редактора есть плагин.</summary><content type="html">
  &lt;p id=&quot;phOr&quot;&gt;Emmet - довольно классный инструмент, который помогает вам писать HTML очень и очень быстро. Это похоже на волшебство. Emmet - это не что-то новое, он существует уже много лет, и для каждого редактора есть плагин.&lt;/p&gt;
  &lt;p id=&quot;J6io&quot;&gt;Всем, кто только начинает осваиваться в программирование эта статья точно пойдет на пользу!&lt;/p&gt;
  &lt;figure id=&quot;U08X&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/34/74/3474b61a-7314-46eb-9f10-3e388d44e40f.png&quot; width=&quot;2178&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;WiVZ&quot;&gt;В VS Code Emmet интегрирован &amp;quot;из коробки&amp;quot;, и всякий раз, когда редактор распознает возможную команду Emmet, он покажет вам всплывающую подсказку.&lt;/p&gt;
  &lt;figure id=&quot;Fjl2&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/2e/a3/2ea32f81-2613-42fe-ac37-10023c4c07a9.png&quot; width=&quot;1576&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Peq4&quot;&gt;Если то, что вы пишете, не имеет других интерпретаций, и VS Code считает, что это должно быть выражение Emmet, то оно будет показано непосредственно во всплывающей подсказке, достаточно красиво:&lt;/p&gt;
  &lt;figure id=&quot;PRWi&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/ce/74/ce744497-4fc0-4c22-a6c9-45c663929159.png&quot; width=&quot;1576&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;t9OB&quot;&gt;Тем не менее, я действительно не знала, как использовать его во всех его тонкостях, пока не начала исследовать и писать об этом)&lt;/p&gt;
  &lt;p id=&quot;11BQ&quot;&gt;Я хочу использовать его в своей повседневной работе, поэтому вот что я узнала:&lt;/p&gt;
  &lt;p id=&quot;QfPk&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;IJx5&quot;&gt;Создайте HTML-файл с нуля&lt;/h2&gt;
  &lt;p id=&quot;f0ib&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;E0ck&quot;&gt;Напечатайте &lt;code&gt;!&lt;/code&gt; и вы получите базовый шаблон HTML для работы:&lt;/p&gt;
  &lt;figure id=&quot;6DTj&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/77/81/7781b726-f1af-4d2f-9355-a17fdc90d68b.png&quot; width=&quot;1576&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;2Pf4&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;and&quot;&gt;&amp;gt; и +&lt;/h2&gt;
  &lt;p id=&quot;DAvl&quot;&gt;&lt;/p&gt;
  &lt;ul id=&quot;87Io&quot;&gt;
    &lt;li id=&quot;TYWp&quot;&gt;&amp;gt; означает ребенка&lt;/li&gt;
    &lt;li id=&quot;3GhH&quot;&gt;+ означает элемент на том же уровне&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;eeWG&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;6t5Z&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7e/ba/7eba4240-ef98-4d0d-806a-81fc92efaa29.png&quot; width=&quot;1540&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;025m&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/72/b6/72b602c2-1d76-487b-a31a-168dfd5545ec.png&quot; width=&quot;1540&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;bnUO&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;xmtA&quot;&gt;Вы можете комбинировать их для выполнения более сложных разметок:&lt;/p&gt;
  &lt;figure id=&quot;EP7l&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d8/24/d82496cd-a81d-4cc5-bee9-df6bb79ccd25.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;BWcN&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;level-up&quot;&gt;Level up&lt;/h2&gt;
  &lt;p id=&quot;LCDc&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;yL3u&quot;&gt;Используя &lt;code&gt;^&lt;/code&gt; вы можете повысить уровень обратно с любого момента, когда вы использовали &lt;code&gt;&amp;gt;&lt;/code&gt; для создания дочернего:&lt;/p&gt;
  &lt;figure id=&quot;Acql&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d8/02/d802bab1-6fb0-4c4c-bc95-288243693bbb.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;wdAm&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;FofU&quot;&gt;Вы можете использовать его несколько раз:&lt;/p&gt;
  &lt;figure id=&quot;mvt6&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b5/ad/b5add35c-92e9-4fa3-9e3b-0d77fd01b244.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;eqCU&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;RT9o&quot;&gt;Применяем умножение&lt;/h2&gt;
  &lt;p id=&quot;WDP7&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;ffC0&quot;&gt;Любой тег может быть добавлен несколько раз с помощью &lt;code&gt;*&lt;/code&gt;:&lt;/p&gt;
  &lt;p id=&quot;bW1p&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;1z5f&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/57/e0/57e03eba-d88d-49d6-9327-93914aac5217.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;C25z&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;9w68&quot;&gt;Группировка выражений&lt;/h2&gt;
  &lt;p id=&quot;UrSt&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;YcWP&quot;&gt;С умножением все начинает становиться немного сложнее. Что делать, если вы хотите умножить 2 элемента? Вы группируете их в круглые скобки &lt;code&gt;( )&lt;/code&gt;:&lt;/p&gt;
  &lt;figure id=&quot;XFSi&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/ba/1f/ba1f5a75-fe8e-4805-b1ef-df2239dd5569.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;selV&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;RQHO&quot;&gt;Атрибуты id и class&lt;/h2&gt;
  &lt;p id=&quot;wJFO&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;bE6B&quot;&gt;&lt;code&gt;id&lt;/code&gt; и &lt;code&gt;class&lt;/code&gt;, вероятно, являются наиболее часто используемыми атрибутами в HTML.&lt;/p&gt;
  &lt;p id=&quot;3wPZ&quot;&gt;Вы можете создать фрагмент HTML, который включает их, используя синтаксис, подобный CSS:&lt;/p&gt;
  &lt;figure id=&quot;UX7T&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/8e/82/8e8272ef-e602-4b6b-b44b-df4dd9ff052c.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;8d4U&quot;&gt;Вы можете добавить несколько классов:&lt;/p&gt;
  &lt;figure id=&quot;McpR&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/91/e6/91e6a91a-b857-4b79-9861-a900285eb5a5.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;3siv&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;X2km&quot;&gt;Добавление уникального class или id&lt;/h2&gt;
  &lt;p id=&quot;y4D8&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;05pH&quot;&gt;&lt;code&gt;id&lt;/code&gt; должен быть уникальным на вашей странице в любое время.&lt;/p&gt;
  &lt;p id=&quot;m3Z8&quot;&gt;&lt;code&gt;class&lt;/code&gt; может быть повторен, но иногда вам нужен инкрементный класс для ваших элементов.&lt;/p&gt;
  &lt;p id=&quot;64Rv&quot;&gt;Вы можете сделать это с помощью &lt;code&gt;$&lt;/code&gt;:&lt;/p&gt;
  &lt;figure id=&quot;76TH&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9b/e7/9be72a62-69be-4263-8612-8d157f11a7ef.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;xEdH&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;2rfN&quot;&gt;Другие атрибуты&lt;/h2&gt;
  &lt;p id=&quot;Q0qO&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;Aymq&quot;&gt;Атрибуты, отличные от &lt;code&gt;class&lt;/code&gt; и &lt;code&gt;id&lt;/code&gt;, должны быть добавлены с помощью скобок &lt;code&gt;[]&lt;/code&gt;:&lt;/p&gt;
  &lt;figure id=&quot;3oeM&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/be/e1/bee12b7f-5a5a-4c0f-93f6-17a59e134ddf.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;2c41&quot;&gt;Вы можете добавить сразу несколько атрибутов:&lt;/p&gt;
  &lt;figure id=&quot;Qho8&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/06/d0/06d06367-5297-46d1-bcff-5ae73e986533.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;uWTg&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;9czo&quot;&gt;Добавление контента&lt;/h2&gt;
  &lt;p id=&quot;tpnu&quot;&gt;&lt;/p&gt;
  &lt;p id=&quot;STkg&quot;&gt;Конечно, вы также можете заполнить HTML-элементы содержимым:&lt;/p&gt;
  &lt;figure id=&quot;ag14&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/09/04/0904923c-3422-480e-9ce0-36b4bf0409b7.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;YbrD&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;qyQg&quot;&gt;Добавление инкрементного числа в разметку&lt;/h2&gt;
  &lt;p id=&quot;zZSW&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;3q4c&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/25/38/2538f7b3-e6a8-45ff-8f91-354221fc781b.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;14zu&quot;&gt;Число обычно начинается с 1, но вы можете заставить его начинаться с произвольного числа:&lt;/p&gt;
  &lt;figure id=&quot;wGR1&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/33/28/3328ae0d-42b5-41b9-8fe9-487785f372f7.png&quot; width=&quot;1618&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Yggk&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;Js3L&quot;&gt;Теги для заголовка страницы&lt;/h2&gt;
  &lt;p id=&quot;zakv&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;4Fbq&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/60/dc/60dc2b84-2d7d-411a-9e04-bd3e949aa21c.png&quot; width=&quot;1700&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Rjoy&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;iuLZ&quot;&gt;Общие теги&lt;/h2&gt;
  &lt;p id=&quot;2CQM&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;yxJB&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/43/59/43593209-2196-4cc2-a121-1f5e7339efc2.png&quot; width=&quot;1700&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;o5To&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;nLcR&quot;&gt;Семантические теги&lt;/h2&gt;
  &lt;p id=&quot;FycP&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;ohYM&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c6/6a/c66a11fe-e167-44a7-bf9c-e54be0beea7b.png&quot; width=&quot;1700&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;GKX1&quot;&gt;&lt;/p&gt;
  &lt;h2 id=&quot;0xXm&quot;&gt;Теги для форм&lt;/h2&gt;
  &lt;p id=&quot;6g24&quot;&gt;&lt;/p&gt;
  &lt;figure id=&quot;eCSv&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b4/12/b412fe83-a2e4-480f-b9b8-8e2d387b3d4f.png&quot; width=&quot;1700&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;16Ii&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/81/e4/81e471ed-9db5-4cdb-95e8-55880660c750.png&quot; width=&quot;1700&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;AR0Q&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9b/16/9b1602db-0307-4058-91c1-dba2a777ac2c.png&quot; width=&quot;1700&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;7gGm&quot;&gt;&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;QF5r&quot;&gt;На этом сегодня все, надеюсь эта статья поможет вам вывести скорость разработки на новый уровень 🔥&lt;/p&gt;
  &lt;p id=&quot;XJmp&quot;&gt;Не забывайте подписываться на &lt;a href=&quot;https://t.me/+nlujTCEwTJk4MTcy&quot; target=&quot;_blank&quot;&gt;телеграм канал&lt;/a&gt;!&lt;/p&gt;

</content></entry></feed>