<?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>DEV Community: Danilo</title>
    <description>The latest articles on DEV Community by Danilo (@danilo_z_j).</description>
    <link>https://dev.to/danilo_z_j</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F580730%2Fea0bf408-c90c-4fd9-a7ed-3916e65d2e37.png</url>
      <title>DEV Community: Danilo</title>
      <link>https://dev.to/danilo_z_j</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/danilo_z_j"/>
    <language>en</language>
    <item>
      <title>I turned a photo of my handwriting into a real font, then open-sourced the whole pipeline</title>
      <dc:creator>Danilo</dc:creator>
      <pubDate>Fri, 24 Jul 2026 07:54:20 +0000</pubDate>
      <link>https://dev.to/danilo_z_j/i-turned-a-photo-of-my-handwriting-into-a-real-font-then-open-sourced-the-whole-pipeline-m7m</link>
      <guid>https://dev.to/danilo_z_j/i-turned-a-photo-of-my-handwriting-into-a-real-font-then-open-sourced-the-whole-pipeline-m7m</guid>
      <description>&lt;p&gt;I wrote my alphabet in a spiral notebook, took one photo in dim light, and got an installable TTF out the other end. My computer now can type in my handwriting. The whole thing is open source (MIT), runs locally, and works as three layers: an npm library, a CLI, and a Claude Code skill on top.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/danilo-znamerovszkij/draw-your-font" rel="noopener noreferrer"&gt;github.com/danilo-znamerovszkij/draw-your-font&lt;/a&gt;&lt;br&gt;
Browser demo: &lt;a href="https://danilo-znamerovszkij.github.io/draw-your-font/" rel="noopener noreferrer"&gt;danilo-znamerovszkij.github.io/draw-your-font/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post is about why I built it and how the pipeline actually works.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;I always thought it would be so cool to have a custom font, designed by you. And every time I researched it, the answer was some version of "sure, if you're willing to suffer".&lt;/p&gt;

&lt;p&gt;Font editors want you to draw every glyph one by one with a tablet pen, or worse, with your touchpad. The tools that accept a photo of your handwriting are limited, and the main one (Calligraphr) wants $8/month for the full version. A subscription for my own handwriting!&lt;/p&gt;

&lt;p&gt;So, how hard could it be to just build it and open source it? Turns out, not that hard. Every piece has been open source for years: sharp for image processing, a JS port of potrace for vectorization, svg2ttf for assembly. Nobody had wired them together into one zero-install package.&lt;/p&gt;

&lt;p&gt;On the open-source side the closest thing is builtree/handwrite: Python, and it requires FontForge and potrace installed system-wide. That's a real barrier. Most people who want their handwriting as a font are not going to brew-install a font editor first.&lt;/p&gt;

&lt;p&gt;So the gap I aimed at was specific: pure npm, no system dependencies, and tolerant of freeform photos instead of demanding a scanner and a perfectly aligned template. Then I wrapped it in a reusable Claude Code skill that does the heavy lifting: you hand it a photo, it hands you a font.&lt;/p&gt;
&lt;h2&gt;
  
  
  Make your font
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add danilo-znamerovszkij/draw-your-font
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then drag a photo into Claude Code and say "make my font". That's it. Claude finds your letters in the photo, labels them with vision, builds the font, shows you a preview, and then critiques its own work before you have to.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Finds and labels&lt;/strong&gt; your letters in a messy photo, and knows a shadow blob from ink.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Critiques its own output.&lt;/strong&gt; "Your g traced badly" comes with the crop and a suggested fix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refines by talking.&lt;/strong&gt; "Make it rounder", "a bit bolder", "how readable is it?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The photo goes to the model for labeling only. The geometry never leaves your machine. Node 18+, nothing else.&lt;/p&gt;
&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Six steps, all deterministic code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Adaptive threshold.&lt;/strong&gt; A global threshold dies on real photos, because a page shadow makes half the image darker than the ink in the other half. Thresholding against the local background is why dim light survives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blob detection.&lt;/strong&gt; Connected components find every ink region. The dot on an i gets merged with its stem by proximity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Labeling.&lt;/strong&gt; Something has to say "blob 14 is a lowercase g". The skill reads a numbered contact sheet with vision, which is why messy freeform photos work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vectorization.&lt;/strong&gt; Potrace, the same engine inside FontForge and Inkscape. The AI never draws a single curve.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metrics.&lt;/strong&gt; The step that separates "font" from "ransom note". Every character gets a vertical band in a shared em square, so your g hangs below the line and your o stays smaller than your O.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assembly.&lt;/strong&gt; Outlines plus metrics become TTF, WOFF/WOFF2, and a ready @font-face snippet.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Put it on your website
&lt;/h2&gt;

&lt;p&gt;The TTF is for your laptop. For your website, ask for WOFF2 and you get a web font plus the @font-face snippet.&lt;/p&gt;

&lt;p&gt;The headline on the demo page is set in a font I made in minutes, from the exact photo in the demo video: &lt;a href="https://danilo-znamerovszkij.github.io/draw-your-font/" rel="noopener noreferrer"&gt;danilo-znamerovszkij.github.io/draw-your-font/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I think this matters more now than it used to. Feeds are full of AI slop. Everything is generated in the same voice and set in the same fonts, page after page, post after post. So a site rendered in your actual handwriting, with the wobble of your real pen in every letter, is a personal touch that's hard to fake. It costs you one photo.&lt;/p&gt;
&lt;h2&gt;
  
  
  One rough edge
&lt;/h2&gt;

&lt;p&gt;Write freeform and some letters can sit a little higher or lower than they should. If you want a cleaner result, print the built-in template (&lt;code&gt;npx draw-your-font template -o template.pdf&lt;/code&gt;) and write in its grid, or just rule a few light pencil lines with an old ruler and write on those. But honestly, freeform works fine. My whole demo is one crooked notebook photo.&lt;/p&gt;
&lt;h2&gt;
  
  
  The fine print
&lt;/h2&gt;

&lt;p&gt;The skill sits on a plain npm CLI with zero system dependencies, so you can run the whole thing without any AI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx draw-your-font make photo.jp![img.png]&lt;span class="o"&gt;(&lt;/span&gt;img.png&lt;span class="o"&gt;)&lt;/span&gt;g &lt;span class="nt"&gt;--chars&lt;/span&gt; &lt;span class="s2"&gt;"ABCabc"&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"My Hand"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's trickier than talking to Claude. You type every character in writing order, and there's no one to catch a bad trace for you. But it's there, and it's fully deterministic. There's also a browser demo that runs the pipeline client-side (potrace compiled to WASM), nothing uploaded.&lt;/p&gt;

&lt;p&gt;Dark pen, letters not touching. That's the only real requirement; my own hero photo has spiral binding, a page shadow, and bad light. The font you generate is 100% yours, commercial use included.&lt;/p&gt;

&lt;p&gt;If you find it useful, please consider starring the repo so more people can find it. And if you make a font from your own hand, I'd genuinely love to see it.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>ai</category>
      <category>showdev</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Danilo</dc:creator>
      <pubDate>Sat, 31 Jan 2026 19:02:04 +0000</pubDate>
      <link>https://dev.to/danilo_z_j/-3414</link>
      <guid>https://dev.to/danilo_z_j/-3414</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://dev.to/danilo_z_j/minmax-dual-range-sliders-for-daisyui-theme-aware-40jh" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" 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%2Ftyrdag6sgd54bddgj0gj.png" height="233" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://dev.to/danilo_z_j/minmax-dual-range-sliders-for-daisyui-theme-aware-40jh" rel="noopener noreferrer" class="c-link"&gt;
            Min/Max Dual-Range Sliders for DaisyUI (Theme-Aware) - DEV Community
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            DaisyUI has a range component, but it doesn’t support dual-handle (min/max) sliders.  That becomes a...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" 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%2F8j7kvp660rqzt99zui8e.png" width="300" height="299"&gt;
          dev.to
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>daisyui</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Min/Max Dual-Range Sliders for DaisyUI (Theme-Aware)</title>
      <dc:creator>Danilo</dc:creator>
      <pubDate>Sat, 31 Jan 2026 19:01:33 +0000</pubDate>
      <link>https://dev.to/danilo_z_j/minmax-dual-range-sliders-for-daisyui-theme-aware-40jh</link>
      <guid>https://dev.to/danilo_z_j/minmax-dual-range-sliders-for-daisyui-theme-aware-40jh</guid>
      <description>&lt;p&gt;DaisyUI has a &lt;code&gt;range&lt;/code&gt; component, but it doesn’t support dual-handle (min/max) sliders.&lt;/p&gt;

&lt;p&gt;That becomes a limitation when building things like price filters, faceted search, dashboards, or admin tools.&lt;/p&gt;

&lt;p&gt;This isn’t solvable with native HTML or CSS alone. A proper min/max slider requires JavaScript for multiple thumbs, value constraints, keyboard and touch interaction, and accessibility.&lt;/p&gt;

&lt;p&gt;Once you accept that JS is required, there’s another issue:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;there’s no obvious, DaisyUI-friendly solution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What typically happens is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a slider library is introduced (often noUiSlider)&lt;/li&gt;
&lt;li&gt;its generated DOM is inspected&lt;/li&gt;
&lt;li&gt;styles are overridden to match DaisyUI&lt;/li&gt;
&lt;li&gt;that setup gets copied into the next project&lt;/li&gt;
&lt;li&gt;slightly differently each time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve done this more than once. It works, but it’s repetitive and not very reusable.&lt;/p&gt;

&lt;h3&gt;
  
  
  The idea
&lt;/h3&gt;

&lt;p&gt;Instead of repeating that wiring, I packaged it once:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/danilo-znamerovszkij/daisy-dual-range" rel="noopener noreferrer"&gt;&lt;strong&gt;daisy-dual-range&lt;/strong&gt;&lt;br&gt;
&lt;/a&gt;&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%2Fzpgyj8eplj22y0d31jdf.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%2Fzpgyj8eplj22y0d31jdf.png" alt="daisy-dual-range" width="800" height="584"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uses noUiSlider for behavior&lt;/li&gt;
&lt;li&gt;uses DaisyUI CSS variables for styling&lt;/li&gt;
&lt;li&gt;keeps styles scoped (no global overrides)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s essentially a small integration layer between the two.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it provides
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;dual-handle slider by default&lt;/li&gt;
&lt;li&gt;theme-aware via DaisyUI tokens (primary, accent, error, etc.)&lt;/li&gt;
&lt;li&gt;visual parity with DaisyUI range inputs&lt;/li&gt;
&lt;li&gt;automatic adaptation when the theme changes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why a wrapper?
&lt;/h3&gt;

&lt;p&gt;You can wire this up manually if you want.&lt;br&gt;
The wrapper exists because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the choice of slider library isn’t obvious&lt;/li&gt;
&lt;li&gt;the DaisyUI ↔ noUiSlider integration is non-trivial&lt;/li&gt;
&lt;li&gt;the same setup tends to be re-implemented across projects&lt;/li&gt;
&lt;li&gt;Packaging the pattern once reduces that duplication.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Scope
&lt;/h3&gt;

&lt;p&gt;This is intentionally small.&lt;br&gt;
It’s not a DaisyUI core component, a Tailwind plugin, or a framework abstraction, just a focused utility for a missing use case.&lt;/p&gt;

&lt;p&gt;If you run into this problem while using DaisyUI, this is one option to consider.&lt;/p&gt;

</description>
      <category>daisyui</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>The Practical Guide to Optimizing @font-face</title>
      <dc:creator>Danilo</dc:creator>
      <pubDate>Mon, 24 Nov 2025 16:48:07 +0000</pubDate>
      <link>https://dev.to/danilo_z_j/the-practical-guide-to-optimizing-font-face-3cgd</link>
      <guid>https://dev.to/danilo_z_j/the-practical-guide-to-optimizing-font-face-3cgd</guid>
      <description>&lt;p&gt;Web fonts are one of the easiest places to lose performance—and one of the easiest to fix. Most sites ship multiple formats, oversized files, or unnecessary weights. Here's a compact guide to optimizing your fonts the right way.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Use woff2 First (and Preferably Only)
&lt;/h2&gt;

&lt;p&gt;woff2 is the smallest, fastest, and most compressed format.&lt;br&gt;
Unless you must support IE11 (you probably don’t), you can safely drop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;eot&lt;/li&gt;
&lt;li&gt;svg&lt;/li&gt;
&lt;li&gt;ttf&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A clean modern declaration looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@font-face {
  font-family: 'Poppins';
  src: url('Poppins.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you still support older environments, fallbacks are fine—but keep them minimal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@font-face {
  font-family: 'Poppins';
  src: url('Poppins.woff2') format('woff2'),
       url('Poppins.woff') format('woff');
  font-weight: 400;
  font-display: swap;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Only Include the Weights You Actually Use
&lt;/h2&gt;

&lt;p&gt;Many projects include full font families (100–900) when they only use 400 and 600.&lt;/p&gt;

&lt;p&gt;Audit your CSS → keep only what you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Always Use &lt;code&gt;font-display: swap&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;It eliminates invisible text (FOIT) and improves perceived performance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;font-display: swap;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures text renders immediately using a fallback font, then swaps when the custom font loads.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Subset Your Fonts
&lt;/h2&gt;

&lt;p&gt;Most font files include far more glyphs than you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cyrillic&lt;/li&gt;
&lt;li&gt;Arabic&lt;/li&gt;
&lt;li&gt;Vietnamese&lt;/li&gt;
&lt;li&gt;Symbols&lt;/li&gt;
&lt;li&gt;Full Unicode ranges&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your site uses only Latin characters, subsetting can reduce file sizes by up to 70–90%.&lt;/p&gt;

&lt;p&gt;Two great tools:&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1. Transfonter: &lt;a href="https://transfonter.org/" rel="noopener noreferrer"&gt;https://transfonter.org/&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;(Upload → subset → download optimized woff2)&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2. Google Webfonts Helper: &lt;a href="https://gwfh.mranftl.com/fonts" rel="noopener noreferrer"&gt;https://gwfh.mranftl.com/fonts&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;(Self-host Google Fonts + get correctly pre-built subsets)&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Inline Preload for Critical Fonts
&lt;/h2&gt;

&lt;p&gt;For your main UI font, consider preloading:&lt;/p&gt;



&lt;h3&gt;
  
  
  Final Checklist
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use woff2 (and fallback to woff)&lt;/li&gt;
&lt;li&gt;Remove eot, svg, and ttf unless required&lt;/li&gt;
&lt;li&gt;Keep only the weights you use&lt;/li&gt;
&lt;li&gt;Always include &lt;code&gt;font-display: swap&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Subset using Transfonter or Google Webfonts Helper&lt;/li&gt;
&lt;li&gt;Preload critical fonts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Small changes → big wins. Typography stays beautiful, performance gets faster, and you ship fewer kilobytes.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>css</category>
      <category>font</category>
    </item>
    <item>
      <title>Improving Core Web Vitals: LCP Trick</title>
      <dc:creator>Danilo</dc:creator>
      <pubDate>Mon, 17 Nov 2025 17:50:18 +0000</pubDate>
      <link>https://dev.to/danilo_z_j/core-web-vitals-top-trick-4i1</link>
      <guid>https://dev.to/danilo_z_j/core-web-vitals-top-trick-4i1</guid>
      <description>&lt;p&gt;Ranking high on Google directly depends on your Core Web Vitals.&lt;/p&gt;

&lt;p&gt;For me, one of the most impactful thing was this:&lt;/p&gt;

&lt;p&gt;Preload your LCP&lt;/p&gt;

&lt;p&gt;Determine what your Largest Contentful Paint element is, and add &lt;code&gt;&amp;lt;link rel="preload" href="..."&amp;gt;&lt;/code&gt;&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>seo</category>
      <category>webdev</category>
      <category>cwv</category>
    </item>
    <item>
      <title>Sunburst Chart in JS | ECharts x D3 x Plotly</title>
      <dc:creator>Danilo</dc:creator>
      <pubDate>Tue, 11 Nov 2025 14:56:49 +0000</pubDate>
      <link>https://dev.to/danilo_z_j/sunburst-chart-in-js-echarts-x-d3-x-plotly-16i6</link>
      <guid>https://dev.to/danilo_z_j/sunburst-chart-in-js-echarts-x-d3-x-plotly-16i6</guid>
      <description>&lt;p&gt;I just wanted to plot my data on a sunburst chart. I assumed choosing a library would be one ChatGPT question away... but it wasn't. There were at least a dozen of alternatives to consider.&lt;/p&gt;

&lt;p&gt;Spoiler alert: I went with Apache Echarts. Here's why.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. D3.js - the safe choice
&lt;/h3&gt;

&lt;p&gt;D3.js is the most popular and familiar option. I’ve used it before. But could it handle a sunburst chart cleanly?&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%2Fwokcrglwm4f0mwxbf2oi.gif" 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%2Fwokcrglwm4f0mwxbf2oi.gif" alt="D3 Sunburst demo" width="400" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I found a demo &lt;a href="https://observablehq.com/@d3/zoomable-sunburst" rel="noopener noreferrer"&gt;here&lt;/a&gt;, but it seemed too complex with generating the arc, computing the layout, etc, it didn’t feel like the obvious choice for this project.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Plotly - ChatGPT's recommendation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://plotly.com/javascript/sunburst-charts/" rel="noopener noreferrer"&gt;Plotly&lt;/a&gt; does support sunburst charts, but the transitions and label visibility looked too clumsy:&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%2Ff9951adyjf21fjdz8uj4.gif" 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%2Ff9951adyjf21fjdz8uj4.gif" alt="Plotly Sunburst demo" width="400" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. ECharts 👑
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://echarts.apache.org/en/option.html#series-sunburst" rel="noopener noreferrer"&gt;Apache Echarts&lt;/a&gt; is free, simple to use, and the default demos already looked great. The data structure is clean and intuitive, smooth transitions, minimal config required. It was the clear winner.&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%2F7lar3fywj04aeg06t9t2.gif" 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%2F7lar3fywj04aeg06t9t2.gif" alt="Echarts Sunburst demo" width="400" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick proof of concept — Claude + ECharts
&lt;/h3&gt;

&lt;p&gt;Before setting up the full project (I wrote earlier about choosing Vite), I wanted a quick proof of concept.&lt;/p&gt;

&lt;p&gt;So I pasted the data into Claude and said:&lt;br&gt;
“Using ECharts, visualize this data as a sunburst chart.”&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%2Fvlertpf3v9j73cc8nuyi.gif" 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%2Fvlertpf3v9j73cc8nuyi.gif" alt="Claude Demo" width="400" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After 2 minutes I had a functioning sunburst chart with my data.&lt;/p&gt;

&lt;p&gt;Of course, the real project needed more refinement, customization, and performance work.&lt;br&gt;
But having a working prototype in minutes made the choice obvious.&lt;/p&gt;

&lt;p&gt;Data format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const baseData = [
  {
    name: 'Parent 1',
    children: [
      {
        name: 'Child 1',
        children: [
          { name: 'Grandchild 1', value: 1 },
          { name: 'Grandchild 2', value: 1 },
          ...
        ]
      },
  ...
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see the final result: &lt;a href="https://github.com/danilo-znamerovszkij/c-atlas" rel="noopener noreferrer"&gt;the repo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>datascience</category>
      <category>showdev</category>
    </item>
    <item>
      <title>🚀 Best Frontend Performance Guide

I was going through my old bookmarks, and this article is honestly still one of the best resources on frontend performance

https://www.smashingmagazine.com/2021/01/front-end-performance-2021-free-pdf-checklist/</title>
      <dc:creator>Danilo</dc:creator>
      <pubDate>Mon, 10 Nov 2025 11:04:40 +0000</pubDate>
      <link>https://dev.to/danilo_z_j/best-frontend-performance-guide-i-was-going-through-my-old-bookmarks-and-this-article-is-227d</link>
      <guid>https://dev.to/danilo_z_j/best-frontend-performance-guide-i-was-going-through-my-old-bookmarks-and-this-article-is-227d</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.smashingmagazine.com/2021/01/front-end-performance-2021-free-pdf-checklist/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Farchive.smashing.media%2Fassets%2F344dbf88-fdf9-42bb-adb4-46f01eedd629%2F08a226c5-5a9a-4bd2-bba7-dad7e74f69e9%2Fadaptive-media-serving-opt.png" height="389" class="m-0" width="799"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.smashingmagazine.com/2021/01/front-end-performance-2021-free-pdf-checklist/" rel="noopener noreferrer" class="c-link"&gt;
            Front-End Performance Checklist 2021 (PDF, Apple Pages, MS Word) — Smashing Magazine
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Let’s make 2021... fast! An annual front-end performance checklist, with everything you need to know to create fast experiences on the web today, from metrics to tooling and CSS/JavaScript techniques.

          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.smashingmagazine.com%2Fimages%2Ffavicon%2Ffavicon.ico" width="32" height="32"&gt;
          smashingmagazine.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>performance</category>
      <category>frontend</category>
      <category>resources</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Clamp CSS in 2025 | Why I Stopped Writing Media Queries For Small Tweaks</title>
      <dc:creator>Danilo</dc:creator>
      <pubDate>Thu, 06 Nov 2025 14:06:55 +0000</pubDate>
      <link>https://dev.to/danilo_z_j/clamp-css-in-2025-why-i-stopped-writing-media-queries-for-small-tweaks-7fk</link>
      <guid>https://dev.to/danilo_z_j/clamp-css-in-2025-why-i-stopped-writing-media-queries-for-small-tweaks-7fk</guid>
      <description>&lt;p&gt;Media queries still work.&lt;/p&gt;

&lt;p&gt;But they’re not always the best tool when it comes to small layout changes.&lt;/p&gt;

&lt;p&gt;I ran into this while building a popup that needed to shrink smoothly between 750px and 950px. I added three media queries. It felt clunky.&lt;/p&gt;

&lt;p&gt;That’s when I gave &lt;code&gt;clamp()&lt;/code&gt; another look.&lt;/p&gt;

&lt;p&gt;Turns out, clamp() lets you describe responsive behavior in one line. It’s supported by &lt;a href="https://caniuse.com/?search=clamp()" rel="noopener noreferrer"&gt;96% of browsers&lt;/a&gt; and works for any CSS property that accepts a unit (font, spacing, etc.)&lt;/p&gt;

&lt;p&gt;The syntax looks like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;font-size: clamp(16px, 2vw, 32px);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;or if you're using rem&lt;/p&gt;

&lt;p&gt;&lt;code&gt;font-size: clamp(1rem, 2vw, 2rem);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Never go below 16px&lt;/li&gt;
&lt;li&gt;Never exceed 32px&lt;/li&gt;
&lt;li&gt;In between, scale based on viewport width&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s simple, except tuning the values feels awkward. The “preferred” value must be a fluid unit like vw or vmin, and the curve is linear between min and max.&lt;/p&gt;

&lt;p&gt;There are many small tools, I personally like this one to preview and fine-tune clamp expressions: &lt;a href="https://design.dev/tools/clamp-generator/" rel="noopener noreferrer"&gt;https://design.dev/tools/clamp-generator/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>css</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Why You Should Try Vite For Your Next Project (and Forget About Webpack)</title>
      <dc:creator>Danilo</dc:creator>
      <pubDate>Tue, 04 Nov 2025 12:21:18 +0000</pubDate>
      <link>https://dev.to/danilo_z_j/why-you-should-try-vite-for-your-next-project-and-forget-about-webpack-33dh</link>
      <guid>https://dev.to/danilo_z_j/why-you-should-try-vite-for-your-next-project-and-forget-about-webpack-33dh</guid>
      <description>&lt;p&gt;For years, I lived in Webpack configs. Every small project felt like booting a factory for one cup of coffee. Then I tried Vite. Two minutes later, I had a working setup. No waiting. No dependency hell.&lt;/p&gt;

&lt;p&gt;At its core, frontend isn’t about frameworks. It’s about rendering data into something humans can see, understand, and interact with. For my project, a simple data visualization app, I didn’t need another layer of abstraction. I still wanted a few modern comforts: code splitting, hot reload, fast bundling, minified JS. But not if it meant fighting config files for half a day.&lt;/p&gt;

&lt;h3&gt;
  
  
  The stack:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Vite — instant startup, zero config, ES modules by default&lt;/li&gt;
&lt;li&gt;TypeScript — strong typing, fewer surprises&lt;/li&gt;
&lt;li&gt;SCSS — clean syntax, mixins, control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What impressed me most was how production-ready Vite is right out of the box. I generally agree that you should use the stack you’re comfortable with, but Webpack was never about comfort to begin with.&lt;/p&gt;

&lt;p&gt;Every few years, frontend tools get heavier than the code they build. From that perspective, Vite feels like a breath of fresh air. For future small projects — experiments, visualizers, ideas — this is the tool I’ll reach for again.&lt;/p&gt;

&lt;p&gt;🔗 Project repo: &lt;a href="https://github.com/danilo-znamerovszkij/c-atlas" rel="noopener noreferrer"&gt;github.com/danilo-znamerovszkij/c-atlas&lt;/a&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>webdev</category>
      <category>vite</category>
      <category>webpack</category>
    </item>
    <item>
      <title>Export Chrome tabs as plain text or JSON (tiny tool I made)</title>
      <dc:creator>Danilo</dc:creator>
      <pubDate>Sun, 20 Jul 2025 17:48:04 +0000</pubDate>
      <link>https://dev.to/danilo_z_j/export-chrome-tabs-as-plain-text-or-json-tiny-tool-i-made-22k0</link>
      <guid>https://dev.to/danilo_z_j/export-chrome-tabs-as-plain-text-or-json-tiny-tool-i-made-22k0</guid>
      <description>&lt;p&gt;I had too many Chrome tabs open (100+), and I wanted to ask ChatGPT to help me prioritize.&lt;br&gt;
But I couldn’t easily copy them all.&lt;/p&gt;

&lt;p&gt;So I made a tiny Chrome extension that dumps all open tabs — titles and URLs — in plain text or JSON.&lt;br&gt;
Click → copy → done.&lt;/p&gt;

&lt;p&gt;It’s super minimal. Just helped me get the list out fast.&lt;/p&gt;

&lt;p&gt;Open source here: &lt;a href="https://github.com/danilo-znamerovszkij/TabsDump" rel="noopener noreferrer"&gt;https://github.com/danilo-znamerovszkij/TabsDump&lt;/a&gt; ⭐&lt;/p&gt;

</description>
      <category>extensions</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Figma MCP Server Guide</title>
      <dc:creator>Danilo</dc:creator>
      <pubDate>Fri, 21 Mar 2025 16:04:29 +0000</pubDate>
      <link>https://dev.to/danilo_z_j/figma-mcp-server-guide-2a18</link>
      <guid>https://dev.to/danilo_z_j/figma-mcp-server-guide-2a18</guid>
      <description>&lt;p&gt;This guide walks you through a complete Figma → MCP Server workflow so you can streamline your design-to-code pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Get Your API Token
&lt;/h2&gt;

&lt;p&gt;Figma won’t let MCP fetch designs unless you provide an API key.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Figma → Settings → Security → Personal Access Tokens&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Generate a new token
&lt;/li&gt;
&lt;li&gt;Copy it somewhere safe—you’ll need it shortly
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 2: Run MCP Server
&lt;/h2&gt;

&lt;p&gt;Once you have your token, start the server by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx figma-developer-mcp &lt;span class="nt"&gt;--figma-api-key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YOUR_FIGMA_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Connect MCP Server with Cursor
&lt;/h2&gt;

&lt;p&gt;If you're using &lt;strong&gt;Cursor&lt;/strong&gt; for AI-assisted development, add this to your settings:&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;"mcpServers"&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;"figma-developer-mcp"&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;"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;"sse"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3333/sse"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"FIGMA_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_FIGMA_API_KEY"&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;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;h2&gt;
  
  
  Step 4: Verify the Connection
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Cursor&lt;/strong&gt; and check if the MCP Server is recognized.
&lt;/li&gt;
&lt;li&gt;If everything is set up correctly, you should see &lt;strong&gt;successful API calls&lt;/strong&gt; when you request a design.
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 5: Install Live Preview Plugin
&lt;/h2&gt;

&lt;p&gt;To see &lt;strong&gt;real-time HTML previews&lt;/strong&gt;, install the &lt;strong&gt;Live Preview&lt;/strong&gt; plugin in &lt;strong&gt;VSCode&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;VSCode&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Extensions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;Live Preview&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Install and activate it
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now you can view live updates as you implement your email markup!&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>figma</category>
      <category>cursor</category>
    </item>
    <item>
      <title>Debug JS events with monitorEvents</title>
      <dc:creator>Danilo</dc:creator>
      <pubDate>Thu, 02 Nov 2023 15:35:04 +0000</pubDate>
      <link>https://dev.to/danilo_z_j/debug-js-events-with-monitorevents-ge9</link>
      <guid>https://dev.to/danilo_z_j/debug-js-events-with-monitorevents-ge9</guid>
      <description>&lt;p&gt;It can be challenging sometimes to debug events, because of how many browsers and devices there are, so I wanted to share one underrated feature called &lt;code&gt;monitorEvents&lt;/code&gt; that can track events on specific elements in the document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Log all events firing on the body element
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;monitorEvents(document.body)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Log all mouse events on the body
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;monitorEvents(document.body, 'mouse')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Log all events on all input elements
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;monitorEvents(document.body.querySelectorAll('input'))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>debugging</category>
      <category>console</category>
    </item>
  </channel>
</rss>
