<?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: Juan Martin</title>
    <description>The latest articles on DEV Community by Juan Martin (@tinchox5).</description>
    <link>https://dev.to/tinchox5</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%2F139960%2F6df2ccf3-5a97-4a9f-9f3b-add197e8e5fb.jpeg</url>
      <title>DEV Community: Juan Martin</title>
      <link>https://dev.to/tinchox5</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tinchox5"/>
    <language>en</language>
    <item>
      <title>I built a paint app where the PNG is the canvas (no &lt;canvas&gt; element)
snapDOM is normally stateless — every capture re-clones the live element.

https://snapdom.dev/labs/paint-canvas/</title>
      <dc:creator>Juan Martin</dc:creator>
      <pubDate>Wed, 22 Jul 2026 02:28:03 +0000</pubDate>
      <link>https://dev.to/tinchox5/i-built-a-paint-app-where-the-png-is-the-canvas-no-element-snapdom-is-normally-stateless-ck1</link>
      <guid>https://dev.to/tinchox5/i-built-a-paint-app-where-the-png-is-the-canvas-no-element-snapdom-is-normally-stateless-ck1</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://snapdom.dev/labs/paint-canvas/" 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%2Fsnapdom.dev%2Fassets%2Fog-card.jpg" height="420" 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://snapdom.dev/labs/paint-canvas/" rel="noopener noreferrer" class="c-link"&gt;
            Paint Canvas — The PNG Is the Canvas — SnapDOM Labs
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            A paint app with no &amp;lt;canvas&amp;gt; element — a SnapDOM plugin accumulates every stroke onto the last captured clone.
          &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%2Fsnapdom.dev%2Fassets%2Ffavicon%2Ffavicon-96x96.png" width="96" height="96"&gt;
          snapdom.dev
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Juan Martin</dc:creator>
      <pubDate>Tue, 14 Jul 2026 02:59:04 +0000</pubDate>
      <link>https://dev.to/tinchox5/-1jm0</link>
      <guid>https://dev.to/tinchox5/-1jm0</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/tinchox5/why-snapdom-beats-html2canvas-for-dom-to-image-capture-14ch" class="crayons-story__hidden-navigation-link"&gt;Why SnapDOM Beats html2canvas for DOM-to-Image Capture&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/tinchox5" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F139960%2F6df2ccf3-5a97-4a9f-9f3b-add197e8e5fb.jpeg" alt="tinchox5 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/tinchox5" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Juan Martin
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Juan Martin
                
              
              &lt;div id="story-author-preview-content-4137182" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/tinchox5" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F139960%2F6df2ccf3-5a97-4a9f-9f3b-add197e8e5fb.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Juan Martin&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/tinchox5/why-snapdom-beats-html2canvas-for-dom-to-image-capture-14ch" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 14&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/tinchox5/why-snapdom-beats-html2canvas-for-dom-to-image-capture-14ch" id="article-link-4137182"&gt;
          Why SnapDOM Beats html2canvas for DOM-to-Image Capture
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/html"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;html&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/tinchox5/why-snapdom-beats-html2canvas-for-dom-to-image-capture-14ch" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;4&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/tinchox5/why-snapdom-beats-html2canvas-for-dom-to-image-capture-14ch#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Why SnapDOM Beats html2canvas for DOM-to-Image Capture</title>
      <dc:creator>Juan Martin</dc:creator>
      <pubDate>Tue, 14 Jul 2026 00:40:20 +0000</pubDate>
      <link>https://dev.to/tinchox5/why-snapdom-beats-html2canvas-for-dom-to-image-capture-14ch</link>
      <guid>https://dev.to/tinchox5/why-snapdom-beats-html2canvas-for-dom-to-image-capture-14ch</guid>
      <description>&lt;p&gt;Capturing a slice of the DOM as an image is one of those deceptively hard problems in frontend engineering. For years, &lt;a href="https://html2canvas.hertzen.com/" rel="noopener noreferrer"&gt;html2canvas&lt;/a&gt; has been the default answer. It works, it's battle-tested, and it's everywhere. But if you've ever pushed it hard — large trees, custom fonts, shadow DOM, or high-DPI exports — you already know where the cracks are. &lt;a href="https://github.com/zumerlab/snapdom" rel="noopener noreferrer"&gt;SnapDOM&lt;/a&gt; is a newer take on the same problem, and in most of the ways that matter for real applications, it's simply a better tool. Here's a technical breakdown of why.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/U7peCdBiFy8"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The core architectural difference
&lt;/h2&gt;

&lt;p&gt;html2canvas works by &lt;strong&gt;re-implementing the browser's rendering engine in JavaScript&lt;/strong&gt;. It walks the DOM, reads computed styles, and then manually paints each element onto a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;. That's an enormous surface area to get right: every CSS property, every layout quirk, every edge case in text rendering has to be reproduced by hand. This is why html2canvas ships with a long list of "known unsupported CSS properties" — it can only render what its authors have explicitly taught it to render.&lt;/p&gt;

&lt;p&gt;SnapDOM takes a fundamentally different route. It serializes the target node into an &lt;strong&gt;inlined SVG&lt;/strong&gt; using the &lt;code&gt;&amp;lt;foreignObject&amp;gt;&lt;/code&gt; element, then rasterizes that SVG through the browser's &lt;em&gt;native&lt;/em&gt; rendering pipeline. In other words, instead of re-implementing the browser, it hands the work back to the browser. The practical consequence is huge: if the browser can display it, SnapDOM can generally capture it — gradients, filters, blend modes, transforms, and modern CSS features included — without anyone having to write bespoke support for each one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Because SnapDOM leans on native rasterization rather than a hand-rolled paint loop in JS, it avoids a large class of expensive per-element JavaScript work. For typical UI captures the difference is very noticeable, and it scales better as the node count grows. html2canvas's cost climbs with the complexity of the tree because every node is processed by its interpreter; SnapDOM's serialize-then-rasterize approach keeps more of the heavy lifting inside optimized browser internals.&lt;/p&gt;

&lt;p&gt;Caching is another big lever. Resolving fonts, images, backgrounds, and computed styles is some of the most expensive work in any capture, and a lot of it is repeated across captures. SnapDOM leans on caching so those resolved resources don't have to be recomputed every time — the second capture of the same UI, and repeated captures in general (think live previews, thumbnails, or exporting many similar cards), get dramatically faster because the heavy resource resolution is reused instead of redone.&lt;/p&gt;

&lt;p&gt;It's also worth noting SnapDOM's output flexibility: you can get an SVG, a raster image, a &lt;code&gt;Blob&lt;/code&gt;, a data URL, a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;, or a ready-to-use &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; in a single call. When you don't force a raster round-trip you can keep the result vector-sharp, which matters for retina displays and print.&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;snapdom&lt;/span&gt; &lt;span class="p"&gt;}&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;@zumer/snapdom&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;el&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;#card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Multiple output formats from one capture&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;png&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;snapdom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toPng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&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;svg&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;snapdom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toSvg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&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;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;snapdom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fidelity and modern CSS
&lt;/h2&gt;

&lt;p&gt;This is where the architectural choice pays off the most. Shadow DOM, web components, pseudo-elements, CSS custom properties, and modern layout all tend to "just work" with SnapDOM because they're rendered by the same engine that renders your page. Fonts are a classic pain point with html2canvas; SnapDOM's approach to inlining resources and honoring the real computed styles produces output that matches what the user actually sees far more often. Fewer surprises, fewer manual workarounds, fewer "why does the export look different from the screen" bug reports.&lt;/p&gt;

&lt;h2&gt;
  
  
  SnapDOM vs. native capture APIs and other approaches
&lt;/h2&gt;

&lt;p&gt;It's fair to ask: browsers keep gaining native capture-ish capabilities, and there are other libraries in this space — so why SnapDOM? A few reasons it stays genuinely useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It already supports the html-to-canvas style output.&lt;/strong&gt; You don't lose anything by choosing SnapDOM: it can hand you a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; (and PNG/JPEG/WebP from it) just like the canvas-first tools, while &lt;em&gt;also&lt;/em&gt; giving you SVG, &lt;code&gt;Blob&lt;/code&gt;, data URL, and &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;. It's a superset, not a trade-off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native APIs solve a different problem.&lt;/strong&gt; Things like &lt;code&gt;getDisplayMedia&lt;/code&gt;/screen capture or the experimental region-capture APIs grab the &lt;em&gt;rendered viewport&lt;/em&gt; through the OS/compositor. They require user permission prompts, capture what's actually on screen (scroll position, overlays, device chrome), and can't cleanly isolate a single off-screen or partially-scrolled node. SnapDOM captures a &lt;em&gt;specific DOM node&lt;/em&gt; deterministically, with no permission dialog, regardless of what's currently visible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;foreignObject&amp;gt;&lt;/code&gt; done right.&lt;/strong&gt; The raw "serialize DOM into an SVG &lt;code&gt;&amp;lt;foreignObject&amp;gt;&lt;/code&gt;" trick is well known, but doing it correctly — inlining fonts and images, honoring computed styles, handling shadow DOM and cross-origin resources, and producing consistent raster output — is where most hand-rolled attempts fall apart. SnapDOM packages that hard part into something reliable and extensible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency across environments.&lt;/strong&gt; Native and OS-level capture varies by browser, platform, and permissions. A DOM-based approach gives you the same result wherever your page runs, which matters for reproducible thumbnails, share images, and automated pipelines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: native capture is great when you want "whatever is on the user's screen," but for "turn &lt;em&gt;this component&lt;/em&gt; into an image, faithfully and programmatically," SnapDOM is the right tool — and it covers the canvas use case on top.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plugins and extensibility
&lt;/h2&gt;

&lt;p&gt;A big practical advantage of SnapDOM is that it's built to be &lt;strong&gt;extended&lt;/strong&gt; rather than patched. Its capture pipeline exposes hook points, so you can transform nodes before serialization, adjust or inline resources, tweak the output, and plug in custom behavior without forking the library. That plugin-oriented design means teams can adapt capture behavior to their own components and edge cases instead of waiting for upstream to add a special case.&lt;/p&gt;

&lt;p&gt;html2canvas, by contrast, is essentially a monolithic renderer. Its extension surface is a set of options and callbacks bolted onto a fixed pipeline. When it doesn't support something, your realistic choices are to work around it, monkey-patch it, or fork it. The extensibility model of SnapDOM turns "the library doesn't do X" from a dead end into a solvable problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flexibility in real projects
&lt;/h2&gt;

&lt;p&gt;Beyond raw capture, SnapDOM is flexible about &lt;em&gt;how&lt;/em&gt; you integrate it. Options for background color, scaling/DPI, cropping, resource inlining, and choice of output format let you tune it to the task — thumbnails, social share images, PDF pipelines, or pixel-perfect design exports — without stitching together extra tooling. Because the primitive it produces is an SVG, you also get an escape hatch: you can post-process the vector output before rasterizing, something that's awkward at best with a canvas-only approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling to large DOM trees
&lt;/h2&gt;

&lt;p&gt;Big, deeply nested trees are the classic stress test for any DOM-to-image tool, and it's an area where SnapDOM is actively getting better. The stable production releases have already landed impressive speedups for large captures, and the work isn't stopping there: the ongoing effort in the dev branch pushes this even further, with genuinely exciting progress on making large-tree captures faster and more efficient. If you have heavy dashboards or dense component trees, this is a project moving in exactly the right direction — and the gains already shipped in stable are substantial today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maintainability
&lt;/h2&gt;

&lt;p&gt;There's a subtler, longer-term argument here too. A library that re-implements the browser is, by definition, chasing a moving target: every new CSS feature is potential new work and a new source of divergence. A library that &lt;em&gt;delegates&lt;/em&gt; to the browser inherits new features largely for free. That makes SnapDOM's core smaller and its behavior more predictable to reason about, which is exactly what you want in a dependency you'll be shipping in production for years.&lt;/p&gt;

&lt;p&gt;From a project-health standpoint, SnapDOM is actively developed with a clear, modern codebase and a design that invites contribution through its plugin points. A tighter core with well-defined extension seams is generally easier to maintain, test, and trust than a sprawling engine that must account for the entire CSS specification by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;If you're starting fresh, capturing modern UI, or you've been fighting html2canvas over fonts, shadow DOM, performance, or CSS support, SnapDOM is the more forward-looking choice. Delegating rendering to the browser instead of reimplementing it gives you better fidelity, better performance, an actual plugin/extensibility story, and a codebase that's easier to maintain over the long haul.&lt;/p&gt;

&lt;p&gt;Same problem, smarter architecture.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>html</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I got tired of page navigation. So I built a zoom-based alternative</title>
      <dc:creator>Juan Martin</dc:creator>
      <pubDate>Mon, 06 Apr 2026 01:10:32 +0000</pubDate>
      <link>https://dev.to/tinchox5/i-got-tired-of-page-navigation-so-i-built-a-zoom-based-alternative-2koo</link>
      <guid>https://dev.to/tinchox5/i-got-tired-of-page-navigation-so-i-built-a-zoom-based-alternative-2koo</guid>
      <description>&lt;p&gt;The idea is simple: instead of navigating between pages, you zoom into content. Mark an element as zoomable, point it to a view, and Zumly handles the transition and inserts the new content. That’s basically it.&lt;/p&gt;

&lt;p&gt;I started this in 2020 after stepping back from Zircle UI, a Vue zooming library I built before. I wanted to take the core idea further without being tied to any framework. So &lt;strong&gt;Zumly&lt;/strong&gt; is framework-agnostic and focused purely on the zoom transition. It doesn’t care about your CSS, your design system, or your stack.&lt;br&gt;
Since then I rewrote the engine several times and changed the approach more than once. Only now am I actually happy with how it feels.&lt;/p&gt;

&lt;p&gt;The landing page is built with Zumly itself, so you get the interaction before touching any code:&lt;br&gt;
&lt;a href="https://zumerlab.github.io/zumly" rel="noopener noreferrer"&gt;https://zumerlab.github.io/zumly&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Still rough edges ahead. Would love to hear what you think about the interaction model and if the API makes sense.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>showdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>From frustration to open source adoption: my journey building SnapDOM</title>
      <dc:creator>Juan Martin</dc:creator>
      <pubDate>Sat, 27 Sep 2025 14:22:02 +0000</pubDate>
      <link>https://dev.to/tinchox5/from-frustration-to-open-source-adoption-my-journey-building-snapdom-4p4o</link>
      <guid>https://dev.to/tinchox5/from-frustration-to-open-source-adoption-my-journey-building-snapdom-4p4o</guid>
      <description>&lt;p&gt;I started hacking on what later became SnapDOM in April this year. At first it wasn’t even meant to be a standalone library — it began as an internal tool for a zoomable UI project (Zumly), I was building. To make that project work, I needed a way to capture DOM elements with high speed and fidelity. Existing DOM-to-image libraries like html2canvas often failed in subtle but important ways: missing pseudo-elements, mis-rendering fonts, ignoring Shadow DOM, or breaking on Safari. What started as a quick internal hack slowly grew into its own project.&lt;br&gt;
Open sourcing SnapDOM changed everything. Suddenly the audience wasn’t just me, but anyone with their own browser, CSS, and HTML quirks. That’s when I realized how immense the attack surface really is. Every combination of engines, DOM structures, styles, and external resources can break in unexpected ways. At times it felt overwhelming, but I’ve learned to treat each bug as a reproducible pattern: isolate it, fix it, and carry the lesson forward.&lt;/p&gt;

&lt;p&gt;From the beginning, two principles guided the work: fidelity and speed. Capturing “every detail” would not matter if the process was unbearably slow, so I spent a lot of time on caching strategies, incremental updates, and efficient DOM cloning. Benchmarking against existing libraries became part of the routine. Performance was never an afterthought — it was always as important as accuracy.&lt;/p&gt;

&lt;p&gt;On the technical side, SnapDOM pushed me into DOM cloning strategies, caching, font embedding heuristics, browser-specific hacks, and the constant tradeoffs between fidelity and performance. On the personal side, it has been just as educational: patience, humility, and learning to really listen to users. Some of the best moments have been receiving thoughtful PRs and clear reproduction cases — collaboration that genuinely made the project better. The respect shown in these contributions has been one of the most motivating parts of the journey.&lt;/p&gt;

&lt;p&gt;Another milestone: only a few months in, SnapDOM already has its first two GitHub Sponsors and has passed 6k stars on GitHub. Knowing that people found enough value to sponsor the project, and that thousands more cared enough to star it, has been incredibly rewarding.&lt;/p&gt;

&lt;p&gt;I’ve also been designing a plugin system, so the core stays lean while features like cropping, filters, or alternative exporters can live as extensions. It’s not merged into the mainline yet, but it’s a direction I’m excited about — and another layer of complexity to manage as the project evolves.&lt;/p&gt;

&lt;p&gt;It’s still early days, but reflecting on the journey from April to now has been meaningful. What started as a small internal helper for a zoomable UI turned into an open source project with real users, contributions, sponsors, and community respect. Balancing the technical struggles with the human side of open source has made this one of the most rewarding experiences I’ve had so far.&lt;/p&gt;

&lt;p&gt;Thank you, Martin&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/zumerlab/snapdom" rel="noopener noreferrer"&gt;https://github.com/zumerlab/snapdom&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>🎉 SnapDOM celebrates 3 months! 🎉</title>
      <dc:creator>Juan Martin</dc:creator>
      <pubDate>Sun, 27 Jul 2025 10:37:36 +0000</pubDate>
      <link>https://dev.to/tinchox5/snapdom-celebrates-3-months-2ee4</link>
      <guid>https://dev.to/tinchox5/snapdom-celebrates-3-months-2ee4</guid>
      <description>&lt;p&gt;Today, 27 July, we mark the first 90 days since Snapdom was born.&lt;br&gt;
We couldn’t be more grateful to the amazing community that made it possible. 🙌&lt;/p&gt;

&lt;p&gt;🚀 In just 3 months, Snapdom has reached:&lt;/p&gt;

&lt;p&gt;⭐ 3550+ stars&lt;br&gt;
🍴 107 forks&lt;br&gt;
📦 18 releases published&lt;br&gt;
👥 14 incredible contributors&lt;br&gt;
Snapdom grew fast, but on a solid foundation. During this time, we’ve added advanced support for:&lt;/p&gt;

&lt;p&gt;✅ Web Components and slots&lt;br&gt;
✅ Complex pseudo-elements&lt;br&gt;
✅ Remote and local fonts (including icon fonts!)&lt;br&gt;
✅ &lt;a class="mentioned-user" href="https://dev.to/import"&gt;@import&lt;/a&gt; and @font-face styles&lt;br&gt;
✅ mask-image, backgrounds, canvas, SVG, and more&lt;br&gt;
✅ Fixes for Safari, Firefox, Edge, Chromium...&lt;br&gt;
✅ Performance optimizations, compression, and smart caching&lt;br&gt;
✅ New benchmarks, CI compatibility, improved DX and documentation&lt;/p&gt;

&lt;p&gt;👩‍🔧 Every release brought significant improvements, with a steady evolution focused on true visual fidelity.&lt;/p&gt;

&lt;p&gt;🔥 What truly sets Snapdom apart is its speed — it is hands down the fastest DOM capture tool available.&lt;/p&gt;

&lt;p&gt;What truly sets Snapdom apart is its speed — it is hands down the fastest DOM capture tool available.&lt;/p&gt;

&lt;p&gt;While other tools like html2canvas, html-to-image, and modern-screenshot may take noticeably longer or face challenges with complex DOMs, Snapdom captures almost instantly, even with deep and dynamic structures. This unmatched speed makes it the go-to solution for real-time apps, visual editors, and any workflow where performance is critical.&lt;/p&gt;

&lt;p&gt;Our benchmarks prove it out: Snapdom surpasses these alternatives by a wide margin, delivering high-fidelity results without compromising speed.&lt;/p&gt;

&lt;p&gt;The secret behind this performance lies mainly in Snapdom’s advanced caching system combined with its intelligent CSS class assembly. By efficiently reusing cached styles and building compact CSS increments, Snapdom drastically reduces final bundle size and speeds up style processing, resulting in lightning-fast captures even in the most demanding scenarios.&lt;/p&gt;

&lt;p&gt;You can check all the progress in the full Changelog, or explore our interactive demos to see what it can do.&lt;/p&gt;

&lt;p&gt;💜 Huge thanks to everyone who opened issues, submitted PRs, starred the repo, or helped test.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>📊 SnapDOM - Performance Benchmarks For clientside screenshots</title>
      <dc:creator>Juan Martin</dc:creator>
      <pubDate>Thu, 10 Jul 2025 16:51:18 +0000</pubDate>
      <link>https://dev.to/tinchox5/snapdom-performance-benchmarks-for-clientside-screenshots-47kf</link>
      <guid>https://dev.to/tinchox5/snapdom-performance-benchmarks-for-clientside-screenshots-47kf</guid>
      <description>&lt;p&gt;Snapdom has made &lt;strong&gt;major performance leaps&lt;/strong&gt; since &lt;code&gt;v1.8.0&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple elements (ms, lower is better)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Snapdom (current)&lt;/th&gt;
&lt;th&gt;Snapdom v1.8.0&lt;/th&gt;
&lt;th&gt;html2canvas&lt;/th&gt;
&lt;th&gt;modern-screenshot&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Small (200×100)&lt;/td&gt;
&lt;td&gt;0.4&lt;/td&gt;
&lt;td&gt;1.2&lt;/td&gt;
&lt;td&gt;70.3&lt;/td&gt;
&lt;td&gt;11.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modal (400×300)&lt;/td&gt;
&lt;td&gt;0.4&lt;/td&gt;
&lt;td&gt;1.1&lt;/td&gt;
&lt;td&gt;68.8&lt;/td&gt;
&lt;td&gt;14.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page View&lt;/td&gt;
&lt;td&gt;0.4&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;100.5&lt;/td&gt;
&lt;td&gt;34.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large Scroll&lt;/td&gt;
&lt;td&gt;0.4&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;153.1&lt;/td&gt;
&lt;td&gt;77.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Very Large&lt;/td&gt;
&lt;td&gt;0.4&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;278.9&lt;/td&gt;
&lt;td&gt;194.7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Complex elements (ms)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Snapdom (current)&lt;/th&gt;
&lt;th&gt;Snapdom v1.8.0&lt;/th&gt;
&lt;th&gt;html2canvas&lt;/th&gt;
&lt;th&gt;modern-screenshot&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Small (200×100)&lt;/td&gt;
&lt;td&gt;1.1&lt;/td&gt;
&lt;td&gt;3.2&lt;/td&gt;
&lt;td&gt;72.5&lt;/td&gt;
&lt;td&gt;16.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modal (400×300)&lt;/td&gt;
&lt;td&gt;4.5&lt;/td&gt;
&lt;td&gt;14.0&lt;/td&gt;
&lt;td&gt;90.1&lt;/td&gt;
&lt;td&gt;34.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page View&lt;/td&gt;
&lt;td&gt;32.9&lt;/td&gt;
&lt;td&gt;113.6&lt;/td&gt;
&lt;td&gt;196.1&lt;/td&gt;
&lt;td&gt;181.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large Scroll&lt;/td&gt;
&lt;td&gt;133.9&lt;/td&gt;
&lt;td&gt;387.4&lt;/td&gt;
&lt;td&gt;446.6&lt;/td&gt;
&lt;td&gt;635.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Very Large&lt;/td&gt;
&lt;td&gt;364.0&lt;/td&gt;
&lt;td&gt;1200.4&lt;/td&gt;
&lt;td&gt;1275.4&lt;/td&gt;
&lt;td&gt;1685.6&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  ⚡ Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Snapdom (current) is &lt;strong&gt;2–4× faster&lt;/strong&gt; than v1.8.0
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Up to 500× faster than html2canvas&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Much faster&lt;/strong&gt; than modern-screenshot, especially with large/complex DOMs
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧪 Benchmarks run with &lt;strong&gt;Chromium + Vitest&lt;/strong&gt; on a &lt;strong&gt;2018 MacBook Air&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
🏎️ Even better performance on modern hardware!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/zumerlab/snapdom/discussions/102" rel="noopener noreferrer"&gt;https://github.com/zumerlab/snapdom/discussions/102&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>opensource</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Snapdom: a modern and faster alternative to html2canvas</title>
      <dc:creator>Juan Martin</dc:creator>
      <pubDate>Tue, 01 Jul 2025 07:36:50 +0000</pubDate>
      <link>https://dev.to/tinchox5/snapdom-a-modern-and-faster-alternative-to-html2canvas-1m9a</link>
      <guid>https://dev.to/tinchox5/snapdom-a-modern-and-faster-alternative-to-html2canvas-1m9a</guid>
      <description>&lt;p&gt;In less than two months, &lt;a href="https://github.com/zumerlab/snapdom" rel="noopener noreferrer"&gt;Snapdom&lt;/a&gt; reached &lt;strong&gt;2,120+ stars&lt;/strong&gt;, with 7 contributors and a growing user base. But the goal has been clear since day one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Build a modern, accurate and fast replacement for &lt;code&gt;html2canvas&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;&lt;code&gt;html2canvas&lt;/code&gt; was a milestone. I love it. It brought DOM-to-image to mainstream frontend. But time has passed, and the web platform has evolved: higher DPI screens, complex shadows, pseudo-elements with &lt;code&gt;::before { content: url(...) }&lt;/code&gt;, imported icon fonts, variables inside gradients, shadow DOM, web components, and more.&lt;/p&gt;

&lt;p&gt;Many of those features don’t render correctly in &lt;code&gt;html2canvas&lt;/code&gt;. Snapdom aims to &lt;strong&gt;fix that&lt;/strong&gt; with a new approach.&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%2F7863f4h357vzfwx09wow.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%2F7863f4h357vzfwx09wow.gif" alt="Benchmark" width="542" height="496"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  What Snapdom does differently
&lt;/h3&gt;

&lt;p&gt;Snapdom captures how a DOM &lt;strong&gt;looks&lt;/strong&gt;. While tools like &lt;code&gt;html2canvas&lt;/code&gt; attempt to reproduce the layout procedurally using canvas drawing commands, Snapdom takes a different route:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It builds a &lt;strong&gt;visual clone&lt;/strong&gt; of the DOM using a serialized structure and renders it via &lt;strong&gt;SVG with &lt;code&gt;&amp;lt;foreignObject&amp;gt;&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Styles are computed via &lt;code&gt;getComputedStyle()&lt;/code&gt; and inlined per element, or &lt;strong&gt;collapsed into reusable CSS classes&lt;/strong&gt; when &lt;code&gt;compress&lt;/code&gt; mode is enabled.&lt;/li&gt;
&lt;li&gt;Snapdom uses &lt;strong&gt;caching strategies&lt;/strong&gt; for computed styles, fonts, and DOM shape to improve render performance.&lt;/li&gt;
&lt;li&gt;It supports &lt;strong&gt;hi-DPI scaling&lt;/strong&gt;, fixed size snapshots, and consistent box models across browsers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach makes it fast, modular, and portable — and allows Snapdom to produce &lt;strong&gt;SVG output that can be rendered, embedded, or exported&lt;/strong&gt; in almost any format.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual fidelity
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Captures &lt;code&gt;::before&lt;/code&gt; / &lt;code&gt;::after&lt;/code&gt; / &lt;code&gt;::first-letter&lt;/code&gt;, including icons, URLs and inline content.&lt;/li&gt;
&lt;li&gt;Supports &lt;code&gt;background-image&lt;/code&gt; with multiple layers: &lt;code&gt;url()&lt;/code&gt;, &lt;code&gt;linear-gradient(...)&lt;/code&gt;, &lt;code&gt;var(...)&lt;/code&gt;, mixed.&lt;/li&gt;
&lt;li&gt;Handles shadows, filters, transforms, blend modes, scroll, overflow, and z-index correctly.&lt;/li&gt;
&lt;li&gt;Captures shadow DOM content and visual order.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Fonts and icon support
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Full support for &lt;code&gt;@font-face&lt;/code&gt; via stylesheets or &lt;code&gt;FontFace()&lt;/code&gt; constructor.&lt;/li&gt;
&lt;li&gt;Correct rendering of &lt;strong&gt;icon fonts&lt;/strong&gt; (FontAwesome, Material Icons, etc.) — including inside pseudo-elements.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;embedFonts: true&lt;/code&gt; will inline all fonts into the SVG.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DOM state
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Captures &lt;strong&gt;current values&lt;/strong&gt; of inputs, selects, and textareas.&lt;/li&gt;
&lt;li&gt;Preserves scroll position (&lt;code&gt;scrollTop&lt;/code&gt;, &lt;code&gt;scrollLeft&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;HiDPI / Retina support via &lt;code&gt;devicePixelRatio&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Optional fixed dimensions with &lt;code&gt;width&lt;/code&gt; and/or &lt;code&gt;height&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;snapdom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;embedFonts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;compress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;h3&gt;
  
  
  Performance-focused
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Snapshots in &lt;strong&gt;milliseconds&lt;/strong&gt;, even on complex pages.&lt;/li&gt;
&lt;li&gt;One-time capture → multiple exports:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;snapdom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toSvg&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toPng&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toWebp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Coming soon: Plugin system
&lt;/h3&gt;

&lt;p&gt;We're working on a &lt;strong&gt;native plugin architecture&lt;/strong&gt; so anyone can extend Snapdom with custom needs.&lt;/p&gt;

&lt;p&gt;Some ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Watermarking&lt;/li&gt;
&lt;li&gt;PDF export&lt;/li&gt;
&lt;li&gt;WebGL / canvas integration&lt;/li&gt;
&lt;li&gt;Post-capture mutation (blurring, tinting, overlays, etc.)&lt;/li&gt;
&lt;li&gt;Integration with visual editors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The plugin API will allow users to hook into preprocessing, postprocessing, and export logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  API at a glance
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;snapdom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;compress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;embedFonts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;crossOrigin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anonymous&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Exports&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toSvg&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toCanvas&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toPng&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toWebp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toImg&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;data-capture="exclude"&lt;/code&gt; skips a node and its children.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;data-capture="placeholder"&lt;/code&gt; replaces a node with an empty box (useful for ads, iframes, etc).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;📦 GitHub → &lt;a href="https://github.com/zumerlab/snapdom" rel="noopener noreferrer"&gt;github.com/zumerlab/snapdom&lt;/a&gt;&lt;br&gt;
🧪 Live demo → &lt;a href="https://zumerlab.github.io/snapdom" rel="noopener noreferrer"&gt;zumerlab.github.io/snapdom&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Snapdom is fully browser-based. No canvas hacks, no server dependency. Just clean JS + SVG + Web APIs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We're actively looking for feedback and contributors. If you're hitting limits with &lt;code&gt;html2canvas&lt;/code&gt;, try Snapdom and help shape its future.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>A practical way to test HTML and CSS in real-time using only CSS.</title>
      <dc:creator>Juan Martin</dc:creator>
      <pubDate>Wed, 28 Aug 2024 13:16:39 +0000</pubDate>
      <link>https://dev.to/tinchox5/a-practical-way-to-test-html-and-css-in-real-time-using-only-css-3c80</link>
      <guid>https://dev.to/tinchox5/a-practical-way-to-test-html-and-css-in-real-time-using-only-css-3c80</guid>
      <description>&lt;p&gt;Recently, I made public &lt;a href="https://dev.to/tinchox5/orbit-a-css-framework-for-crafting-simple-or-complex-radial-interfaces-2463"&gt;a CSS framework&lt;/a&gt; I developed for creating radial designs. During development, I faced several challenges, including testing different features. I noticed that CSS linters and other tools didn't allow me to see why something wasn't working, even if there were no basic errors. Another typical CSS problem was seeing how it was shared across different browsers. Fortunately, I discovered that certain new CSS features can be used to create a series of real-time tests. These features are &lt;code&gt;@support&lt;/code&gt;, &lt;code&gt;@container&lt;/code&gt;, and &lt;code&gt;:has()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By combining these features, I developed a testing system not only to check if the framework works in the browser but also, and most importantly, to see if we are applying HTML correctly according to the browser's requirements and avoiding involuntary errors when developing an application.&lt;/p&gt;

&lt;p&gt;Since my CSS framework necessarily uses features that only the newest browsers have, such as trigonometric functions like &lt;code&gt;cos()&lt;/code&gt; and &lt;code&gt;sin()&lt;/code&gt;, I created a series of rules to test if they are supported by the browser. If they're not, a message appears asking to update the browser. Similarly, if the browser doesn't support &lt;code&gt;:has()&lt;/code&gt;, which is used throughout the framework.&lt;/p&gt;

&lt;p&gt;There are also typical cases of browser incompatibility, so in some non-critical cases, I use &lt;code&gt;@support&lt;/code&gt; or &lt;code&gt;@container&lt;/code&gt; to hide certain Orbit features that don't affect its use. For example, Safari doesn't accept SVG &lt;code&gt;context-stroke&lt;/code&gt;, so I hide them.&lt;/p&gt;

&lt;p&gt;However, beyond those critical checks and compatibility, the most common issue when using a CSS framework is not knowing how to use it properly. That's why I created other CSS rules that allow analyzing if a parent element has the required child elements and not others. Here, visual alerts also appear while developing to give a hint about where the error is in the code.&lt;/p&gt;

&lt;p&gt;I don't want to bore you with the details specific to Orbit, but I'll leave you the link to the support source and related documentation.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/zumerlab/orbit" rel="noopener noreferrer"&gt;https://github.com/zumerlab/orbit&lt;/a&gt;&lt;br&gt;
Source file: &lt;a href="https://github.com/zumerlab/orbit/blob/main/src/scss/_support.scss" rel="noopener noreferrer"&gt;https://github.com/zumerlab/orbit/blob/main/src/scss/_support.scss&lt;/a&gt;&lt;br&gt;
Orbit Support documtation: &lt;a href="https://zumerlab.github.io/orbit-docs/tools/support/" rel="noopener noreferrer"&gt;https://zumerlab.github.io/orbit-docs/tools/support/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Good to go deeper:  &lt;a href="https://heydonworks.com/article/testing-html-with-modern-css" rel="noopener noreferrer"&gt;https://heydonworks.com/article/testing-html-with-modern-css&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>testing</category>
    </item>
    <item>
      <title>Orbit a CSS framework for crafting simple or complex radial interfaces.</title>
      <dc:creator>Juan Martin</dc:creator>
      <pubDate>Tue, 27 Aug 2024 10:11:02 +0000</pubDate>
      <link>https://dev.to/tinchox5/orbit-a-css-framework-for-crafting-simple-or-complex-radial-interfaces-2463</link>
      <guid>https://dev.to/tinchox5/orbit-a-css-framework-for-crafting-simple-or-complex-radial-interfaces-2463</guid>
      <description>&lt;p&gt;Hi Devs!&lt;/p&gt;

&lt;p&gt;I've been a long-time fan of DEV, but this is my first post. I'm excited to introduce &lt;strong&gt;Orbit&lt;/strong&gt;, a new CSS framework I've created that allows you to build radial interfaces &lt;strong&gt;using only CSS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Orbit has a flexible API that borrows some spatial design concepts to make it familiar and easy to use. With Orbit, you can create complex radial layouts and designs without writing a single line of JavaScript. Imagine building gauges, charts, watches, Mini Cooper dashboards ;), solar systems, and even esoteric user interfaces seen in sci-fi movies! You can achieve all those and more with CSS. &lt;/p&gt;

&lt;p&gt;I'll stop here, as I just want to introduce Orbit to the community. In future posts, I plan to write some tutorials and examples to help you get started with Orbit. If you have any suggestions for examples or projects you'd like to see, please let me know! &lt;/p&gt;

&lt;p&gt;I left here a Codepen example&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/zircle/embed/poXKqwz?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I'd love to hear your feedback.&lt;/p&gt;

&lt;p&gt;Thank you,&lt;br&gt;
Martin&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/zumerlab/orbit" rel="noopener noreferrer"&gt;Repository link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://zumerlab.github.io/orbit-docs" rel="noopener noreferrer"&gt;Documentation link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
