<?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: Anton Kovalev</title>
    <description>The latest articles on Forem by Anton Kovalev (@antonko).</description>
    <link>https://forem.com/antonko</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%2F2876466%2F20e625d1-9adb-4bfc-82c1-d8d2ed8f3ac9.jpg</url>
      <title>Forem: Anton Kovalev</title>
      <link>https://forem.com/antonko</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/antonko"/>
    <language>en</language>
    <item>
      <title>I Got Tired of Messy Text in Directus, So I Built a Typograf Button</title>
      <dc:creator>Anton Kovalev</dc:creator>
      <pubDate>Sat, 06 Dec 2025 19:19:54 +0000</pubDate>
      <link>https://forem.com/antonko/i-got-tired-of-messy-text-in-directus-so-i-built-a-typograf-button-4c8g</link>
      <guid>https://forem.com/antonko/i-got-tired-of-messy-text-in-directus-so-i-built-a-typograf-button-4c8g</guid>
      <description>&lt;p&gt;I care way too much about how text looks.&lt;/p&gt;

&lt;p&gt;If I see straight quotes instead of proper ones, random hyphens where a dash should be, no non-breaking spaces, slightly broken English next to slightly broken anything else — my brain immediately switches from «reading content» to «spot the typo game». And once you notice this stuff in a CMS, you start seeing it everywhere.&lt;/p&gt;

&lt;p&gt;We use Directus a lot, and at some point it became obvious:&lt;br&gt;
if the text is stored «ugly» in the admin panel, it will stay ugly everywhere it goes — website, emails, mobile app, PDFs, whatever. Nothing magically fixes it on the way.&lt;/p&gt;

&lt;p&gt;So I stopped complaining and wrote a tiny extension.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;The project is called &lt;code&gt;directus-extension-typograf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It’s a custom interface for Directus that behaves almost like a normal text field, but with one extra thing: a small «typography» button next to it.&lt;/p&gt;

&lt;p&gt;You type your content.&lt;br&gt;
You click the button.&lt;br&gt;
The extension runs the value through &lt;a href="https://github.com/typograf/typograf" rel="noopener noreferrer"&gt;Typograf&lt;/a&gt; using language-specific rules and puts the cleaned-up text back into the same field.&lt;/p&gt;

&lt;p&gt;No magic behind the scenes, no hidden pipeline — you see exactly what changed before you hit «Save».&lt;/p&gt;

&lt;p&gt;The interface supports different use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;single-line input for titles,&lt;/li&gt;
&lt;li&gt;multiline textarea for longer copy,&lt;/li&gt;
&lt;li&gt;Markdown,&lt;/li&gt;
&lt;li&gt;WYSIWYG with HTML.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part: HTML/Markdown structure is preserved, only the text nodes are touched.&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%2F0wutr6ig126otgyu564k.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%2F0wutr6ig126otgyu564k.png" alt=" " width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Why typography in the CMS, not on the frontend
&lt;/h3&gt;

&lt;p&gt;We did try the usual «fix it on render» approach before.&lt;/p&gt;

&lt;p&gt;Add a frontend helper, or a filter, or a nice higher-order component, pipe all visible text through it, and call it a day. On paper this sounds fine. In reality it turns into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one project uses the helper, another one doesn’t;&lt;/li&gt;
&lt;li&gt;emails and PDFs get the raw text;&lt;/li&gt;
&lt;li&gt;someone copies content straight from Directus into a presentation;&lt;/li&gt;
&lt;li&gt;the same field looks different depending on where it’s rendered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typography is deterministic. If you run it once at the source of truth — the CMS — you can stop thinking about it later. For editors the mental model is very simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;«I wrote a paragraph, pressed the button, checked the result, saved it. This is now the final version.»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s the whole idea.&lt;/p&gt;




&lt;h3&gt;
  
  
  What the button actually fixes
&lt;/h3&gt;

&lt;p&gt;Under the hood the extension relies on Typograf, which has rules for a bunch of languages (Russian, English, German and many others).&lt;/p&gt;

&lt;p&gt;You can either hard-code a language in the field settings or let the interface pick it automatically from a language code field in your translations.&lt;/p&gt;

&lt;p&gt;On the text level it does the things editors usually do manually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;converts straight quotes to proper ones, depending on the language;&lt;/li&gt;
&lt;li&gt;turns hyphens into dashes where it makes sense;&lt;/li&gt;
&lt;li&gt;adds non-breaking spaces in places that often break layouts;&lt;/li&gt;
&lt;li&gt;removes extra spaces and other small garbage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s not trying to be smart about meaning. It just removes the boring mechanical work that doesn’t really deserve human attention.&lt;/p&gt;




&lt;h3&gt;
  
  
  How it feels for editors
&lt;/h3&gt;

&lt;p&gt;From an editor’s point of view, nothing dramatic changes.&lt;/p&gt;

&lt;p&gt;They still see a familiar field, they still type the same way. The only difference is that, from time to time, they hit a small icon, watch the text tidy itself up, maybe tweak a word or two, and then save.&lt;/p&gt;

&lt;p&gt;There is no «mysterious backend process» silently rewriting their content later. Everything happens in front of them, at the moment they’re already focused on that text.&lt;/p&gt;

&lt;p&gt;For me that was important: the extension should not fight for control, it should just help.&lt;/p&gt;




&lt;h3&gt;
  
  
  If you want to try it
&lt;/h3&gt;

&lt;p&gt;The code and more details live here:&lt;br&gt;
👉 &lt;a href="https://github.com/antonko/directus-extension-typograf" rel="noopener noreferrer"&gt;https://github.com/antonko/directus-extension-typograf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re using Directus, work with multilingual content and get slightly annoyed by crooked quotes and weird spaces — you’ll probably enjoy having a «make it pretty» button right inside the CMS.&lt;/p&gt;

&lt;p&gt;And if you run into odd edge cases, especially with Markdown or specific languages, I’m always happy to hear about them and improve the extension.&lt;/p&gt;

</description>
      <category>directus</category>
      <category>typograf</category>
      <category>cms</category>
    </item>
    <item>
      <title>Blurhash and Directus: How to Add Blurred Image Loading</title>
      <dc:creator>Anton Kovalev</dc:creator>
      <pubDate>Mon, 17 Feb 2025 18:32:27 +0000</pubDate>
      <link>https://forem.com/antonko/blurhash-and-directus-how-to-add-blurred-image-loading-kco</link>
      <guid>https://forem.com/antonko/blurhash-and-directus-how-to-add-blurred-image-loading-kco</guid>
      <description>&lt;p&gt;&lt;a href="https://blurha.sh/" rel="noopener noreferrer"&gt;Blurhash&lt;/a&gt; is a compact text-based representation of an image that enables you to display an appealing blurred preview before the original fully loads. This technology not only makes the interface feel more responsive but also provides a more visually engaging waiting experience. Blurhash is an impressive and forward-looking development that offers new possibilities for web and mobile applications.&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%2Fphawpwwwivp8fbcfs518.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%2Fphawpwwwivp8fbcfs518.png" alt="Image description" width="800" height="648"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Implementing Blurhash in Directus has become extremely straightforward thanks to specialized plugins. Whether you're using Next.js, Flutter, or any other framework, the result will be equally compelling. Below, we'll walk through how to integrate this into your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use the directus-extension-blurhasher Plugin?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/antonko/directus-extension-blurhasher" rel="noopener noreferrer"&gt;directus-extension-blurhasher&lt;/a&gt; automatically generates a Blurhash for images upon upload and stores it in the database. You can choose a detail level (Low, Medium, High), which affects both the length of the Blurhash string and processing speed. The plugin also provides an option for full regeneration: on the next Directus restart, it recalculates the Blurhash for all previously uploaded images. Thanks to automatic migration upon installation, integration is virtually instantaneous.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the Plugin
&lt;/h2&gt;

&lt;p&gt;Through Docker&lt;/p&gt;

&lt;p&gt;If you use Docker, add the following snippet to your Dockerfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; directus/directus:10.10.4&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; root&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;corepack &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;pnpm &lt;span class="nb"&gt;install &lt;/span&gt;directus-extension-blurhasher
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have a Directus fork, just add the dependency:&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;directus-extension-blurhasher
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then restart Directus. The plugin will automatically perform a migration and be ready for use.&lt;/p&gt;

&lt;h2&gt;
  
  
  New Settings in Directus
&lt;/h2&gt;

&lt;p&gt;After installing the plugin, two new settings appear in Directus:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Blurhasher Detail Level: Sets the level of detail (Low, Medium, High). Higher levels produce more accurate blur but require more processing time.&lt;/li&gt;
&lt;li&gt;Blurhasher Regenerate on Restart: When enabled, instructs Directus to regenerate the Blurhash for all previously uploaded images on the next restart. Once the process is complete, this setting automatically turns off.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;After installing the plugin, any file request (for example, &lt;code&gt;GET https://localhost/files/{id}&lt;/code&gt;) returns a new blurhash field containing the generated Blurhash string. You can use this string in any frontend—Next.js, Flutter, or another framework—to display a blurred preview before the original image is fully loaded.&lt;/p&gt;

&lt;p&gt;Below is an example API response showing the blurhash field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bca3eab2-12c3-49fc-9ae9-ce6c91b81166"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"storage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"local"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"filename_disk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bca3eab2-12c3-49fc-9ae9-ce6c91b81166.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"filename_download"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"basta_1280х1280.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Basta 1280х1280"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image/jpeg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"folder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"uploaded_by"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3810105c-9a6c-41ec-bd43-867b9920bf77"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"created_on"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-12-26T14:46:27.462Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"modified_by"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"modified_on"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-12-26T14:46:28.367Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"charset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"filesize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"916978"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"width"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"height"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"embed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"focal_point_x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"focal_point_y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tus_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tus_data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"uploaded_on"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-12-26T14:46:28.014Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"blurhash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;":sIy@7}Q$fxHENf9n%R-=sX7Nxs.NHsms.R*aLR.Rkn$kBWVoJWXoMoeWBWCoeR+WCo1j?WXWDf6odfkWqoLxGWCWCj[WWj[ayj[s.WVWCoLa}j[jZjZsojtR+jss:a}WVa|"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Ffo8n3r0olx9vxgz82m4t.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%2Ffo8n3r0olx9vxgz82m4t.png" alt="Image description" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you have the generated blurhash string, all that’s left is to display it on your frontend. There are plenty of libraries that can help you do just that—links and documentation can be found in the &lt;a href="https://github.com/woltapp/blurhash" rel="noopener noreferrer"&gt;official BlurHash repository&lt;/a&gt;. Let’s keep pushing the boundaries of UX and make our interfaces as pleasant and responsive as possible!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Be sure to support the &lt;a href="https://github.com/antonko/directus-extension-blurhasher" rel="noopener noreferrer"&gt;project on GitHub&lt;/a&gt; and share your integration experiences!&lt;/p&gt;

</description>
      <category>blurhash</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>ui</category>
    </item>
  </channel>
</rss>
