<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Web Dev Sandbox</title><generator>teletype.in</generator><description><![CDATA[Веб-разработка, 3d моделирование и путешествия. 
Не только интересные статьи на тему IT, но и персональный блог с мыслями разработчика на удаленке! 🌏]]></description><image><url>https://img2.teletype.in/files/5f/26/5f26d1af-f901-44e4-a36b-02c5bafdf929.png</url><title>Web Dev Sandbox</title><link>https://teletype.in/@web_dev_sandbox</link></image><link>https://teletype.in/@web_dev_sandbox?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=web_dev_sandbox</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/web_dev_sandbox?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/web_dev_sandbox?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Mon, 18 May 2026 12:37:03 GMT</pubDate><lastBuildDate>Mon, 18 May 2026 12:37:03 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@web_dev_sandbox/dev_simulate_notes_2</guid><link>https://teletype.in/@web_dev_sandbox/dev_simulate_notes_2?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=web_dev_sandbox</link><comments>https://teletype.in/@web_dev_sandbox/dev_simulate_notes_2?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=web_dev_sandbox#comments</comments><dc:creator>web_dev_sandbox</dc:creator><title>Симулятор разработки: приложение для заметок (часть 2)</title><pubDate>Wed, 02 Nov 2022 12:10:18 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/8b/76/8b76c63d-7413-4989-b570-6f9d5e83b672.png"></media:content><category>Симулятор разработки</category><description><![CDATA[<img src="https://img1.teletype.in/files/45/01/450162c0-cd0e-4032-a53d-f991f081f338.jpeg"></img>Продолжаем вести наш проект и разрабатывать приложение для заметок. В предыдущей части мы определились с требованиями, базовыми прототипами и архитектурой, а так же сделали доску с задачами для нашего проекта.]]></description><content:encoded><![CDATA[
  <p id="dXcI">Продолжаем вести наш проект и разрабатывать приложение для заметок. В <a href="https://blog.travellerlogs.ru/dev_simulate_notes_1" target="_blank">предыдущей части</a> мы определились с требованиями, базовыми прототипами и архитектурой, а так же сделали доску с задачами для нашего проекта.</p>
  <p id="mO8R">Сегодня нам предстоит спланировать этапы, которые будут отвечать за то, в какой последовательности мы будем что-то разрабатывать или настраивать +  начнем работать с кодом, мы то знаем, что это самая кайфовая часть)</p>
  <figure id="hKCr" class="m_column">
    <img src="https://img1.teletype.in/files/45/01/450162c0-cd0e-4032-a53d-f991f081f338.jpeg" width="2880" />
  </figure>
  <p id="OrCX">Давайте посмотрим на то, как выглядит наша доска с задачами в данный момент:</p>
  <figure id="jQsG" class="m_column">
    <img src="https://img2.teletype.in/files/19/de/19de0217-c9a4-4800-a4e2-20b42fc8a75e.png" width="1688" />
  </figure>
  <p id="hhIv">Задача, которая сформулирована как &quot;Создать каркас приложения&quot; - не особо то понятна, помните, что при виде задачи, вы должны с легкостью себе ответить на вопросы:</p>
  <ul id="s4L0">
    <li id="GGuB"><strong>Что именно должно быть сделано в этой задаче?</strong></li>
    <li id="juwV"><strong>Как я пойму, что задача завершена?</strong></li>
  </ul>
  <p id="CAWK"></p>
  <h2 id="XlzQ">Определяемся, что нужно для старта</h2>
  <p id="zItP">И так, для начала нет смысла смотреть на функциональные требования, которые мы с вами определили в прошлой статье, так как у нас еще нет настроенного окружения, где бы мы могли с вами все разрабатывать, поэтому для начала определим задачи, которые помогут нам получить это окружение.</p>
  <p id="OOK0">Что нужно чтобы сделать фронтовой проект? Ну, давайте подумаем...</p>
  <ol id="S1Jq">
    <li id="e4WL">Создать базовый проект и очистить его от всего ненужного (банальный <code>create-react-app</code>)</li>
    <li id="NmTn">Определиться со стайлингом и настроить автоматическое исправление</li>
    <li id="3Op5">Определиться со структурой папок, чтобы не было хаоса</li>
    <li id="HtFJ">Настроить коннект с <em>git</em></li>
  </ol>
  <p id="260S">Пакеты все пачкой ставить не будем, лучше этим заниматься по мере необходимости!</p>
  <p id="71eC">И так, после подобных раздумий наша доска проекта выглядит уже примерно следующим образом:</p>
  <figure id="v65D" class="m_column">
    <img src="https://img2.teletype.in/files/1e/4e/1e4e4add-fcda-4e2a-9166-31d5f8b04ecd.png" width="1688" />
  </figure>
  <p id="0l7J"></p>
  <h2 id="c1GG">Создаем базовый проект и зачищаем ненужное</h2>
  <p id="lQ8y">Приступаем к первой задаче, просто создадим наше приложение:</p>
  <pre id="g4Qi" data-lang="bash">yarn create react-app note-app --template typescript</pre>
  <h3 id="mhUz"></h3>
  <p id="4QtI">Чтобы у нас не было ничего лишнего, удалим все из папки <em>src</em>, кроме<em> index.tsx</em>, index.css и <em>App.tsx</em>, причем в <em>index.tsx</em> оставим только вот это:</p>
  <pre data-lang="jsx" id="f363">import React from &#x27;react&#x27;;
import ReactDOM from &#x27;react-dom/client&#x27;;
import App from &#x27;./App&#x27;;
import &#x27;./index.css&#x27;;

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

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

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

export default App;</pre>
  <h3 id="cgtj"></h3>
  <p id="EO7Q">А в папке <em>public/ оставим только</em></p>
  <p id="o8EG"></p>
  <h2 id="WXpi">Настраиваем eslint</h2>
  <p id="eza6">Не знаю как вам, но мне уже не комфортно работать в проекта, где нет базовой настройки для поддержания чистого код стайла, поэтому давайте супер быстро выполним простую настройку и пойдем дальше!</p>
  <p id="zxvB">Для начала поставим необходимые зависимости для eslint:</p>
  <pre data-lang="bash" id="C4Tb">yarn add -D eslint-plugin-import @typescript-eslint/parser eslint-import-resolver-typescript</pre>
  <p id="0XIj">После чего произведем инициализацию:</p>
  <pre data-lang="bash" id="5x9o">npx eslint --init</pre>
  <p id="hsXC">Отвечаем на вопросы в консоли примерно вот так:</p>
  <blockquote id="RDNz">How would you like to use ESLint?</blockquote>
  <p id="vrL1">-&gt; To check syntax and find problems</p>
  <blockquote id="k0VB">What type of modules does your project use?</blockquote>
  <p id="z0CU">-&gt; JavaScript modules (import/export)</p>
  <blockquote id="wNUC">Which framework does your project use?</blockquote>
  <p id="ZnWW">-&gt; React</p>
  <blockquote id="oRFW">Does your project use TypeScript?</blockquote>
  <p id="xYRR">-&gt; Yes</p>
  <blockquote id="4dlO">Where does your code run?</blockquote>
  <p id="c6fm">-&gt; Browser, Node</p>
  <blockquote id="BfkU">What format do you want your config file to be in?</blockquote>
  <p id="t7uu">-&gt; JSON</p>
  <blockquote id="6KpX">Would you like to install them now?</blockquote>
  <p id="xnJX">-&gt; yes</p>
  <blockquote id="a3RX">Which package manager do you want to use?</blockquote>
  <p id="6Jmh">-&gt; yarn</p>
  <p id="MaCf">После этого нужно будет внести некоторые изменения в .eslintrc.json чтобы внести немного своих правил + чтобы у нас не было дальше конфликта с prettier, итоговый файл выглядит вот так:</p>
  <pre data-lang="javascript" id="d8Gm">{
  &quot;env&quot;: {
    &quot;browser&quot;: true,
    &quot;es2021&quot;: true,
    &quot;node&quot;: true,
    &quot;jest&quot;: true
  },
  &quot;extends&quot;: [
    &quot;eslint:recommended&quot;,
    &quot;plugin:react/recommended&quot;,
    &quot;plugin:@typescript-eslint/recommended&quot;,
    &quot;prettier&quot;
  ],
  &quot;overrides&quot;: [],
  &quot;parser&quot;: &quot;@typescript-eslint/parser&quot;,
  &quot;parserOptions&quot;: {
    &quot;ecmaVersion&quot;: &quot;latest&quot;,
    &quot;sourceType&quot;: &quot;module&quot;
  },
  &quot;plugins&quot;: [
    &quot;react&quot;,
    &quot;react-hooks&quot;,
    &quot;@typescript-eslint&quot;,
    &quot;prettier&quot;
  ],
  &quot;rules&quot;: {
    &quot;react/react-in-jsx-scope&quot;: &quot;off&quot;,
    &quot;spaced-comment&quot;: &quot;error&quot;,
    &quot;quotes&quot;: [&quot;error&quot;, &quot;single&quot;],
    &quot;no-duplicate-imports&quot;: &quot;error&quot;
  },
  &quot;settings&quot;: {
    &quot;import/resolver&quot;: {
      &quot;typescript&quot;: {}
    }
  }
}</pre>
  <h3 id="ewc8"></h3>
  <h2 id="HCuP">Настраиваем prettier</h2>
  <p id="y1v3">Устанавливаем необходимые зависимости:</p>
  <pre data-lang="bash" id="VJdV">yarn add -D prettier eslint-config-prettier eslint-plugin-prettier eslint-plugin-react-hooks</pre>
  <p id="Mc3j">И создаем файл .prettierrc.json:</p>
  <pre data-lang="javascript" id="V7VZ">{
  &quot;semi&quot;: true,
  &quot;tabWidth&quot;: 2,
  &quot;printWidth&quot;: 100,
  &quot;singleQuote&quot;: true,
  &quot;trailingComma&quot;: &quot;all&quot;,
  &quot;jsxSingleQuote&quot;: true,
  &quot;bracketSpacing&quot;: true
}</pre>
  <p id="bYPc">И так, на этом настройка утилит закончена, осталось только добавить новые скрипты в package.json:</p>
  <pre data-lang="javascript" id="DSwy">&quot;lint&quot;: &quot;eslint src/**/*.{js,jsx,ts,tsx,json}&quot;,
&quot;lint:fix&quot;: &quot;eslint --fix &#x27;src/**/*.{js,jsx,ts,tsx,json}&#x27;&quot;,
&quot;format&quot;: &quot;prettier --write &#x27;src/**/*.{js,jsx,ts,tsx,css,md,json}&#x27; --config ./.prettierrc&quot;</pre>
  <h2 id="8L1M"></h2>
  <h2 id="qSRk">Структура папок</h2>
  <p id="ol29">Для крупного приложения сложно с самого начала продумать хорошую структуру хранения кода, но основу заложить стоит, чтобы команда, которая состоит из нескольких разработчиков не писала как кому придет в голову.</p>
  <p id="ykC5">И так, я предлагаю придерживаться в нашем проекте вот такой структуры:</p>
  <pre id="dTkr">-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</pre>
  <p id="MaQt"></p>
  <ul id="mveb">
    <li id="04lD"><code>components/</code> - для хранения компонент нашего приложения</li>
    <li id="J9YQ"><code>hooks/</code> - для общих хуков, которые используются в разных местах</li>
    <li id="Hh8D"><code>context/</code> - для описание различных контекстов приложения</li>
    <li id="oOtM"><code>typings/</code> - для описание типов в приложении</li>
    <li id="50MB"><code>configs/</code> - для хранения различных кончиков (например, роутинг)</li>
    <li id="0aFt"><code>services/</code> - для описание различных утилит, которые пригодятся нам при работе</li>
  </ul>
  <p id="oEpb">Данная структура, возможно, не является оптимальной, да и для большого проекта скорее всего не подойдет, но скорее всего достаточно хорошо ляжет на наш простой проект с заметками.</p>
  <p id="MhVD">Если у вас есть свои идеи по структуре файлов, то жду ваши комментарии)</p>
  <p id="wtYB"></p>
  <hr />
  <p id="4jYy"><strong>Следующая задача - подключение к Git</strong>, думаю, это достаточно простое действие, так что описывать не буду, гайдов на эту тему очень много...</p>
  <p id="9G4R">Ну а мы, пойдем дальше...</p>
  <hr />
  <p id="wBxq"></p>
  <h2 id="NL6N">Приступаем к планированию разработки</h2>
  <p id="uNOC">Для начала давайте вспомним формальные требования, которые мы составили в прошлый раз:</p>
  <section style="background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="ipVw">Необходимо создать приложение Заметки с помощью Reactjs и технологий браузеров.</p>
    <p id="agd3">Возможные действия с заметками:</p>
    <ul id="f7oj">
      <li id="qlUL">Создать (нажимаем на кнопку создать, открывается markdown редактор на ввод)</li>
      <li id="Rs6J">Редактировать (чтобы редактировать заметку нужно открыть нужную заметку и нажать на отдельную кнопку для редактирования)</li>
      <li id="AD5u">Удалить (чтобы удалить заметку нужно открыть нужную заметку и нажать на отдельную кнопку для удаления, после чего нужна остерегающая модалка)</li>
    </ul>
    <p id="5fMM">Сохранение изменений в заметке должно происходить автоматически с внесением этих изменений.</p>
  </section>
  <p id="NIzk"></p>
  <p id="3FWr">Если подумать, то нужно сделать примерно следующие задачи:</p>
  <ul id="qlE5">
    <li id="sOGk">Настроить навигацию, чтобы иметь возможность перемещаться между заметками</li>
    <li id="0SbD">Подключить базу данных</li>
    <li id="ielc">Настроить общий контекст</li>
    <li id="Jzfz">Отображение списка существующих заметок</li>
    <li id="GNAO">Открытие текста определенной заметки</li>
    <li id="wmaN">Создание простой текстовой заметки</li>
    <li id="Yobz">Удаления заметки</li>
    <li id="xuy1">Редактирование заметки</li>
    <li id="v2b8">Поиск по списку заметок</li>
    <li id="xhoo">Отображение заметки в виде отрендеренного <em>Markdown</em></li>
    <li id="jI3t">Что-то еще?</li>
  </ul>
  <p id="OXiM"></p>
  <p id="HCEX">Возможно, сейчас я что-то упустила, но мы это с вами обнаружим в ходе работы, если что!<br /><br />Унесите эти задачи себе на доску проекта, чтобы ничего не потерять!</p>
  <p id="Q9a8"></p>
  <hr />
  <p id="msnU">На этой стадии проекта мы сегодня закончим, в следующий раз мы уже приступим к написанию кода!</p>
  <p id="msnU">Если вам интересен такой формат разора работы над проектом, то очень жду ваших реакций и комментариев!</p>
  <hr />
  <section>
    <p id="vLIj">🤖 Чтобы не пропустить новые уроки подпишись на <a href="https://t.me/travellerLogs" target="_blank">телеграм канал!</a></p>
  </section>

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

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@web_dev_sandbox/react_1</guid><link>https://teletype.in/@web_dev_sandbox/react_1?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=web_dev_sandbox</link><comments>https://teletype.in/@web_dev_sandbox/react_1?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=web_dev_sandbox#comments</comments><dc:creator>web_dev_sandbox</dc:creator><title>React является декларативным - что это значит?</title><pubDate>Tue, 25 Oct 2022 16:31:05 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/7e/fa/7efad26c-bef7-462b-97e4-d92fd0998121.png"></media:content><category>React</category><description><![CDATA[<img src="https://img3.teletype.in/files/ab/f7/abf742f8-7dc0-41f9-acad-d235826fe6c4.png"></img>При изучении React вы, скорее всего не раз слышали, что он является декларативным. Но что означает декларативность и что противоположно декларативности? ]]></description><content:encoded><![CDATA[
  <p id="JNKk">При изучении <em>React</em> вы, скорее всего не раз слышали, что он является декларативным. Но что означает декларативность и что противоположно декларативности? </p>
  <figure id="GGj6" class="m_column">
    <img src="https://img3.teletype.in/files/ab/f7/abf742f8-7dc0-41f9-acad-d235826fe6c4.png" width="1050" />
  </figure>
  <h2 id="yR6w">Декларативный vs императивный</h2>
  <p id="zZKw">Противоположностью декларативности является императивность. Это не специфические для <em>React</em> термины. Они применимы к программированию в целом.</p>
  <p id="E3Vt">Если кратко, то с точки зрения пользовательских интерфейсов:</p>
  <ul id="LzeC">
    <li id="beEU">императивный подход - это когда вы обеспечиваете пошаговую мутацию <strong>DOM</strong> до достижения желаемого пользовательского интерфейса.</li>
    <li id="9uT6">декларативный подход - это когда вы описываете конечное состояние желаемого пользовательского интерфейса.<br /></li>
  </ul>
  <h2 id="Y3CS">Давайте посмотрим на примеры</h2>
  <p id="n5j6">Допустим, нам нужно создать такой пользовательский интерфейс:</p>
  <figure id="1DjP" class="m_original">
    <img src="https://img2.teletype.in/files/5e/65/5e652493-fa1e-428b-a5c0-58b688194500.gif" width="600" />
  </figure>
  <h3 id="HSHM">Императивный подход</h3>
  <p id="xOdu">Вот императивное решение.Для каждого взаимодействия мы предоставляем пошаговые мутации DOM для достижения желаемого состояния пользовательского интерфейса.</p>
  <pre id="9i0c" data-lang="javascript">const btn = document.querySelector(&#x27;.btn&#x27;);
const container = document.querySelector(&#x27;.container&#x27;);

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

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

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

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

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

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

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


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

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@web_dev_sandbox/react_deep_dive_1</guid><link>https://teletype.in/@web_dev_sandbox/react_deep_dive_1?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=web_dev_sandbox</link><comments>https://teletype.in/@web_dev_sandbox/react_deep_dive_1?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=web_dev_sandbox#comments</comments><dc:creator>web_dev_sandbox</dc:creator><title>Исследуем код React (часть 1)</title><pubDate>Sun, 09 Oct 2022 12:57:55 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/c7/60/c7609d24-fc35-45e7-bc5a-4cf362a19c4a.png"></media:content><category>React</category><description><![CDATA[<img src="https://img3.teletype.in/files/24/f4/24f4ed21-c644-428e-a3fd-c293a2967ecf.jpeg"></img>Я всегда воспринимала React как черный ящик, который берет JSX и выводит что-то на экран, не задумываясь о том, как он это делает.]]></description><content:encoded><![CDATA[
  <p id="vXpS">Я всегда воспринимала <em>React</em> как черный ящик, который берет <em>JSX</em> и выводит что-то на экран, не задумываясь о том, как он это делает.</p>
  <p id="U8qG">Конечно, я знаю то-то и то-то о виртуальном DOM и алгоритме свертки и т.д. <em>По крайней мере, в теории.</em></p>
  <p id="DHUC">Но только в этом году мое любопытство наконец-то пересилило меня. Я открыла репозиторий <em>React</em>, но на этот раз с намерением прочитать код....</p>
  <p id="wPsn">Данный цикл статей подойдет не только тем, кто уже давно пользуется React, но и тем, кто только начинает. Понимать как что-то устроено под капотом всегда полезно, тем более что некоторые моменты, которые мы тут разберем не редко встречаются на собеседованиях.</p>
  <figure id="CCOZ" class="m_column">
    <img src="https://img3.teletype.in/files/24/f4/24f4ed21-c644-428e-a3fd-c293a2967ecf.jpeg" width="2880" />
  </figure>
  <p id="GXUJ">Прежде чем вы продолжите чтение, я должна отметить, что это не должно быть исчерпывающим обзором того, как <em>React</em> работает под капотом. На самом деле, некоторые из моих предположений на этот счет, вероятно, окажутся неверными </p>
  <p id="fwnd">В этом цикле статей мы увидим, какие практики и паттерны основная команда <em>React</em> применила к части программного обеспечения, используемого бесчисленным количеством инженеров. Надеюсь, мы сможем почерпнуть вдохновение из их решений.</p>
  <p id="h67j">Ну что же, давайте начнем!</p>
  <p id="dzqN"></p>
  <h2 id="sL2w">И первое что мы видим... Монорепа</h2>
  <p id="U0lz">Я открыла <a href="https://github.com/facebook/react" target="_blank">репозиторий ректа</a>, ожидая найти каталог <em>src</em>. Вместо этого я увидела один каталог с названием <em>packages</em>, сразу поняв, что передо мной <strong>монорепа</strong>. </p>
  <p id="mAHz">Если кто в танке, то <strong>монорепа</strong> - это один репозиторий, в котором хранится несколько различных приложений или библиотек.</p>
  <p id="KiHw">Репозиторий React содержит 30+ пакетов, включая <em>react</em>, <em>react-dom</em>, <em>react-server</em>, <em>react-devtools</em> и многие другие.</p>
  <p id="MLju">Основное преимущество монорепы - более простая локальная настройка для больших проектов, состоящих из нескольких независимых частей, и лучшая возможность повторного использования кода между ними. Это достигается ценой более сложного развертывания и увеличения общей сложности кодовой базы.</p>
  <p id="DH6W">У меня никогда не было возможности поговорить о своих обидах на монорепы, поэтому я могу воспользоваться этой возможностью. </p>
  <p id="yEWU">За последний год я работала в яндексе, в сервисе, который хранит свой код в огромной фронтовой монорепе. Когда все разделено между репозиториями, вы вынуждены внедрять изменения постепенно и больше думать о дизайне.</p>
  <p id="iGmo">Я обнаружила, что продуктивный рабочий процесс с монорепой сложнее реализовать, потому что ваше локальное окружение отличается от того, которое работает в продакшене. Это выстреливало мне в ногу больше раз, чем я смею признаться.</p>
  <p id="WQRN">Однако это не критика архитектуры <em>React</em>. Я уверена, что мейнтейнеры разобрались в своих процессах.</p>
  <p id="QWWH"></p>
  <h2 id="PrHr">С чего бы начать?</h2>
  <p id="kI8v">Чтение незнакомого кода вызывает недоумение. Тем более, если вы не знаете никого, кто мог бы вам в этом помочь. Поэтому мы должны начать с чего-то, чтобы понять кодовую базу и опираться на нее, обращая внимание на паттерны, которые мы обнаруживаем по пути.</p>
  <p id="gbS5">Независимо от программного обеспечения, при исследовании новой для меня кодовой базы, я всегда беру один из его публичных <em>API</em> и начинаю разбираться с него.</p>
  <p id="5Bvg"><strong>Что такое такое публичные API React?</strong></p>
  <p id="lzHd">Например хуки, такие как <code>useState</code> и <code>useEffect</code>, являются частью <em>API</em>. Но, начав с них, мы не сможем понять, что происходит, поскольку у нас не будет контекста того, как работают компоненты или рендеринг.</p>
  <p id="BT9n">Вместо этого мы начнем с одного из публичных методов <em>React</em>, который вызывается только один раз в каждом приложении.</p>
  <pre id="tekb" data-lang="jsx">import ReactDOM from &#x27;react-dom&#x27;;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

]]></content:encoded></item></channel></rss>