<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Andrey Sitnik</title>
    <description>The latest articles on Forem by Andrey Sitnik (@iskin).</description>
    <link>https://forem.com/iskin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F58773%2Fc1871837-301b-4015-b979-4b8a2e471265.jpg</url>
      <title>Forem: Andrey Sitnik</title>
      <link>https://forem.com/iskin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/iskin"/>
    <language>en</language>
    <item>
      <title>Better web video with AV1 codec</title>
      <dc:creator>Andrey Sitnik</dc:creator>
      <pubDate>Tue, 20 Aug 2019 16:46:59 +0000</pubDate>
      <link>https://forem.com/evilmartians/better-web-video-with-av1-codec-52kd</link>
      <guid>https://forem.com/evilmartians/better-web-video-with-av1-codec-52kd</guid>
      <description>&lt;p&gt;Learn how to instantly improve online viewing experience for your users by embracing the new AV1 video format that is already supported by Chrome and Firefox. This short guide will also show how to replace your GIF's with videos, using AV1 or H.264, to make your files twenty to forty times smaller.&lt;/p&gt;

&lt;p&gt;The bets are placed. Both YouTube and Netflix have named &lt;a href="https://en.wikipedia.org/wiki/AV1"&gt;AV1&lt;/a&gt; a video codec for the future: Google's video service is already using it on &lt;a href="https://www.youtube.com/testtube"&gt;TestTube&lt;/a&gt; (new, experimental features for YouTube). Netflix has been calling AV1 &lt;a href="http://www.csimagazine.com/csi/Netflix-AV1-is-our-primary-next-gen-codec.php"&gt;"our primary next-gen codec"&lt;/a&gt; for a while now. At Evil Martians, we have already tried AV1 at &lt;a href="https://evilmartians.com/"&gt;our landing page&lt;/a&gt; and at the landing page of &lt;a href="https://amplifr.com/en/"&gt;Amplifr&lt;/a&gt;. In this article, we will share our experience with a new video format and give step-by-step instructions for optimal encoding strategies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Codecs and Containers
&lt;/h2&gt;

&lt;p&gt;With static images, you don't have to think twice: opt for &lt;a href="https://en.wikipedia.org/wiki/JPEG"&gt;JPEG&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Portable_Network_Graphics"&gt;PNG&lt;/a&gt; supported by all browsers, or experiment with a more compact Google-developed &lt;a href="https://en.wikipedia.org/wiki/WebP"&gt;WebP&lt;/a&gt; for &lt;a href="https://caniuse.com/#search=webp"&gt;newer browsers&lt;/a&gt;. You can almost always (barring some &lt;a href="http://www.aerasec.de/security/advisories/decompression-bomb-vulnerability.html"&gt;dirty hacking tricks&lt;/a&gt; that tools like &lt;a href="https://github.com/DarthSim/imgproxy"&gt;imgproxy&lt;/a&gt; can protect you &lt;a href="https://evilmartians.com/chronicles/introducing-imgproxy"&gt;against&lt;/a&gt;) be sure that an image file with &lt;code&gt;.png&lt;/code&gt; extension is, indeed, a PNG.&lt;/p&gt;

&lt;p&gt;With video files, it is a bit more tricky than that. File extensions (&lt;code&gt;.mp4&lt;/code&gt;, &lt;code&gt;.wmv&lt;/code&gt;, &lt;code&gt;.webm&lt;/code&gt; or &lt;code&gt;.mov&lt;/code&gt;) barely represent containers, up to three different formats are used to make a video file happen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Video codec:&lt;/strong&gt; determines the compression strategy for your video, this is where the trade-offs are made between quality and quantity. On the web, some popular video codecs are H.264, HEVC, VP9, and now AV1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audio codec:&lt;/strong&gt; does the same for audio. If your video does not have sound, you can do without it. Otherwise, the popular choices are MP3, Opus, and AAC.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Containers&lt;/strong&gt; store both video (compressed by some video codec) and audio streams (compressed by some audio codec), and can also add extra details like subtitles and meta information. Popular containers are MP4, MOV, WebM.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, when you see &lt;code&gt;.mp4&lt;/code&gt; extension, the only thing you can be sure about is that the MP4 container had been used to package a file. The choice of codecs depends entirely on a creator: it can be H.264/AAC, or AV1/Opus, or something else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet AV1
&lt;/h2&gt;

&lt;p&gt;AV1 is a video &lt;em&gt;codec&lt;/em&gt; that was first released almost a year ago: in March 2018. It is designed to compete with previous codec generations such as HEVC/VP9 and H.264/VP8.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BQRwPEuS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/b6ztu3frsea4o994k1g0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BQRwPEuS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/b6ztu3frsea4o994k1g0.png" alt="Codec generations"&gt;&lt;/a&gt;&lt;/p&gt;
Video codecs generations diagram by Tsahi Levent-Levi (&lt;a href="https://webrtcglossary.com/av1/"&gt;source&lt;/a&gt;)



&lt;p&gt;To get familiar with technologies used in a new generation video code, feel free to read &lt;a href="https://people.xiph.org/~xiphmont/demo/av1/demo1.shtml"&gt;"Introducing AV1"&lt;/a&gt; and &lt;a href="https://hacks.mozilla.org/2018/06/av1-next-generation-video-the-constrained-directional-enhancement-filter/"&gt;"AV1: next generation video"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With all the low-level trickery involved, AV1 is capable of generating files that are up to &lt;a href="https://code.fb.com/video-engineering/av1-beats-x264-and-libvpx-vp9-in-practical-use-case/"&gt;30-50% smaller&lt;/a&gt; than H.264/VP8 and &lt;a href="https://www.youtube.com/watch?v=k7QHUx09dxo"&gt;up to 30%&lt;/a&gt; smaller than HEVC, even though, due to being still mostly experimental, it has some problems (at the time of this writing):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The encoder is not optimized yet. As a result, encoding is &lt;em&gt;extremely&lt;/em&gt; slow (an &lt;a href="https://github.com/xiph/rav1e"&gt;upcoming encoder&lt;/a&gt; written in Rust attempts to solve this issue). The format is not yet ready for live streaming. However, it is perfectly suitable for web, as your average landing page will usually have a short embedded video that rarely changes.&lt;/li&gt;
&lt;li&gt;While supported by Chrome and Firefox, AV1 lacks implementations for Safari and Edge (although Microsoft already has AV1 support in &lt;a href="https://www.microsoft.com/en-us/p/av1-video-extension-beta/9mvzqvxjbq9v?activetab=pivot%3Aoverviewtab"&gt;early beta&lt;/a&gt;). So you need to have at least two versions of all your videos: AV1 for Chrome/Firefox and H.264 for everything else. Ideally, you should have a third, HEVC version for your Safari users on desktop and mobile and we will show how to prepare all three of those files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The central promise for of AV1 is maintaining high image quality even at low bitrates, thus allowing for smaller files without apparent compression artifacts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bboDMIej--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/s5cj5mjh736rsv7f9z2n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bboDMIej--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/s5cj5mjh736rsv7f9z2n.png" alt="Bitrate comparison between major codecs"&gt;&lt;/a&gt;&lt;/p&gt;
A &lt;a href="https://www.streamingmedia.com/Articles/Editorial/Featured-Articles/AV1-A-First-Look-127133.aspx"&gt;chart&lt;/a&gt; by Jan Ozer plots data rate against the VMAF quality metric. AV1 is a clear winner.



&lt;h2&gt;
  
  
  How to use AV1 right now
&lt;/h2&gt;

&lt;p&gt;Now we are going to show a sequence of steps required to produce the quality video content for the web with AV1. First, you need to choose a container: in theory, it does not matter, but MP4 is recommended and seems to be &lt;a href="https://en.wikipedia.org/wiki/AV1#Supported_container_formats"&gt;the most popular at the moment&lt;/a&gt;. For the audio codec, we will use Opus with AV1 as an &lt;a href="http://opus-codec.org/comparison/"&gt;efficient&lt;/a&gt; and free alternative.&lt;/p&gt;

&lt;p&gt;To ensure the best cross-browser compatibility, we will produce not one, but three files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For desktop Chrome and Firefox (&lt;a href="https://caniuse.com/#search=av1"&gt;31% of users&lt;/a&gt; as of August 2019): MP4 container with AV1 video codec and Opus audio codec.&lt;/li&gt;
&lt;li&gt;For Safari and Edge (&lt;a href="https://caniuse.com/#feat=hevc"&gt;16% of users&lt;/a&gt;): MP4 with HEVC and AAC.&lt;/li&gt;
&lt;li&gt;For other browsers: a larger file in MP4 container with H.264 for video and AAC for audio.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also go with just options 1 and 3, you will still ensure that all your users can see the video.&lt;/p&gt;

&lt;p&gt;For conversion, I recommend using &lt;a href="https://www.ffmpeg.org/"&gt;FFmpeg&lt;/a&gt; in a terminal. There are plenty of GUI tools for video compression, but CLI allows for steps that are easily reproducible and can be automated with a script. Make sure that you are using the most recent version of FFmpeg, as versions below 4.1 do not support AV1 in an MP4 container. Here are the steps to install it.&lt;/p&gt;

&lt;p&gt;For Mac:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make sure you have &lt;a href="https://brew.sh/"&gt;Homebrew&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brew install ffmpeg&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For Linux, we recommend using the latest build of FFmpeg from the official website, as at the time of this writing not all package managers contain most recent, AV1-enabled versions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tar -xf ffmpeg-release-amd64-static.tar.xz&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo cp ffmpeg-4.1-64bit-static/ff* /usr/local/bin/&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For Windows, you can use &lt;a href="https://www.wdiaz.org/how-to-install-ffmpeg-on-windows/"&gt;this guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once &lt;code&gt;ffmpeg&lt;/code&gt; executable is available in your command line, let's generate the H.264 file (to ensure compatibility with older browsers). Since all our files will use MP4 as a container, I will use &lt;code&gt;.av1.mp4&lt;/code&gt;, &lt;code&gt;.hevc.mp4&lt;/code&gt;, and &lt;code&gt;.h264.mp4&lt;/code&gt; file extensions. Here is the command you will need to use (don't worry, we will walk you through all the options in a moment).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Replace SOURCE.mov with a path to your source video file&lt;/span&gt;

ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; SOURCE.mov &lt;span class="nt"&gt;-map_metadata&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:a libfdk_aac &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-crf&lt;/span&gt; 24 &lt;span class="nt"&gt;-preset&lt;/span&gt; veryslow &lt;span class="nt"&gt;-profile&lt;/span&gt;:v main &lt;span class="nt"&gt;-pix_fmt&lt;/span&gt; yuv420p &lt;span class="nt"&gt;-movflags&lt;/span&gt; +faststart &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=trunc(iw/2)*2:trunc(ih/2)*2"&lt;/span&gt; video.h264.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open the resulting &lt;code&gt;video.h264.mp4&lt;/code&gt; file and check your quality. If you are satisfied with the result, but the size still seems too big, try adjusting the &lt;code&gt;-crf&lt;/code&gt; option (try &lt;code&gt;-crf 26&lt;/code&gt; or &lt;code&gt;-crf 28&lt;/code&gt;): it will reduce the file size, but also the quality, so try to find an acceptable trade-off. That process, frankly, is more art than science.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can convert H.264 to AV1 if you don't have a single uncompressed source.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now it is time to generate the AV1 file. The command below will take longer than the one for H.264, but that is to be expected: at the moment, AV1 codec does not use the full power of CPU. That is a curse, but also a blessing: if you are about to encode several files at the same time, it is safe to do so, as multi-threading is currently &lt;a href="https://trac.ffmpeg.org/wiki/Encode/AV1"&gt;not supported by default&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; SOURCE.mov &lt;span class="nt"&gt;-map_metadata&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:a libopus &lt;span class="nt"&gt;-c&lt;/span&gt;:v libaom-av1 &lt;span class="nt"&gt;-crf&lt;/span&gt; 34 &lt;span class="nt"&gt;-b&lt;/span&gt;:v 0 &lt;span class="nt"&gt;-pix_fmt&lt;/span&gt; yuv420p &lt;span class="nt"&gt;-movflags&lt;/span&gt; +faststart &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=trunc(iw/2)*2:trunc(ih/2)*2"&lt;/span&gt; &lt;span class="nt"&gt;-strict&lt;/span&gt; experimental video.av1.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Play around with the &lt;code&gt;-crf&lt;/code&gt; setting for an optimal size/quality balance.&lt;/p&gt;

&lt;p&gt;Now the same for HEVC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; SOURCE.mov &lt;span class="nt"&gt;-map_metadata&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:a libfdk_aac &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx265 &lt;span class="nt"&gt;-crf&lt;/span&gt; 24 &lt;span class="nt"&gt;-preset&lt;/span&gt; veryslow &lt;span class="nt"&gt;-pix_fmt&lt;/span&gt; yuv420p &lt;span class="nt"&gt;-movflags&lt;/span&gt; +faststart &lt;span class="nt"&gt;-tag&lt;/span&gt;:v hvc1 &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=trunc(iw/2)*2:trunc(ih/2)*2"&lt;/span&gt; video.hevc.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then copy all three resulting files (&lt;code&gt;video.h264.mp4&lt;/code&gt;, &lt;code&gt;video.hevc.mp4&lt;/code&gt;, and &lt;code&gt;video.av1.mp4&lt;/code&gt;) to the root of your web project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understand compression options
&lt;/h3&gt;

&lt;p&gt;For now, the commands above look like black magic spells, but all those keys are used for a purpose. Here is what they do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-i SOURCE.mov&lt;/code&gt; sets the source video file for input. FFmpeg will take video and audio streams from this file, convert them, and pack into a new container.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-map_metadata -1&lt;/code&gt; will remove video metadata (like the name of a tool that was used initially to create a video). Sometimes metadata is useful, but for web development it is rarely the case.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-c:a libopus&lt;/code&gt; or &lt;code&gt;-c:a libfdk_aac&lt;/code&gt; selects an &lt;em&gt;audio&lt;/em&gt; codec.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-c:v libaom-av1&lt;/code&gt; selects a &lt;em&gt;video&lt;/em&gt; codec, a library to compress images into a video stream.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-crf 34&lt;/code&gt; stands for Constant Rate Factor and sets your size/quality balance. Think of it as the quality slider for JPEG, but it goes in the opposite direction (&lt;code&gt;0&lt;/code&gt; stands for best quality and bigger size). CRF scale is different for H.264 and AV1: H.264 goes from 0 to 51, AV1 from 0 to 61. As a result, you will have different CRF ratios for AV1 and H.264. According to &lt;a href="https://code.fb.com/video-engineering/av1-beats-x264-and-libvpx-vp9-in-practical-use-case/"&gt;this guide&lt;/a&gt; by Facebook, here are the optimal mappings between H.264 and AV1 CRF values: 19 → 27, 23 → 33, 27 → 39, 31 → 45, 35 → 51, 39 → 57.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-preset veryslow&lt;/code&gt; forces H.264 and HEVC codecs to generate smaller video file even if it will be much longer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-profile:v main&lt;/code&gt; that we use in our H.264 command selects the video codec &lt;a href="https://superuser.com/questions/489087/what-are-the-differences-between-h-264-profiles"&gt;profile&lt;/a&gt;. We can only use "Main", as our video will not be played in Safari otherwise.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-b:v 0&lt;/code&gt; a sets minimum bitrate to force the constant quality mode in AV1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-pix_fmt yuv420p&lt;/code&gt; (pixel format) is a trick to reduce the size of a video. Basically, it uses full resolution for brightness and a smaller resolution for color. It is a way to fool a human eye, and you can safely remove this argument if it does not work in your case.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-movflags +faststart&lt;/code&gt; moves the important information to the beginning of the file. It allows browser to start playing video during downloading.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-tag:v hvc1&lt;/code&gt; enables native HEVC video support on Apple operating systems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-vf "scale=trunc(iw/2)*2:trunc(ih/2)*2"&lt;/code&gt; is a way to ensure the produced video will always have an &lt;em&gt;even&lt;/em&gt; size (some codecs will only work with sizes like &lt;code&gt;300x200&lt;/code&gt; and &lt;code&gt;302x200&lt;/code&gt;, but not with &lt;code&gt;301x200&lt;/code&gt;). This option tells FFmpeg to scale the source for the closes even resolution. If your video dimensions were even in the first place, it would not do anything.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-strict experimental&lt;/code&gt; option needs to be used for AV1 as AV1 encoder is still experimental.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;video.av1.mp4&lt;/code&gt; sets the name for the output file.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Play nice with browsers
&lt;/h3&gt;

&lt;p&gt;Now you need to make sure that browsers will display the right file depending on whether it is supported or not. Luckily, we can set a &lt;code&gt;type&lt;/code&gt; attribute on a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source"&gt;source element&lt;/a&gt;, and only the supported file will be played. For more &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; tag options, look &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;video&lt;/span&gt; &lt;span class="na"&gt;controls&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"400"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"video.hevc.mp4"&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"video/mp4; codecs=hevc,mp4a.40.2"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"video.av1.mp4"&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"video/mp4; codecs=av01.0.05M.08,opus"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"video.h264.mp4"&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"video/mp4; codecs=avc1.4D401E,mp4a.40.2"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/video&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Source tags work similarly to &lt;code&gt;if...else&lt;/code&gt; statements: the browser will read the list of &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; tags top to bottom and play the first one with supported video type.&lt;/p&gt;

&lt;p&gt;Type attribute describes a file format: which container (&lt;code&gt;video/mp4&lt;/code&gt; for MP4), video codec (&lt;code&gt;av01.0.05M.08&lt;/code&gt; for AV1, &lt;code&gt;hevc&lt;/code&gt; for HEVC and &lt;code&gt;avc1.4D401E&lt;/code&gt; for H.264), and audio codec (&lt;code&gt;opus&lt;/code&gt; for Opus and &lt;code&gt;mp4a.40.2&lt;/code&gt; for AAC) should be used.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: how to convert GIFs to AV1 and H.264
&lt;/h2&gt;

&lt;p&gt;In modern times, using GIF for video fragments is a poor practice. GIFs take 20 to 40 times more space than H.264 or AV1. They also require more CPU and power and drain more battery than modern video formats. If you need short animation sequences on your website in 2019, always opt for video codecs. Luckily, FFmpeg supports GIF files as an input source.&lt;/p&gt;

&lt;p&gt;Here's how to convert your GIF to H.264:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; IMAGE.gif &lt;span class="nt"&gt;-map_metadata&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;-an&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-crf&lt;/span&gt; 24 &lt;span class="nt"&gt;-preset&lt;/span&gt; veryslow &lt;span class="nt"&gt;-profile&lt;/span&gt;:v main &lt;span class="nt"&gt;-pix_fmt&lt;/span&gt; yuv420p &lt;span class="nt"&gt;-movflags&lt;/span&gt; +faststart &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=trunc(iw/2)*2:trunc(ih/2)*2"&lt;/span&gt; animation.h264.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's how to go even further and convert it to AV1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; IMAGE.gif &lt;span class="nt"&gt;-map_metadata&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;-an&lt;/span&gt; opus &lt;span class="nt"&gt;-c&lt;/span&gt;:v libaom-av1 &lt;span class="nt"&gt;-crf&lt;/span&gt; 50 &lt;span class="nt"&gt;-b&lt;/span&gt;:v 0 &lt;span class="nt"&gt;-pix_fmt&lt;/span&gt; yuv420p &lt;span class="nt"&gt;-movflags&lt;/span&gt; +faststart &lt;span class="nt"&gt;-vf&lt;/span&gt; &lt;span class="s2"&gt;"scale=trunc(iw/2)*2:trunc(ih/2)*2"&lt;/span&gt; &lt;span class="nt"&gt;-strict&lt;/span&gt; experimental animation.av1.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use &lt;code&gt;animation.h264.mp4&lt;/code&gt; and &lt;code&gt;animation.av1.mp4&lt;/code&gt; in our HTML. Just replace &lt;code&gt;VIDEO_WIDTH&lt;/code&gt;, &lt;code&gt;VIDEO_HEIGHT&lt;/code&gt;, and &lt;code&gt;PATH_TO_VIDEO&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;video&lt;/span&gt;
  &lt;span class="na"&gt;autoplay&lt;/span&gt;
  &lt;span class="na"&gt;loop&lt;/span&gt;
  &lt;span class="na"&gt;muted&lt;/span&gt;
  &lt;span class="na"&gt;playsinline&lt;/span&gt;
  &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"VIDEO_WIDTH"&lt;/span&gt;
  &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"VIDEO_HEIGHT"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"PATH_TO_VIDEO/animation.av1.mp4"&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"video/mp4; codecs=av01.0.05M.08"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"PATH_TO_VIDEO/animation.h264.mp4"&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"video/mp4"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/video&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;autoplay&lt;/code&gt; and &lt;code&gt;loop&lt;/code&gt; attributes will emulate the expected behavior of a GIF: looping an animation after the website was loaded. &lt;code&gt;playsinline&lt;/code&gt; will forbid Safari from opening the video in full-screen mode.&lt;/p&gt;




&lt;p&gt;And that concludes our practical guide!&lt;/p&gt;

&lt;p&gt;Even though AV1 codec is still considered experimental, you can already leverage its high-quality, low-bitrate features for a sizable chunk for your web audience (users with current versions of Chrome and Firefox). Of course, you would not want to leave users for other browsers hanging, but the attributes for &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; tags make implementing this logic easy, and in pure HTML, you don't need to go at length to detect user agents with JavaScript. Mastering a few FFmpeg commands also seems like an easy way to improve the video viewing experience for your visitors. We already use AV1 in production on a couple of our projects and have not encountered any significant problems (except for video compression times, but, again, we are dealing mostly with short static sequences).&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>html</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Faster WebGL/Three.js 3D graphics with OffscreenCanvas and Web Workers</title>
      <dc:creator>Andrey Sitnik</dc:creator>
      <pubDate>Tue, 02 Apr 2019 15:03:59 +0000</pubDate>
      <link>https://forem.com/evilmartians/faster-webgl-three-js-3d-graphics-with-offscreencanvas-and-web-workers-43he</link>
      <guid>https://forem.com/evilmartians/faster-webgl-three-js-3d-graphics-with-offscreencanvas-and-web-workers-43he</guid>
      <description>&lt;p&gt;&lt;strong&gt;Translations:&lt;/strong&gt; &lt;a href="https://habr.com/ru/post/446682/" rel="noopener noreferrer"&gt;Russian&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Learn how to improve WebGL performance when creating complex scenes with &lt;a href="https://threejs.org/" rel="noopener noreferrer"&gt;Three.js&lt;/a&gt; library, by moving the render away from the main thread into a Web worker with &lt;code&gt;OffscreenCanvas&lt;/code&gt;. Your 3D will render better on low-end devises and the average performance will go up. &lt;/p&gt;

&lt;p&gt;After I &lt;a href="https://twitter.com/sitnikcode/status/1098238272768217088" rel="noopener noreferrer"&gt;added&lt;/a&gt; a 3D WebGL model of an earth on my &lt;a href="https://sitnik.ru/" rel="noopener noreferrer"&gt;personal website&lt;/a&gt;, I found that I immediately lost 5% on &lt;a href="https://developers.google.com/web/tools/lighthouse/" rel="noopener noreferrer"&gt;Google Lighthouse&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In this article, I will show you how to win back the performance without sacrificing cross-browser compatibility with a tiny library that I wrote for this purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;With Three.js it is easy to create complex WebGL scenes. Unfortunately, it has a price. Three.js will add around &lt;a href="https://bundlephobia.com/result?p=three@0.102.1" rel="noopener noreferrer"&gt;563 KB&lt;/a&gt; to your JS bundle size (and due to its architecture it is not really tree-shakeable).&lt;/p&gt;

&lt;p&gt;You may say that the average background image could have the same 500 KB. But every kilobyte of JavaScript costs more to your website’s overall performance than a kilobyte of image data. Latency and bandwidth are not the only things to consider if you aim for a fast website: it is also important to consider how much time will the CPU spend on processing your content. And on lower-end devices, processing resources can take more time than downloading them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fxs4kuxe0hat7b31lqg2z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fxs4kuxe0hat7b31lqg2z.png" alt="3.5 seconds to process 170 KB of JS and 0.1 second for 170 KB of JPEG"&gt;&lt;/a&gt;&lt;br&gt;3.5 seconds to process 170 KB of JS and 0.1 second for 170 KB of JPEG. &lt;a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/javascript-startup-optimization/" rel="noopener noreferrer"&gt;Addy Osmani&lt;/a&gt;
 &lt;/p&gt;

&lt;p&gt;Your webpage will be effectively frozen while the browser processes 500KB of Three.js code, as executing JavaScript takes up the main thread. Your user will bot be able to interact with a page until a scene is fully rendered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Workers and Offscreen Canvas
&lt;/h2&gt;

&lt;p&gt;Web Workers is a solution to avoid page freeze during JS execution. It is a way to move some JavaScript code to a separated thread.&lt;/p&gt;

&lt;p&gt;Unfortunately, multi-thread programming is very hard. To make it simpler, Web Workers do not have access to DOM. Only the main JavaScript thread has this access. However, Three.js requires and access to the &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; node located in the DOM.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas" rel="noopener noreferrer"&gt;&lt;code&gt;OffscreenCanvas&lt;/code&gt;&lt;/a&gt; is a solution to this problem. It allows you to transfer canvas access the to Web Worker. It is still thread safe as the main thread cannot access &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; once you opt for this workaround.&lt;/p&gt;

&lt;p&gt;Sounds like we got our bases covered, but here’s the problem: Offscreen Canvas API is supported by Google Chrome only.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fo2nqcjv8cwvc76rgrh8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fo2nqcjv8cwvc76rgrh8q.png" alt="Only Chrome, Android and Chrome for Android supports OffscreenCanvas according to Can I Use"&gt;&lt;/a&gt;&lt;br&gt;Browsers with Offscreen Canvas support in April of 2019 according to &lt;a href="https://caniuse.com/#feat=offscreencanvas" rel="noopener noreferrer"&gt;Can I Use&lt;/a&gt;
 &lt;/p&gt;

&lt;p&gt;However, even in the face of our main enemy, cross-browser issues, we shall not be afraid. Let’s use progressive enhancement: we will improve performance for Chrome and future browsers. Other browsers will run Three.js the old way in the main JavaScript thread.&lt;/p&gt;

&lt;p&gt;We need to come up with a way to write a single file for two different environments, keeping in mind that many DOM APIs will not work inside the Web Worker.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;To hide all the hacks and keep the code readable I created a tiny &lt;strong&gt;&lt;a href="https://github.com/ai/offscreen-canvas" rel="noopener noreferrer"&gt;offscreen-canvas&lt;/a&gt;&lt;/strong&gt; JS library (just 400 bytes). The following examples will rely on it, but I will also explain how it works under the hood.&lt;/p&gt;

&lt;p&gt;First, add &lt;code&gt;offscreen-canvas&lt;/code&gt; npm package to your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;offscreen-canvas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will need to provide a separated JS file for Web Worker. Let’s create a separate JS bundle in webpack’s or Parcel’s config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  entry: {
    'app': './src/app.js',
&lt;span class="gi"&gt;+   'webgl-worker': './src/webgl-worker.js'
&lt;/span&gt;  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bundlers will add a cache buster to bundle’s file names in production. To use the name in our main JS file, let’s add a &lt;a href="https://3perf.com/blog/link-rels/" rel="noopener noreferrer"&gt;preload&lt;/a&gt; tag. The exact code will depend on the way you generate HTML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"preload"&lt;/span&gt; &lt;span class="na"&gt;as=&lt;/span&gt;&lt;span class="s"&gt;"script"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"./webgl-worker.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we should get the canvas node and a worker URL in the main JS file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;createWorker&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offscreen-canvas/create-worker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;workerUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[rel=preload][as=script]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;canvas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createWorker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;workerUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/ai/offscreen-canvas/blob/master/create-worker.js" rel="noopener noreferrer"&gt;&lt;code&gt;createWorker&lt;/code&gt;&lt;/a&gt; looks for &lt;code&gt;canvas.transferControlToOffscreen&lt;/code&gt; to detect &lt;code&gt;OffscreenCanvas&lt;/code&gt; support. If the browser supports it, the library will load JS files as a Web Worker. Otherwise, it will load the JS file as a regular script.&lt;/p&gt;

&lt;p&gt;Now, let’s open &lt;code&gt;webgl-worker.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;insideWorker&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offscreen-canvas/inside-worker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;insideWorker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Here we will initialize Three.js&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/ai/offscreen-canvas/blob/master/inside-worker.js" rel="noopener noreferrer"&gt;&lt;code&gt;insideWorker&lt;/code&gt;&lt;/a&gt; checks if it was it loaded in Web Worker. Depending on the environment, it will use different ways to communicate with the main thread.&lt;/p&gt;

&lt;p&gt;The library will execute the callback on any message from the main thread. The first message from &lt;code&gt;createWorker&lt;/code&gt; for our worker will always be the object with &lt;code&gt;{ canvas, width, height }&lt;/code&gt; to initialize canvas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;+ import {
+   WebGLRenderer, Scene, PerspectiveCamera, AmbientLight,
+   Mesh, SphereGeometry, MeshPhongMaterial
+ } from 'three'
&lt;/span&gt;  import insideWorker from 'offscreen-canvas/inside-worker'
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ const scene = new Scene()
+ const camera = new PerspectiveCamera(45, 1, 0.01, 1000)
+ scene.add(new AmbientLight(0x909090))
+
+ let sphere = new Mesh(
+   new SphereGeometry(0.5, 64, 64),
+   new MeshPhongMaterial()
+ )
+ scene.add(sphere)
+
+ let renderer
+ function render () {
+   renderer.render(scene, camera)
+ }
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  const worker = insideWorker(e =&amp;gt; {
    if (e.data.canvas) {
&lt;span class="gi"&gt;+     // canvas in Web Worker will not have size, we will set it manually to avoid errors from Three.js
+     if (!canvas.style) canvas.style = { width, height }
+     renderer = new WebGLRenderer({ canvas, antialias: true })
+     renderer.setPixelRatio(pixelRatio)
+     renderer.setSize(width, height)
+
+     render()
&lt;/span&gt;    }
  })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While creating an initial state of the scene, we can find some error messages from Three.js. Not all the DOM APIs are available in a Web Worker. For instance, there is no &lt;code&gt;document.createElement&lt;/code&gt; to load SVG texture. We will need a different loader for Web Worker and regular script environments. We can detect the environment by &lt;code&gt;worker.isWorker&lt;/code&gt; property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;      renderer.setPixelRatio(pixelRatio)
      renderer.setSize(width, height)
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+     const loader = worker.isWorker ? new ImageBitmapLoader() : new ImageLoader()
+     loader.load('/texture.png', mapImage =&amp;gt; {
+       sphere.material.map = new CanvasTexture(mapImage)
+       render()
+     })
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;      render()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We rendered the initial state of the scene. But most of WebGL scenes need to react to user actions. It could be rotating a camera with a mouse. Or updating &lt;code&gt;canvas&lt;/code&gt; on window resize. Unfortunately, Web Worker doesn’t have access to any of the DOM’s events. We need to listen to events in the main thread and send messages to the worker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  import createWorker from 'offscreen-canvas/create-worker'
&lt;span class="err"&gt;
&lt;/span&gt;  const workerUrl = document.querySelector('[rel=preload][as=script]').href
  const canvas = document.querySelector('canvas')
&lt;span class="err"&gt;
&lt;/span&gt;  const worker = createWorker(canvas, workerUrl)
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ window.addEventListener('resize', () =&amp;gt; {
+   worker.post({
+     type: 'resize', width: canvas.clientWidth, height: canvas.clientHeight
+   })
+ })
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  const worker = insideWorker(e =&amp;gt; {
    if (e.data.canvas) {
      if (!canvas.style) canvas.style = { width, height }
      renderer = new WebGLRenderer({ canvas, antialias: true })
      renderer.setPixelRatio(pixelRatio)
      renderer.setSize(width, height)
&lt;span class="err"&gt;
&lt;/span&gt;      const loader = worker.isWorker ? new ImageBitmapLoader() : new ImageLoader()
      loader.load('/texture.png', mapImage =&amp;gt; {
        sphere.material.map = new CanvasTexture(mapImage)
        render()
      })
&lt;span class="err"&gt;
&lt;/span&gt;      render()
&lt;span class="gd"&gt;-   }
&lt;/span&gt;&lt;span class="gi"&gt;+   } else if (e.data.type === 'resize') {
+     renderer.setSize(width, height)
+     render()
+   }
&lt;/span&gt;  })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;OffscreenCanvas&lt;/code&gt;, I fixed UI freezes on my personal site in Chrome and got a full 100 score on Google Lighthouse. And my WebGL scene still works in all other browsers.&lt;/p&gt;

&lt;p&gt;You can check the result: &lt;strong&gt;&lt;a href="https://sitnik.ru/" rel="noopener noreferrer"&gt;demo&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;source code&lt;/strong&gt; for &lt;a href="https://github.com/ai/sitnik.ru/blob/master/src/earth/earth.js" rel="noopener noreferrer"&gt;main thread&lt;/a&gt; and &lt;a href="https://github.com/ai/sitnik.ru/blob/master/src/earth/worker.js" rel="noopener noreferrer"&gt;worker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fn6esc7r6qba9vip43xsy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fn6esc7r6qba9vip43xsy.png" alt="With OffscreenCanvas Google Lighthouse Performance rate increased from 95 to 100"&gt;&lt;/a&gt;&lt;br&gt;With OffscreenCanvas Google Lighthouse Performance rate increased from 95 to 100
 &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>CSS and JS Are at War, Here’s How to Stop It</title>
      <dc:creator>Andrey Sitnik</dc:creator>
      <pubDate>Tue, 29 Jan 2019 13:36:31 +0000</pubDate>
      <link>https://forem.com/evilmartians/css-and-js-are-at-war-heres-how-to-stop-it-158a</link>
      <guid>https://forem.com/evilmartians/css-and-js-are-at-war-heres-how-to-stop-it-158a</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; There are a lot of people who love &lt;strong&gt;both&lt;/strong&gt; JS and UX/CSS/etc. If we stop labeling people just as “JS developers” or “UX developers”, we can achieve a ceasefire in the current “JS vs. CSS” war and get closer to peace.&lt;/p&gt;

&lt;h2&gt;
  
  
  The War is Real
&lt;/h2&gt;

&lt;p&gt;Some call it &lt;a href="https://css-tricks.com/the-great-divide/"&gt;The Great Divide&lt;/a&gt;: the frontline is real, with JavaScript diehards on one side, and UX/CSS people who advocate non-JS approaches to interfaces—on another.&lt;/p&gt;

&lt;p&gt;Front-end developers are afraid of losing their jobs if they avoid the whole JavaScript hype. And it is perfectly understandable: CSS is out of trends. There are significantly fewer CSS conferences and meetups compared to JS/React and friends. For instance, there are 6+ JS meetups in New York and 0 regular CSS meetups.&lt;/p&gt;

&lt;p&gt;On the other hand, we see simple static websites being over-engineered out of a sheer &lt;a href="https://en.wikipedia.org/wiki/Fear_of_missing_out"&gt;FOMO&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;We see prominent figures in the front-end community passing the blame on each other every day and that is unfortunate, to say the least.&lt;/p&gt;

&lt;h2&gt;
  
  
  Look Beyond
&lt;/h2&gt;

&lt;p&gt;The warring factions are often labeled as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;“JS-JS-JS”&lt;/strong&gt;: Developers who create SPA with client-side JavaScript frameworks like React, Vue.js, and Angular. They are heavy users of innumerable build tools (Babel, webpack, etc.) and JS libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;“UX developers”, “CSS developers”, “HTML-JS-CSS developers”&lt;/strong&gt;: Developers who create static websites with vanilla JavaScript and plain CSS. Accessibility and performance are most important topics in their community.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But do we &lt;strong&gt;have&lt;/strong&gt; to have this split? Maybe this dualism is based solely on our own bias? &lt;/p&gt;

&lt;p&gt;In my opinion, this bias is largely caused by two things.&lt;/p&gt;

&lt;p&gt;First of all, there is a trend to separate CSS and JavaScript conferences. I think it got started by a very popular and successful JSConf/CSSConf family of events and by a trend for Put-Your-Own-City-Here.js meetups. Content platforms also support the divide: some of them publishe mostly React/JS articles, others focus on CSS and UX.&lt;/p&gt;

&lt;p&gt;Second of all, social networks are good at &lt;a href="http://www.pewresearch.org/fact-tank/2016/01/27/the-demographic-trends-shaping-american-politics-in-2016-and-beyond/"&gt;polarizing society&lt;/a&gt;. We put ourselves in a bubble of likeminded individuals by subscribing to their feeds and make things even worse by reposting only the most aggressive opinions coming from the other side.&lt;/p&gt;

&lt;p&gt;The modern web is incredibly complex. It is extremely hard to master all the technologies that power it and no one can really call oneself a 100% “full-stack” developer. But due to the fact that the JS and CSS/UX discourses have become so (artificially) separated, people with different, but not necessarily opposing passions are bing shoved into a black-and-white “JS vs. CSS” world view. React developers who are passionate about CSS animations and &lt;a href="https://en.wikipedia.org/wiki/Computer_accessibility"&gt;a11y&lt;/a&gt; are labeled simple as “JS folks”. And a CSS developer who loves Babel and zero-runtime CSS-in-JS will still be painted as a “CSS guy/gal”. &lt;/p&gt;

&lt;h2&gt;
  
  
  People Who Love Them Both
&lt;/h2&gt;

&lt;p&gt;As a creator of &lt;a href="https://postcss.org/"&gt;PostCSS&lt;/a&gt;, I could never really pick a side, even if I wanted to. On one hand, PostCSS is a tool for CSS (hence the name). On another hand, PostCSS is a &lt;strong&gt;JavaScript&lt;/strong&gt; build tool and build tools are not well accepted in a modern CSS community.&lt;/p&gt;

&lt;p&gt;And I am not alone, there are so many people like me: the creator of an amazing &lt;a href="https://github.com/aholachek/react-flip-toolkit"&gt;React toolkit for animations&lt;/a&gt;, or the creator of a &lt;a href="https://github.com/YozhikM/stylelint-a11y"&gt;CSS a11y linter&lt;/a&gt;, to name a few.&lt;/p&gt;

&lt;p&gt;To say the truth, each of us knows only a small subset of technologies that exist out there. And one’s passions not necessarily come from a single topic either. It is OK to love both React and CSS. Or use complex build systems to be sure about you got your a11y right. Or you can dive into distributed systems because you want to make &lt;a href="https://github.com/logux"&gt;great UX with a bad Internet connection&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Even technologies themselves cannot be seen in black and white.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://getbem.com/"&gt;BEM&lt;/a&gt; is often mentioned by the proponents of “CSS faction” as a way to avoid the possible confusion of CSS-in-JS. But few people know that it was not designed by &lt;a href="https://yandex.com/company/"&gt;Yandex&lt;/a&gt; as a purely CSS technology! It also contains a JavaScript framework and originally had a set of ideas that were later used in React (like nesting small isolated components).&lt;/p&gt;

&lt;p&gt;ESLint configs, popular in React community (like &lt;a href="https://www.npmjs.com/package/eslint-config-airbnb"&gt;AirBnB config&lt;/a&gt;), contain &lt;a href="https://github.com/evcohen/eslint-plugin-jsx-a11y#supported-rules"&gt;a lot of a11y rules&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;I think the war is real. I think we can stop this war if we stop dividing developers into black and white categories.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you like technologies from both “sides”: say it out loud! Make it visible, so people can start a civilized discussion. Do you like modern JS frameworks, but also like creating static websites that don’t involve client-side rendering at all? Tell the world about it. Open source authors will create more frameworks for static websites, if they see the need.&lt;/li&gt;
&lt;li&gt;Let’s have a public forum for a conversation between JS and CSS worlds. If you are organizing a JavaScript meetup, set aside a day for CSS/UX talks. Let’s “front-end” conferences instead of “JS conferences” and “CSS conferences”, where people from different camps could explain their daily problems and preferred solutions to their opponents.&lt;/li&gt;
&lt;li&gt;Let’s try technologies coming from “the other side”:

&lt;ul&gt;
&lt;li&gt;If you are a CSS/UX developer, start with linters. &lt;a href="https://stylelint.io/"&gt;Stylelint&lt;/a&gt; is a good CSS linter to start with. It will warn you about mistakes and allow you to share best practices across the team. And you can run it as a plugin for your favorite text editor, so you can start even without any bundlers.&lt;/li&gt;
&lt;li&gt;If you are React developer, try some vanilla JS on your next landing page or a blog. This will allow you to better understand your framework’s internals. And your users will thank you for increased performance due to a lighter JavaScript bundle.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;Here is my article about &lt;a href="https://evilmartians.com/chronicles/five-years-of-postcss-state-of-the-union"&gt;the future of PostCSS, linters, and CSS-in-JS&lt;/a&gt; at &lt;a href="https://evilmartians.com/chronicles/"&gt;Martian Chronicles&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>css</category>
      <category>react</category>
      <category>discuss</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How a Month without Computers Changed Me</title>
      <dc:creator>Andrey Sitnik</dc:creator>
      <pubDate>Wed, 31 Oct 2018 16:01:23 +0000</pubDate>
      <link>https://forem.com/evilmartians/how-a-month-without-computers-changed-me-1ho4</link>
      <guid>https://forem.com/evilmartians/how-a-month-without-computers-changed-me-1ho4</guid>
      <description>&lt;p&gt;No emails left for me to read. Nor write. I’ve sent a message to my family and delegated my open source projects (Autoprefixer and PostCSS) to my friends. With my last tweet sent, I turn off my laptop, phone, and tablet. My Digital Sabbath begins in 10 minutes: no digital devices for the next month.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From the days of the Butlerian Jihad when “thinking machines” had been wiped from most of the universe, computers had inspired distrust.&lt;br&gt;
— &lt;a href="https://en.wikipedia.org/wiki/Dune_Messiah" rel="noopener noreferrer"&gt;Dune Messiah&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejz3hvlcmwg24e7birlh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejz3hvlcmwg24e7birlh.jpg" alt="Laptop, smartphone and other digitals devices on the left side and books, notepad and other old things on the right side" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;
On the left are things from my old, digital life—carefully, I turned them off, got together and put into a bag. What I got myself for the new life is on the right.



&lt;h1&gt;
  
  
  The Month of Ramadan
&lt;/h1&gt;

&lt;p&gt;It began with &lt;a href="https://sajjadi.livejournal.com/158713.html" rel="noopener noreferrer"&gt;a post&lt;/a&gt; about the Islamic &lt;a href="https://en.wikipedia.org/wiki/Ramadan" rel="noopener noreferrer"&gt;month of Ramadan&lt;/a&gt;, when one is not allowed to drink or eat until ‘the first star appears in the sky’ (imagine how difficult it must be fasting like that in Norway, during the polar day). The Ambassador explained that religious people deny themselves what everyday life has to offer to understand how great God’s grace is. This idea gave birth in my imagination to a technocratic state where people do without soy and genetically modified foods for a year just to see: natural agriculture is costly and might lead to global hunger. &lt;/p&gt;

&lt;p&gt;Then I asked myself if ‘technological fasting’ could do one good in modern society. Technology has changed the world in the blink of an eye, leaving us no time to reflect on it. What if a month without modern technology could ‘travel’ you to the past? What if there is a way you could compare your technology-relying self to what you once were?&lt;/p&gt;

&lt;p&gt;I had doubts. My love of IT and addiction to digital overload were not going to make it easy. But then I learned about &lt;a href="https://www.theverge.com/2013/5/1/4279674/im-still-here-back-online-after-a-year-without-the-internet" rel="noopener noreferrer"&gt;this effort of a computer-weary&lt;/a&gt; The Verge journalist. My life, he wrote, had become so much better without the computers. To me, his report seemed not without bias, and I decided to take my own journey into the pre-digital world—this time to be seen through the eyes of a programmer.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Preparation
&lt;/h1&gt;

&lt;p&gt;Doing without my laptop was not gonna cut it, I thought. Smart chips being now used in every domain of life, I must use no digital device at all. I read about fasting in other religions and decided to make precise rules to guide me through whatever difficulty arises. In its final form my covenant was, ‘you must not operate any device that stores a programme in its memory’—in other words, no &lt;a href="https://en.wikipedia.org/wiki/Von_Neumann_architecture" rel="noopener noreferrer"&gt;von Neumann architecture&lt;/a&gt;-based devices were allowed.  &lt;/p&gt;

&lt;p&gt;This was the criterion I used to prepare for my journey. Just like a James Bond, only the other way round: the small, shiny and functional gadgets gave way to things old, cumbersome and one-purpose. Thanks to the hipsters, this vintage could easily be found in flea markets.&lt;/p&gt;

&lt;p&gt;My friends tried to scare me away from taking the journey by telling the tale of the Mozilla programmer whom two month of &lt;a href="https://web.archive.org/web/20140215194411/http://paulrouget.com/e/taiwan2013/" rel="noopener noreferrer"&gt;life without the internet&lt;/a&gt; made him &lt;a href="https://web.archive.org/web/20180823105739/http://paulrouget.com/e/back" rel="noopener noreferrer"&gt;delete his twitter account&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To burn all the bridges, I told everyone about my Digital Sabbath plans. Doing any work during that time was out of the question, so I took a leave and explained my colleagues how to contact my girlfriend in case of emergency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://evilmartians.com/" rel="noopener noreferrer"&gt;Evil Martians&lt;/a&gt; played a trick on me though, by deciding to run an internal competition with prizes for the biggest open-source contributions exactly during my Sabbath month.&lt;/p&gt;

&lt;p&gt;But there was no going back. My fasting began on November 6, 2013.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Photography
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsxv71wto0cq95iec9gue.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsxv71wto0cq95iec9gue.JPG" alt="Andrey Sitnik making selfie in the mirror by Zenit-122" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For my forced dive into the world of analogue photography, I picked a light-meter equipped &lt;a href="http://www.photographyreview.com/product/cameras/film-cameras/35mm/zenit/122.html" rel="noopener noreferrer"&gt;Zenit-122&lt;/a&gt;. My camera would take care of the process—I only needed to keep turning the dials until it told me everything was alright. While most cameras make the focus right using special &lt;a href="https://en.wikipedia.org/wiki/Focusing_screen" rel="noopener noreferrer"&gt;split screen and microprism&lt;/a&gt; to align the two sides of an image, a light-meter is a small solar cell and three LEDs that are seen in the right side of the viewfinder. The upper one is lit if your photo is going to be too dark, the lower if too light, and the middle one turns green if the options are set in the right way.&lt;/p&gt;

&lt;p&gt;It was not that hard taking pictures, but I understood it was the computers that had made photography such an easy-to-do, everyday thing. Of course, even our parents didn’t do it the hard way—they didn’t need to know chemistry or develop the photos. Yet, analogue photography reminded me of driving: you start with theory, then they show you what to do and how, and then you practice in a place without other cars. It is not until you have developed the skill that you go and take actual photos. With digital photography, everyone is a photographer now. It only takes opening your phone app; even a child can do that.&lt;/p&gt;

&lt;p&gt;Another discovery I made was the incredible power that modern digital cameras have gained in the last decade. Before the Digital Sabbath, we got stuck at the Ukrainian border, where we witnessed the wonderful tradition of putting a whole lot of candles in graveyards during All Saints’ Day. At night we took many a wonderful picture without using a tripod—all thanks to the immense light sensitivity and optical stabilisers that modern cameras have. It was no use carrying my analogue camera at night: the photo film is 30 times less light-sensitive, and in semi-darkness there is no taking any half-decent photo without a tripod.&lt;/p&gt;

&lt;p&gt;If I saw a rapidly developing event, I would not even bother to take out the camera—each photo demanding two parameters (focus and exposure time) set, I would not be fast enough to take one. &lt;/p&gt;

&lt;p&gt;But at the same time, I felt film to be a blessing a disguise. Modern cameras are too powerful. You push the button—you get the photo you need, always. As a result, not only do you stop thinking about the how but also about the what. Film is hard to use, film makes you find a way. Analysing all the parameters and options available makes a good warm up exercise for your brain: you start looking for a better angle or composition. &lt;/p&gt;

&lt;p&gt;The grain and warm colours that film has are all the rage now. But personally, I didn’t see any real magic in them. That’s just what photos had been back in the days. Our parents were younger, and we were kids—we get nostalgic, of course. Exactly like pixel art is just the style of games childhood from our childhood. It doesn’t make a game better per se. Will our children value the effects produced by a bad phone matrix, a reminder of their warm past, as high as we do the grain and warm colours?&lt;/p&gt;

&lt;p&gt;My Digital Sabbath made me realise I would use my phone, not my big-ass digital camera, to take photos in my travels. I understood I had no need for the extra options it offered.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Watch
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frkil78l5oowguekac3io.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frkil78l5oowguekac3io.JPG" alt="Soviet Raketa watch" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the Digital Sabbath, I bought a &lt;a href="https://en.wikipedia.org/wiki/Raketa" rel="noopener noreferrer"&gt;Raketa&lt;/a&gt; (Rocket) soviet mechanical watch. Pity I didn’t manage to find a special &lt;a href="https://watchesyoucanafford.com/raketa-and-russian-24-hour-watch-review/" rel="noopener noreferrer"&gt;24-hour face version&lt;/a&gt; for polar explorers and divers.&lt;/p&gt;

&lt;p&gt;In my opinion, each era has a technology that serves as its symbol. The mechanical watch is the crown of the industrial era. Technology was not developed enough for portable devices to be precise, yet people did everything in their might—used their ingenuity, diligence and skill—to make the most of whatever they had. They did manage to make a watch based on pure mechanics. They used gimmickry such as &lt;a href="https://en.wikipedia.org/wiki/Jewel_bearing" rel="noopener noreferrer"&gt;having small rubies&lt;/a&gt; in the mechanism to decrease tension. That was why it was not until the advent of synthetic rubies that watches became cheaper and available to general public at the beginning of the 20th century.  &lt;/p&gt;

&lt;p&gt;My mechanical watch was like a small living creature—its heartbeat kept reminding me it was fragile and needed proper care. For your watch to work for long and show precise time, you need to wind it up every day at exactly the same time. I expected this necessity to turn into a burden, but it didn’t. On the contrary, this nice little duty gave me the opportunity to better feel the passing of time.&lt;/p&gt;

&lt;p&gt;Most importantly, time had become somewhat inaccurate. Contemporary quartz watches have a tiny error of a second per day. Synchronising via the internet, computers and phones don’t accumulate even that much error. It means we really are used to our watches being accurate. When we get to the railway station and there is five minutes left before the departure, we can be absolutely sure we will make it.&lt;/p&gt;

&lt;p&gt;A mechanical watch accumulates an error of up to a minute per day. It means your train may have already left the station because during the week the error has grown as big as five minutes. My watch having an unknown error was getting on my nerves throughout my travel, so I was always looking for sources of exact time to adjust my watch to.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4exi4bh0nsfljunfd6cy.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4exi4bh0nsfljunfd6cy.JPG" alt="quartz clock and alarm clock" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, one day my watch simply stopped, never to work again—no surprise, taking into account how old it was. It is indeed nice carrying a small mechanical life on your wrist; nevertheless, I went to a shop and bought myself a quartz watch (by that time I already knew there was no computer inside it, only simple electronics and mechanics). I do love my time exact; can’t do anything about it.   &lt;/p&gt;

&lt;p&gt;Yet I liked having a watch on my wrist. This childhood feeling had been long forgotten, and I was positively surprised that a watch did help you control the time. It is so much easier to take a look at your hand than to put your phone out of your pocket.&lt;/p&gt;

&lt;p&gt;After the Digital Sabbath, I decided to buy a smartwatch like Pebble or Android Wear.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Map and the Compass
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2yxm3yogfb434fq728fa.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2yxm3yogfb434fq728fa.JPG" alt="The map of Lucca city and compass" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The technology that is the symbol of our era? I would say, GPS and GLONASS. On the one hand, they use the most advanced things one can imagine—rockets to take satellites to the orbit, quantum physics to produce atomic clocks for the satellites, Einstein’s theory of relativity to compensate for the loss of time due to speed and gravity, computers to make complex calculations. On the other hand, unlike other brainy things easy-to-use maps are something that everyone on Earth needs. Satellites provide exact coordinates to every person, in any part of the planet, for free—so long as he or she has a cheap receiver. &lt;/p&gt;

&lt;p&gt;But during the Digital Sabbath, when I visited a new town, I would have to find a newspaper stand, buy a map and then closely read the names of the streets.&lt;/p&gt;

&lt;p&gt;During my preparation, I bought a compass. Primarily for the sake of the warm analogue style. But it actually proved itself useful—so long as you at least know the direction of the street you walk along, it will make reading the map easier.&lt;/p&gt;

&lt;p&gt;I didn’t have much difficulty using a GPS-less, paper map. Moreover, paper maps have their advantages, too: which one can be easily drawn and written upon—a digital or a paper one?&lt;/p&gt;

&lt;h1&gt;
  
  
  The Notepad
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6pid02pvghc4jxeb03of.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6pid02pvghc4jxeb03of.JPG" alt="Pen and notepad with Cyrillic vyaz" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;
During my trip I found old church with old Cyrillic calligraphy. It impress my so much, that I then created &lt;a&gt;@linguopunk&lt;/a&gt; account in Twitter for calligraphies like it.



&lt;p&gt;I wouldn’t have taken any pleasure in my Digital Sabbath if it wasn’t for the small spiral-bound notepad I bought to carry in my shirt pocket. It’s not that I had much choice either: digital life had degraded my memory, and I needed an external device to make notes in.&lt;/p&gt;

&lt;p&gt;Honestly, I don’t consider the bad memory the younger generations have to be that big of a problem. True, we have to search for information all over again, but it might be a good thing. Information is so quick to change now. What you learned yesterday might have already become all wrong today, while bad memory has you find the latest, most accurate data every time.&lt;/p&gt;

&lt;p&gt;I liked using the notepad. You always have a pen to spin in times of idleness. Unlike the touch displays that most phones have, a notepad provides for quick drawings. Another thing I liked was that everything you did at a certain moment was at the same place. The computer makes you follow a hierarchy that is alien to you: one application to search for video, and another for notes. In the notepad, there is only one timeline.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Thoughts
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffs9pu4n1bwypad5xk1z4.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffs9pu4n1bwypad5xk1z4.jpeg" alt="Andrey Sitnik sitting on the roof" width="800" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Boredom was the thing that scared me the most, so I did a lot of preparation: took a few thick books, drew up a schedule (when I leave one place for another) and made up several evening rituals to follow every day. The internet-less reality turned out to be a boredom-less one, too. Recreation does not require anything special—in the end, you can always go out and hunt for good photos. &lt;/p&gt;

&lt;p&gt;On the very first day, I went to bed early and woke up early—my biorhythms adjusted to the Sun in no time.&lt;/p&gt;

&lt;p&gt;Your battery is never low if you don’t have one. Nor will rain ever ruin your expensive phone. I always had time to think everything over and always felt the pleasant sensation of doing the right thing at the right time. My heart was filled with bliss and confidence.&lt;/p&gt;

&lt;p&gt;But soon I saw the difference between IT and other technologies. For example, a lack of electricity or water supply results in immediate discomfort. The internet does not—take a look at our grandparents, who do perfectly fine without computers. Yet without the internet, you sometimes feel so painfully nostalgic that it seems as if you have left your hometown and old friends and reminisce how good it was there.&lt;/p&gt;

&lt;p&gt;Digital technologies are something more than routine tools we use without thought. The digital world has grown into our souls, created whole new worlds for our imagination and creativity, introduced us to so many people we would have never met otherwise—without us noticing it.  &lt;/p&gt;

&lt;p&gt;The digital world needed no neuro-interfaces or cyberpunk-books to become part of us. The most painful thing about my Digital Sabbath was the feeling of something missing deep down inside.&lt;/p&gt;

&lt;p&gt;I came to the conclusion that IT hadn’t changed the world around, but created another, a parallel one. The reason we are always nervous and never have enough time is that we are living two lives now. It’s without a doubt difficult, yet how interesting it is to be living two times as much!&lt;/p&gt;

&lt;p&gt;By the middle of the month, I felt low—so big was my desire to code. It seemed I was wasting time instead of doing anything useful. When the pain was too bad, I would tell myself &lt;a href="https://en.wikipedia.org/wiki/Why_the_lucky_stiff" rel="noopener noreferrer"&gt;the story of _why&lt;/a&gt;, an iconic person in the ruby community. One day he disappeared from the internet, deleting all his vast contribution to the world of open source. His final tweet was “programming is rather thankless. u see your works become replaced by superior ones in a year. unable to run at all in a few more”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9ounyz75oekell4y42e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9ounyz75oekell4y42e.png" alt="GitHub contribution statistics with huge gap in Novermber" width="730" height="190"&gt;&lt;/a&gt;&lt;/p&gt;
My Digital Sabbath was in November, as it can be seen from the GitHub contribution graph.



&lt;p&gt;A little later, my anguish and longing faded into the background, but I got a feeling of my personality dissolving. The internet allows us to express our I much more clearly and intensely. We listen to music that we ourselves find interesting—it doesn’t matter if there is hardly any people in the world that like the same thing. We can pursue hobbies rare, yet intimate. The ability to communicate with anyone, beyond the boundaries of your city, results in relationships with people as congenial as it ever gets. But this all pales in comparison to the opportunities IT gives us in the domain of creativity, a person’s brightest form expression. Time spent without the internet returned me to my school days: you could only listen to whatever music you happened to get and read books that were available in the local store. My personality seemed to be merging with society, majority opinion, and popular music.&lt;/p&gt;

&lt;p&gt;The other side of being calm was a loss of motivation. The internet gets you to do things. You see the successes of other people and try to keep up with them. You value time much more dearly, as you know that any extra 10 minutes you can steal is a chanсe to read an interesting article from your archives that might produce a small change in you.  &lt;/p&gt;

&lt;p&gt;My Digital Sabbath made me re-evaluate my attitude towards social networks. Everyone knows that likes and statuses are no real communication. But when you are far from the place you live in, real communication is impossible. In a few weeks I started to miss my friends and relatives badly. It is true that in the modern world we rarely manage to find time for a heart-to-heart talk, but the little actions and pieces of information from Twitter and Facebook at least give us a connection to others, no matter how small. I may not know all the details, but I keep track of the lives my school friends from another city live. I do know about the most important things in their lives.&lt;/p&gt;

&lt;p&gt;Most importantly, social networks allowed for a new stratum, people who are always on the road, to develop. It’s not that people hadn’t moved to other countries before, but those had been a rare case. Even moving to another city meant having no close friends for a year or so, just because it would take time for your new friends to become close. Changing cities every month would mean having no close communication. Now, you can live far from home and yet feel a certain thread connecting you to your close ones. That’s why there are so many more people travelling non-stop nowadays. Citizens of no particular country. Almost everywhere in Asia or Europe I meet my friends and acquaintances who are living there just at the moment.&lt;/p&gt;

&lt;p&gt;What a strange thing—computers are nothing but little devices solving small-scale, mundane problems for us, but without them, I would be a completely different person.&lt;/p&gt;

&lt;h1&gt;
  
  
  The End
&lt;/h1&gt;

&lt;p&gt;It is December 6, 2013. A month has passed, and my Digital Sabbath is over. My excitement has kept me awake for the last 24 hours. There are hundreds of letters and thousands of RSS news waiting for me. I’m so emotional and busy I will not have more than four hours’ sleep a day, for the next three days, and instantly become a night owl, again. Yet I will be so glad to have returned.  &lt;/p&gt;

&lt;h1&gt;
  
  
  The Conclusion
&lt;/h1&gt;

&lt;p&gt;The ‘analogue’ world didn’t feel that much special and spiritual. The internet is not unlike a new flat—it seems empty and lacking soul. Not because the old one was better, but because the old one simply had many things to bring back good memories. The digital world is soon to get filled with our feelings. Just give it a little time.&lt;/p&gt;

&lt;p&gt;Despite the fact I am not going to do another month without the computers, I liked my Digital Sabbath. A month was too much though. Two weeks would have done just fine. I changed my attitude towards technology and the impact it has on society. I overcame my fear of boredom and now can easily take a cruise or visit places where there is no internet. I stopped worrying I never had enough time—it had become a logical thing, as I understood that with the internet I live two lives in parallel. I stopped getting fancy with the quality of photography. Taking pictures with my phone is good enough, I decided. I also bought a watch—smart, not mechanical though.      &lt;/p&gt;

&lt;p&gt;I would not recommend digital fasting to everyone, but a temporary abstinence of some sort seems a very right thing to do. All religions have compulsory fasting. Abstinence from meat in Christianity, or refraining from work in Judaism (btw, see &lt;a href="https://en.wikipedia.org/wiki/Eruv" rel="noopener noreferrer"&gt;eruv&lt;/a&gt;). The one I like the most is the &lt;a href="https://en.wikipedia.org/wiki/Mauna_(silence)" rel="noopener noreferrer"&gt;keeping of silence&lt;/a&gt; in Hinduism, for example, Mahatma Gandhi would be silent one day a week: he would be reading, thinking, or writing.&lt;/p&gt;

&lt;p&gt;It doesn’t take us much time to get used to a way of living and start doing things on autopilot. Our brain likes to save energy, so it turns our extremely voracious conscience as soon as it understands that everyday life can be done without it. As a result, our perception gets dull and replaced by thoughtless habits. Not letting it happen requires leaving the comfort zone, requires entering a new world, where you don’t know anything and have to start from scratch. You could take up a new hobby each month. Or travel from one city to another. Or do without things you are so used to, like having conversations or using computers—just for a little while.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Translated from &lt;a href="https://habr.com/post/232789/" rel="noopener noreferrer"&gt;Russian&lt;/a&gt; by Yaroslav Shtyrbu&lt;/small&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>mentalhealth</category>
      <category>technology</category>
      <category>culture</category>
    </item>
  </channel>
</rss>
