<?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: Frank Delporte</title>
    <description>The latest articles on DEV Community by Frank Delporte (@fdelporte).</description>
    <link>https://dev.to/fdelporte</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%2F395015%2Fd00fa8a9-663a-48f3-b950-dd3e5d55278f.jpg</url>
      <title>DEV Community: Frank Delporte</title>
      <link>https://dev.to/fdelporte</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fdelporte"/>
    <language>en</language>
    <item>
      <title>A New Website for MelodyMatrix, and What's New in Release 1.1.0</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Mon, 13 Jul 2026 08:04:34 +0000</pubDate>
      <link>https://dev.to/fdelporte/a-new-website-for-melodymatrix-and-whats-new-in-release-110-4nmo</link>
      <guid>https://dev.to/fdelporte/a-new-website-for-melodymatrix-and-whats-new-in-release-110-4nmo</guid>
      <description>&lt;p&gt;Last week was busy for &lt;a href="https://melodymatrix.rocks/" rel="noopener noreferrer"&gt;MelodyMatrix&lt;/a&gt;. The website got rebuilt from the ground up, and the app itself got a solid release with a handful of new features. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Website Is Completely New
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;melodymatrix.rocks&lt;/code&gt; used to be one Spring Boot + Vaadin Flow application serving everything: the public  pages, the account/admin back office, and the REST API used by the desktop app. That worked, but a Vaadin app isn't a perfect match for a public product site as it's not great for SEO.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;www.melodymatrix.rocks&lt;/code&gt; is now a &lt;strong&gt;static, multilingual Hugo site&lt;/strong&gt;, live in &lt;strong&gt;8 languages&lt;/strong&gt; (English, Dutch, German, French, Italian, Polish, Japanese, Chinese), deployed to GitLab Pages. The Vaadin application still exists, but it's trimmed down to only what actually needs a server: &lt;code&gt;my.melodymatrix.rocks&lt;/code&gt; (account, license, teacher/admin back office) and &lt;code&gt;api.melodymatrix.rocks&lt;/code&gt; (the public REST API used by the desktop app, plus the Polar.sh license sales webhook). At this moment, both live in the same application, but the plan is to split them into separate microservices whenever that becomes necessary, e.g. if we sell thousands of licenses a day ;-) &lt;/p&gt;

&lt;p&gt;The new site pulls in live data at build time instead of duplicating it by hand: a small Python script fetches the current releases and the open-source "thanks" list from the API before every Hugo build, so the &lt;a href="https://melodymatrix.rocks/releases/" rel="noopener noreferrer"&gt;Releases page&lt;/a&gt; and the credits are never out of sync with what's actually shipped. This way it's easy to keep the app and website in sync, without the need to maintain the same data in two places.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1w3jsimg5ex5tsktry0q.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1w3jsimg5ex5tsktry0q.png" alt="Homepage of the new website" width="800" height="711"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Built the Same Way as Lottie4J
&lt;/h2&gt;

&lt;p&gt;If this sounds familiar, it's because it's the &lt;a href="https://webtechie.be/post/closing-the-visual-gap-between-the-official-lottie-webplayer-and-lottie4j/" rel="noopener noreferrer"&gt;same approach I wrote about for Lottie4J&lt;/a&gt; two weeks ago: &lt;strong&gt;Theia IDE&lt;/strong&gt; driving the &lt;strong&gt;Claude API&lt;/strong&gt;, with an &lt;code&gt;@Architect&lt;/code&gt; writing a plan and a &lt;code&gt;@Coder&lt;/code&gt; executing it in its own scoped session to simplify the Vaadin website. The layout for the website was created with Claude Design which exported it flawless into a Hugo template. Moving the content from Vaadin to the new website, the i18n scaffolding for 8 languages, the data-driven feature/view/tier cards, was done with AI-assisted coding. Let's be honest, this is the new way of working. Still, a lot of manual work for testing, reviewing, improving, etc. But most of the coding work was done with and by the tools. Yes, it cost me a few 100 dollars in Claude credits, but it saved me a lot of time and frustration. For a pet project, with only minimal available time, I wouldn't have achieved this in such a short time.&lt;/p&gt;

&lt;p&gt;The same discipline applied: small, well-bounded tasks (one section at a time: navigation, features, downloads, legal pages, translations) instead of one giant prompt, and a fresh session per task rather than one ever-growing conversation. &lt;/p&gt;

&lt;h2&gt;
  
  
  App Release 1.1.0
&lt;/h2&gt;

&lt;p&gt;While the website was being rebuilt, MelodyMatrix itself also moved forward to &lt;strong&gt;&lt;a href="https://melodymatrix.rocks/releases/" rel="noopener noreferrer"&gt;version 1.1.0&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Audio spectrum view&lt;/strong&gt;: a new visualizer added to the set of viewer stages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Falling/rising note blocks&lt;/strong&gt; in the Piano view, closer to the "note highway" style many musicians expect from a practice tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved sync between view, soundfont, and audio&lt;/strong&gt; playback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;i18n support&lt;/strong&gt;, with extra languages added to the desktop app itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved MIDI view&lt;/strong&gt; and reordered views for a more logical order.&lt;/li&gt;
&lt;li&gt;A fixed macOS DMG build step in the release pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As before, the &lt;a href="https://github.com/codewriterbv/melodymatrix-app-views" rel="noopener noreferrer"&gt;Viewers module stays open source&lt;/a&gt; and the download packages are published through &lt;a href="https://www.jdeploy.com/" rel="noopener noreferrer"&gt;jDeploy&lt;/a&gt; via &lt;a href="https://github.com/codewriterbv/melodymatrix-app-releases/releases" rel="noopener noreferrer"&gt;GitHub Releases&lt;/a&gt;, with the &lt;a href="https://melodymatrix.rocks/download/" rel="noopener noreferrer"&gt;download page on the new site&lt;/a&gt; always pointing at the current build.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fax8vvaq1s4a4ocyfxov9.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fax8vvaq1s4a4ocyfxov9.png" alt="Piano with effects view" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;With the website live and 1.1.0 out, we will be focusing on content improvements. We want to create videos to demonstrate all views and features. And Vik is working on multiple series of lessons that will be integrated in the app to learn to play piano, use jazz chords, etc. &lt;/p&gt;

&lt;p&gt;Please take a look at the new website and install MelodyMatrix (it's free for most features). Let us know your remarks and provide feedback about what's bad/great! If you spot a broken translation, a confusing page, or a bug in the app, issues can be reported in the &lt;a href="https://github.com/codewriterbv/melodymatrix-app-views/issues" rel="noopener noreferrer"&gt;open-source Viewers repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>javafx</category>
      <category>midi</category>
      <category>melodymatrix</category>
    </item>
    <item>
      <title>My Book 'Java Programming for Raspberry Pi' is Now Available as Softcover and Hardcover on Amazon</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Fri, 10 Jul 2026 07:20:33 +0000</pubDate>
      <link>https://dev.to/fdelporte/my-book-java-programming-for-raspberry-pi-is-now-available-as-softcover-and-hardcover-on-amazon-590b</link>
      <guid>https://dev.to/fdelporte/my-book-java-programming-for-raspberry-pi-is-now-available-as-softcover-and-hardcover-on-amazon-590b</guid>
      <description>&lt;p&gt;"Java Programming for Raspberry Pi: A Hands-On Guide to Electronics and IoT Projects" is now available as a &lt;strong&gt;softcover and hardcover paper book&lt;/strong&gt; through Amazon, on top of the Kindle ebook and the pay-as-you-wish version on &lt;a href="https://leanpub.com/gettingstartedwithjavaontheraspberrypi" rel="noopener noreferrer"&gt;Leanpub&lt;/a&gt;. If you prefer holding a physical book while you're wiring up LEDs and sensors on your Raspberry Pi, that's now possible again.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it got there
&lt;/h2&gt;

&lt;p&gt;The first version of my book, got published as paper book by Elektor in 2020. At that time, they basically took the Leanpub manuscript, did some minor changes, and printed 1000 copies. As a writer, you get only a few percent of the sales price, so although those 1000 copies sold out, you can still considere it a pet project ;-) After that, Elektor returned me the publishing right for a paper version.&lt;/p&gt;

&lt;p&gt;I'm happy to announce, new paper editions are now available! I exported a non-branded version of the manuscript straight from Leanpub and pushed it through Amazon KDP (Kindle Direct Publishing) as a print-on-demand title. I won't pretend it was a smooth ride: reformatting a Leanpub export into something KDP accepts for interior layout and cover specs took several rounds of trial and error. But it is still the shortest and easiest path I found to get a self-published book into a paper form without signing up for a subscription with a print service. You upload once, and Amazon handles printing, shipping, and returns per order.&lt;/p&gt;

&lt;p&gt;Amazon runs price reductions on both the softcover and hardcover fairly often, so it's worth &lt;a href="https://www.amazon.com/dp/B0GZWWKB1L" rel="noopener noreferrer"&gt;keeping an eye on the listing&lt;/a&gt; if the current price is higher than you want to pay. Also, &lt;strong&gt;make sure to check your local Amazon website to avoid extra import or shipping costs&lt;/strong&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxd38wct83wvuuwk4hvwo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxd38wct83wvuuwk4hvwo.jpg" alt="Paper versions of the book" width="800" height="793"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping it in sync with Leanpub
&lt;/h2&gt;

&lt;p&gt;The Leanpub version is the one I keep actively updating, and I'll try to push those updates through to the Amazon paper editions too. Re-exporting and republishing through KDP is more manual than a Leanpub update, so the paper book will always trail a bit behind.&lt;/p&gt;

&lt;p&gt;That said, the timing works out well. End of 2025 and start of 2026 I did a big rewrite to bring everything up to Java 25 and Pi4J V4. That means this print edition is already current with the state of the ecosystem today, and I don't expect Java, Pi4J, or the Raspberry Pi hardware line to go through equally massive changes again any time soon. So even without frequent paper reprints, this version will stay a solid, up-to-date reference for the next few years, especially if you're someone who just prefers reading from paper instead of a screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to get it
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Softcover (Amazon)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.amazon.com/dp/B0GZWWKB1L" rel="noopener noreferrer"&gt;amazon.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardcover (Amazon)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.amazon.com/dp/B0GZWZJSJN" rel="noopener noreferrer"&gt;amazon.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kindle ebook (Amazon)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.amazon.com/dp/B0GXCF1RQT" rel="noopener noreferrer"&gt;amazon.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ebook, pay-as-you-wish&lt;/td&gt;
&lt;td&gt;&lt;a href="https://leanpub.com/gettingstartedwithjavaontheraspberrypi" rel="noopener noreferrer"&gt;leanpub.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://webtechie.be/books/" rel="noopener noreferrer"&gt;books page on my website&lt;/a&gt; has links for more Amazon regions (UK, DE, JP, CA, BE, NL, ...) and stays the up-to-date overview if these change. The full sources, extra links, and documentation remain free on &lt;a href="https://github.com/FDelporte/JavaOnRaspberryPi" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>raspberrypi</category>
      <category>pi4j</category>
      <category>javaonsingleboardcomputers</category>
    </item>
    <item>
      <title>Closing the Visual Gap Between the Official Lottie Webplayer and Lottie4J</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Thu, 02 Jul 2026 09:55:07 +0000</pubDate>
      <link>https://dev.to/fdelporte/closing-the-visual-gap-between-the-official-lottie-webplayer-and-lottie4j-54nn</link>
      <guid>https://dev.to/fdelporte/closing-the-visual-gap-between-the-official-lottie-webplayer-and-lottie4j-54nn</guid>
      <description>&lt;p&gt;A Lottie library is only as good as its output looks. If an animation renders differently in &lt;a href="https://lottie4j.com/" rel="noopener noreferrer"&gt;Lottie4J&lt;/a&gt; than it does in the official web player, that's a bug, even when no exception is thrown and the code looks correct. &lt;/p&gt;

&lt;p&gt;Within the &lt;code&gt;fxfileviewer&lt;/code&gt;, there is an app to visually compare the result of the JavaFX player and a webview using the official JavaScript player. Problem is that I was using the JavaFX Web component for this and this doesn't fully support the latest/best version of this player. Based on this app for manual checks, I also created a unit test which is able to loop over a set of files and compare the differences to make sure changes in the code don't break the existing renderer. But I kept struggling with the same test file &lt;a href="https://github.com/lottie4j/lottie4j/tree/main/fxfileviewer/src/test/resources/json/interactive_mood_selector_ui.json" rel="noopener noreferrer"&gt;interactive_mood_selector_ui.json&lt;/a&gt; which didn't render correctly, both in the JavaFX view and my web-based view to compare it with.&lt;/p&gt;

&lt;p&gt;Over the last weeks the focus has been exactly there: &lt;strong&gt;making the JavaFX output match the reference renderer, pixel for pixel&lt;/strong&gt; (if possible).&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftp4nwivkrhcq6wlbgw78.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftp4nwivkrhcq6wlbgw78.png" alt="Improved result" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Improved Comparison Workflow
&lt;/h3&gt;

&lt;p&gt;The biggest change is not a rendering fix but the way rendering is now verified. The test suite renders the same animation two ways and compares them frame by frame:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;reference&lt;/strong&gt; side runs the official web player inside a headless Chrome instance. This reference renderer was migrated from &lt;code&gt;lottie-web&lt;/code&gt; to &lt;strong&gt;&lt;code&gt;dotlottie-wc&lt;/code&gt; (thorvg)&lt;/strong&gt;, the engine LottieFiles is standardizing on. The reference images are not generated during the unit test, but as a one-time job on my PC and committed in the &lt;a href="https://github.com/lottie4j/lottie4j/tree/main/fxfileviewer/src/test/resources" rel="noopener noreferrer"&gt;test/resources&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Lottie4J&lt;/strong&gt; side renders the same file through the JavaFX player.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now each frame is diffed, instead of every 5 frames before, and measured against a tolerance "floor". When Lottie4J drifts from the reference, a test fails and points at the exact frame. This runs with headless JavaFX on GitHub Actions as described in the post &lt;a href="https://webtechie.be/post/testing-lottie4j-javafx-animations-in-github-actions-without-a-display-javafx-26-headless-to-the-rescue/" rel="noopener noreferrer"&gt;Testing Lottie4J JavaFX Animations in GitHub Actions Without a Display: JavaFX 26 Headless to the Rescue&lt;/a&gt;. That turned "this animation looks a bit off" into a concrete, reproducible signal. The goal is to get each file to &lt;a href="https://github.com/lottie4j/lottie4j/blob/main/fxfileviewer/src/test/java/com/lottie4j/fxfileviewer/CompareFxViewWithWebViewTest.java#L85" rel="noopener noreferrer"&gt;99.5% similarity&lt;/a&gt;, but that value can be overruled per file. As you can &lt;a href="https://github.com/lottie4j/lottie4j/blob/main/fxfileviewer/src/test/java/com/lottie4j/fxfileviewer/CompareFxViewWithWebViewTest.java#L135" rel="noopener noreferrer"&gt;see in the code&lt;/a&gt;, the "worst" file is now at 95.2%, and yes, it's still that difficult &lt;code&gt;interactive_mood_selector_ui.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;     &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;PER_FILE_FLOOR_OVERRIDE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofEntries&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"json/interactive_mood_selector_ui.json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;95.2&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"json/animated_background_patterns.json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;99.2&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"json/angry_bird.json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;98.2&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"json/face-peeking.json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;98.5&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"json/java_duke_flip.json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;95.7&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"json/java_duke_slidein.json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;98.8&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"json/lottie_lego.json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;98.0&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"json/sandy_loading.json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;99.3&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dot/demo-1.lottie"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;99.3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;New real-world test animations, like &lt;code&gt;pi4j.json&lt;/code&gt;, &lt;code&gt;foojay-reporter.json&lt;/code&gt; and &lt;code&gt;foojay-duke.json&lt;/code&gt;, got added so the harness measures against the files I'm actually using.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rendering Fixes
&lt;/h3&gt;

&lt;p&gt;With the harness in place, the diffs made it obvious where JavaFX and the web player disagreed. The fixes can be grouped into a few areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Easing&lt;/strong&gt;: The &lt;code&gt;lottie-web&lt;/code&gt; &lt;code&gt;BezierEaser&lt;/code&gt; was ported byte-for-byte into a shared &lt;code&gt;core.helper.BezierEasing&lt;/code&gt;, and the arc renderer now clamps the easing solver to prevent bezier divergence, with a bisection fallback for flat-point curves. A full-circle trim path that used to flicker (floating-point precision loss when wrapping the offset) is fixed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mattes&lt;/strong&gt;: Pixel-level matte composition was extracted into a testable static helper, and the inverted-alpha matte type (&lt;code&gt;tt: 2&lt;/code&gt; → &lt;code&gt;INVERTED_ALPHA&lt;/code&gt;) is now handled correctly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gradients&lt;/strong&gt;: Alpha and colour stops are merged at the union of their offsets, and linear-RGB gradient stops are densified so colour transitions match the reference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blur and blend modes&lt;/strong&gt;: Gaussian blur was improved, the blend-mode offscreen buffer size is rounded up (ceil) so nothing gets clipped, and the effects renderer was reworked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text&lt;/strong&gt;: Text colour handling and text animation are now correct.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Individually these are small, but together they close a lot of the visible distance between Lottie4J and the official player.&lt;/p&gt;

&lt;h3&gt;
  
  
  Built with Systematic AI Coding
&lt;/h3&gt;

&lt;p&gt;All of this was implemented with &lt;strong&gt;&lt;a href="https://theia-ide.org/" rel="noopener noreferrer"&gt;Theia IDE&lt;/a&gt;&lt;/strong&gt; using the &lt;strong&gt;Claude API&lt;/strong&gt;. I learned about Theia IDE during an Eclipse Foundation workshop in Brussels. I wrote about it on Foojay.io: &lt;a href="https://foojay.io/today/systematic-ai-coding-my-takeaways-from-the-eclipse-foundation-workshop-in-brussels/" rel="noopener noreferrer"&gt;Systematic AI coding, my takeaways&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The takeaways from that article map almost one-to-one onto this batch of work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Design before prompting, then review the output&lt;/strong&gt;: The comparison harness is what makes review possible. And the &lt;code&gt;@Architect&lt;/code&gt; within Theia IDE was able to run the tests file by file, find differences, write plans, and evaluate the results. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A tight feedback loop beats one big prompt&lt;/strong&gt;: Failing frame → targeted fix → re-run → next frame. The &lt;a href="https://github.com/lottie4j/lottie4j/commits/main/" rel="noopener noreferrer"&gt;commit history reads as exactly that rhythm&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep sessions scoped and don't fear a restart&lt;/strong&gt;: The &lt;code&gt;@Architect&lt;/code&gt; writes the plan. And then you start a new session and ask the &lt;code&gt;@Coder&lt;/code&gt; agent to execute it. Each rendering area (mattes, gradients, blur, text) was tackled as its own well-bounded task rather than one ever-lasting conversation. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let the tools review too&lt;/strong&gt;: A round of code improvements came straight out of SonarQube findings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I committed all the tasks written by the &lt;code&gt;@Architect&lt;/code&gt; &lt;a href="https://github.com/lottie4j/lottie4j/tree/main/.prompts/done" rel="noopener noreferrer"&gt;into the repository&lt;/a&gt; so they are available as "history of the project". The most important take-away here isn't that AI wrote the code, but the disciplined process with clear tasks and small iterations, each in a new session.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Result
&lt;/h3&gt;

&lt;p&gt;Where are we now? Check the images below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first screenshot is the test file in the &lt;a href="https://lottiefiles.com/preview" rel="noopener noreferrer"&gt;&lt;strong&gt;Preview player&lt;/strong&gt; on the Lottie website&lt;/a&gt;. As you can see a lot of gradients are used in the background and around the emojis. Those are the parts I was struggling with...&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqhdxpcup3obc96j32chq.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqhdxpcup3obc96j32chq.png" alt="Lottie Preview" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The second screenshot is the &lt;strong&gt;"before"&lt;/strong&gt;. Both the JavaFX and the webview version have a lot of differences. This also means I was using the wrong comparison source images to validate the JavaFX result!&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fswbpm6earmhuwvwp31z0.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fswbpm6earmhuwvwp31z0.png" alt="Before improvements" width="799" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The third screenshot is the &lt;strong&gt;"after"&lt;/strong&gt; which shows a lot of improvements. First and most important, the comparison images from the webview are now pixel-perfect as they get rendered based on the latest version of the official Lottie web player. And you can also see that the JavaFX result is now a really close match! The background gradients are not pixel-perfect yet, and I still see small differences in the text, which confirms the 95% similarity score. But overall, I'm very happy with the improvements! &lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2kq48e6aahy80b7ktwqo.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2kq48e6aahy80b7ktwqo.png" alt="After improvements" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Cost
&lt;/h3&gt;

&lt;p&gt;Of course, the AI coding process is not free. Theia IDE luckily is free, but it needs one or more API keys to call AI services. As you can see, I burned a lot of tokens, and budget. But to be honest, I would not have achieved these improvements by myself in such a short time. Actually, I could do my "real work", and have the tools work in the background!&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fie8q3a8fj7hbrvozcyt0.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fie8q3a8fj7hbrvozcyt0.png" alt="Screenshot Claude cost" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;I'm happy with the results so will release a new version soon. The same approach with &lt;code&gt;@Architect&lt;/code&gt;/&lt;code&gt;@Coder&lt;/code&gt; will help me to further improve or fix the library when needed. But first I want to know which visual differences remain based on feedback from the users of the Lottie4J library!&lt;/p&gt;

&lt;p&gt;As always, contributions, bug reports, and pull requests are welcome at the &lt;a href="https://github.com/lottie4j/lottie4j" rel="noopener noreferrer"&gt;Lottie4J GitHub repository&lt;/a&gt;. If you have an animation that renders differently than you expect, isolate it, and open an issue with the JSON. That's exactly the kind of case the test flow is built to catch.&lt;/p&gt;

</description>
      <category>java</category>
      <category>javafx</category>
      <category>lottie</category>
      <category>animation</category>
    </item>
    <item>
      <title>From breadboard chaos to a real PCB: designing the Pi4J smoke test board</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Thu, 25 Jun 2026 09:30:36 +0000</pubDate>
      <link>https://dev.to/fdelporte/from-breadboard-chaos-to-a-real-pcb-designing-the-pi4j-smoke-test-board-538g</link>
      <guid>https://dev.to/fdelporte/from-breadboard-chaos-to-a-real-pcb-designing-the-pi4j-smoke-test-board-538g</guid>
      <description>&lt;p&gt;Testing a Java I/O library properly means testing it on real hardware. No mocks, no stubs, just actual pins doing actual things. For Pi4J, that means running the smoke test: a setup with two BMP/BME280 sensors, some GPIO-to-GPIO jumper connections, and a bunch of patience while you untangle the wires for the third time this week.&lt;/p&gt;

&lt;p&gt;That last part is what finally pushed us to design a proper PCB. This is the story of board number &lt;code&gt;0001&lt;/code&gt;.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  What is the Pi4J smoke test
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.pi4j.com/hardware-testing/hardware-testing/" rel="noopener noreferrer"&gt;Pi4J smoke test&lt;/a&gt; is a test project that verifies the Pi4J library works correctly on real Raspberry Pi hardware. It covers the most important communication protocols:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I2C: using a BMP280 or BME280 sensor for air pressure and temperature&lt;/li&gt;
&lt;li&gt;SPI: a second BMP/BME280 sensor over SPI&lt;/li&gt;
&lt;li&gt;GPIO: several pin-to-pin connections to test PWM output, digital output, digital input, and debounce behaviour&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The wiring involves quite a few connections. Two sensors, a T-cobbler breakout board plugged into a breadboard, and a collection of colour-coded jumper wires connecting GPIO pins to each other. It works fine, but "works fine" and "reliable test setup" are not always the same thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with the breadboard
&lt;/h2&gt;

&lt;p&gt;Every time someone of the Pi4J sets up the smoke test on a breadboard, something is slightly different. A wire in the wrong column. A jumper that looks seated but is not. A sensor that falls over when you move the board.&lt;/p&gt;

&lt;p&gt;This is fine for a quick experiment. It is not great when you want to hand the setup to a contributor, or use it consistently across different hardware revisions of the Raspberry Pi. The goal of a smoke test is to give you a fast, repeatable answer to the question "does this still work". A breadboard that changes shape every session works against that goal.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Femwe2ggylvat67bmsdrk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Femwe2ggylvat67bmsdrk.jpg" alt="Smoketest setup on a breadboard" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So we wanted to have a "fixed solution" already for a long time...&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing the board with EasyEDA
&lt;/h2&gt;

&lt;p&gt;I used &lt;a href="https://pro.easyeda.com/editor" rel="noopener noreferrer"&gt;EasyEDA Pro&lt;/a&gt; for the design. It is a browser-based PCB design tool with a built-in schematic editor, a large component library, and direct integration with JLCPCB for ordering. The learning curve is manageable, especially for a board this straightforward.&lt;/p&gt;

&lt;p&gt;I did not do this alone. Jan, a coach from my CoderDojo club in Ieper, helped me convert the breadboard setup into a proper schematic. That turned out to be the right call. There are details in PCB design, like how to connect the sensors, adding the LEDs, component placement, and clearance rules, where experience matters more than enthusiasm. Jan has a lot of hardware-design experience and was happy to share it.&lt;/p&gt;

&lt;p&gt;The starting point was the wiring tables from the smoke test documentation. Every connection in those tables needed to end up as a trace or a connector on the board. That gave us a clear scope and made the design process straightforward.&lt;/p&gt;

&lt;p&gt;In the schematic you don't have to draw every wire as a line. Instead you use net labels: a pin gets a label like &lt;code&gt;SDA&lt;/code&gt; or &lt;code&gt;SCL&lt;/code&gt;, and every other pin with the same label is connected to it. The same approach works for both the I2C and the SPI side, and for the ground and 3.3V connections that run across the board. It keeps the schematic readable while still describing every single connection from the wiring table.&lt;/p&gt;

&lt;p&gt;From the schematic, EasyEDA can propose a board layout for you. That proposal is only a starting point. I did a lot of fine-tuning on top of it and went back and forth with the Pi4J team before the layout was right. A nice feature here is that you can hover over a net and watch all its connections light up, which makes it easy to validate that, for example, the ground plane and the SPI wires really go where they should. EasyEDA also has a 3D visualization, so you can turn the board around, check it from all angles, and confirm that everything is labeled correctly before ordering anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is on the board
&lt;/h2&gt;

&lt;p&gt;The finished board has a few distinct sections.&lt;/p&gt;

&lt;p&gt;The 40-pin GPIO header runs across the middle, with pin numbers printed on both rows. This connects directly to the Raspberry Pi GPIO header. Above the header, a row of SMD resistors and LEDs helps to see if the GPIO-to-GPIO tests are running. They are grouped by the pin ranges they cover: 12-16, 13-15, 16-22, 32-36, 36-37, and 38. Each group maps to one of the test cases in the smoke test wiring table.&lt;/p&gt;

&lt;p&gt;On the left side of the board there is an I2C connector for the first BMP/BME280 sensor. On the right side there is an SPI connector for the second sensor. &lt;/p&gt;

&lt;p&gt;The board also has mounting holes in all four corners, which means you can actually fix it to something instead of letting it slide around on a desk. And there are two additional 20-pin headers so it's easy to connect a measuring instrument if something seems to be not working as expected.&lt;/p&gt;

&lt;p&gt;Board number 0001 is the first one off the production run. The QR code in the top corner is the PCB manufacturer's tracking code.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn0c74nzkn38hhfr0vjbi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn0c74nzkn38hhfr0vjbi.jpg" alt="PCB 001" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ordering the board
&lt;/h2&gt;

&lt;p&gt;The board is manufactured by JLCPCB, which integrates directly with EasyEDA. This is where I ran into some user experience problems. These companies are great at hardware, but the ordering software is confusing the first time you use it. From the schematic view, the only thing you get is an "order the parts" button that drops you on the JLCPCB website without actually starting an order. The real ordering options live in the PCB view, behind a different set of buttons that are not clearly labeled. I ended up chatting with the support team just to figure out which button I needed to press.&lt;/p&gt;

&lt;p&gt;Once I found the right place, ordering was easy. The minimum quantity is five boards, which was fine, because I also wanted them assembled and will share with members of the Pi4J team. The only component not in stock was the 40-pin GPIO header, but that is cheap and easy to solder yourself, so it was not a problem.&lt;/p&gt;

&lt;p&gt;The package arrived well protected, with each board resting on a piece of foam to protect the headers. The boards came on a larger panel because my design was too small to run through the production machines on its own, so the manufacturer adds extra board material around it. After that it was just a matter of soldering the 40-pin header, which goes straight through and is the easy part.&lt;/p&gt;

&lt;h2&gt;
  
  
  First results
&lt;/h2&gt;

&lt;p&gt;To make sure nothing had changed in the code, I first ran the existing smoke test on my old breadboard setup with a Raspberry Pi 5, straight from IntelliJ. The run executes about ten tests across the different protocols, including PWM, digital I/O, I2C, and SPI, and the summary reported all ten passing.&lt;/p&gt;

&lt;p&gt;Then I connected the new PCB using a flat cable, carefully matching pin 1 on the Raspberry Pi to pin 1 on the board. Using two flat cables means I don't have to keep unplugging connectors directly on the Raspberry Pi, which limits the stress on the Pi's own header. Running the same smoke test, the LEDs started blinking and jumping from one pin group to the next as each test ran, a nice visual confirmation that something is actually happening. And the result was the same: all tests passed.&lt;/p&gt;

&lt;p&gt;The connections are solid, the connectors are in the right place, and nothing falls over when you pick it up. That is exactly what you want from a test board.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Next
&lt;/h2&gt;

&lt;p&gt;The plan is to open source the EasyEDA design files and add the board to the Pi4J hardware testing documentation. If there is interest from contributors, it could become an official Pi4J testing accessory, something you can order yourself or build from the files.&lt;/p&gt;

&lt;p&gt;If you have feedback on the design, or ideas for what else should go on a future revision, open a discussion on the &lt;a href="https://github.com/Pi4J/pi4j/discussions" rel="noopener noreferrer"&gt;Pi4J GitHub&lt;/a&gt; or find us on &lt;a href="https://join.slack.com/t/pi4j/shared_invite/zt-1ttqt8wgj-E6t69qaLrNuCMPLiYnBCsg" rel="noopener noreferrer"&gt;Slack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And yes, CoderDojo coaches know more about PCB design than you might expect.&lt;/p&gt;

</description>
      <category>iot</category>
      <category>java</category>
      <category>showdev</category>
      <category>testing</category>
    </item>
    <item>
      <title>JavaFX In Action #27 with David Gutierrez about JMathAnim to Create Mathematical Animations</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Thu, 25 Jun 2026 09:28:01 +0000</pubDate>
      <link>https://dev.to/fdelporte/javafx-in-action-27-with-david-gutierrez-about-jmathanim-to-create-mathematical-animations-25df</link>
      <guid>https://dev.to/fdelporte/javafx-in-action-27-with-david-gutierrez-about-jmathanim-to-create-mathematical-animations-25df</guid>
      <description>&lt;p&gt;The &lt;a href="https://www.jfx-central.com/links" rel="noopener noreferrer"&gt;JFX Central Links Of The Week&lt;/a&gt; is a great source to discover what is happening in the JavaFX world. One of the projects that caught my eye is JMathAnim, a tool to create mathematical animations built on top of JavaFX. In this interview, David Gutierrez, a mathematician from Spain, walks us through what the project can do and how it came to life.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  About David
&lt;/h2&gt;

&lt;p&gt;David Gutierrez is a mathematician who started the JMathAnim project during the COVID lockdown period. By his own admission, he is not a trained developer. He built JMathAnim because he needed a tool that didn't exist in Java yet, and Java was the language he was most comfortable with. He was inspired by &lt;a href="https://www.manim.community/" rel="noopener noreferrer"&gt;Manim&lt;/a&gt;, the popular Python library used to create mathematical animations, and decided to build his own equivalent in Java.&lt;/p&gt;

&lt;p&gt;His work is a great example of what happens when domain expertise meets just enough programming knowledge: the result is a highly focused, purpose-built tool that does one thing very well. You can follow his work and find examples of his animations on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://davidgutierrezrubio.codeberg.page/jmathanim/" rel="noopener noreferrer"&gt;JMathAnim website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codeberg.org/davidgutierrezrubio/jmathanim" rel="noopener noreferrer"&gt;JMathAnim source code on Codeberg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bsky.app/profile/davidcalculin.bsky.social/post/3mlbvm4rlg22d" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  About JMathAnim
&lt;/h2&gt;

&lt;p&gt;JMathAnim is a Java library and UI built on JavaFX that lets you create animated mathematical visualizations. The goal is simple: make it easy to build videos that explain mathematical concepts through animation. It's inspired by the kind of content you see on YouTube channels like &lt;a href="https://www.youtube.com/@3blue1brown" rel="noopener noreferrer"&gt;3Blue1Brown&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What It Can Do
&lt;/h3&gt;

&lt;p&gt;The library covers a wide range of use cases. You can animate LaTeX-rendered formulas, morphing one expression into another step by step. You can build geometric visualizations, simulate cell growth, generate fractals, and produce videos explaining number theory concepts like base conversion. Everything you see in the animation is defined in code, and the output can be exported directly to a video file, no intermediate steps required.&lt;/p&gt;

&lt;p&gt;A particularly nice touch is the built-in code editor, which includes syntax highlighting via &lt;a href="https://github.com/bobbylight/rsyntaxtextarea" rel="noopener noreferrer"&gt;RSyntaxTextArea&lt;/a&gt; and code completion hints. This makes it accessible to people who want to experiment with the library without setting up a full Java IDE.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnkqig2hjstp1m4k27cr9.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnkqig2hjstp1m4k27cr9.png" alt="Base 10 to 5 animation" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Ruby in the Code Editor?
&lt;/h3&gt;

&lt;p&gt;One interesting design choice is the use of Ruby as the scripting language inside the built-in editor. The reason isn't mathematical tradition, but it's practical. Ruby's scripting model fits well with the way animation sequences are written, making it a natural fit for the kind of short, expressive scripts you need to define animations. The Java library itself handles all the heavy lifting; Ruby is just the glue layer in the interactive editor.&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaFX as the Rendering Engine
&lt;/h3&gt;

&lt;p&gt;All rendering in JMathAnim is done on a JavaFX Canvas. LaTeX formula rendering is handled by &lt;a href="https://github.com/opencollab/jlatexmath" rel="noopener noreferrer"&gt;JLatexMath&lt;/a&gt;, and video export relies on &lt;a href="https://github.com/bytedeco/javacv" rel="noopener noreferrer"&gt;JavaCV&lt;/a&gt;. The combination gives JMathAnim a capable pipeline from code to finished video.&lt;/p&gt;

&lt;p&gt;David is the first to admit that JavaFX had a learning curve, especially since he came at it as a mathematician rather than a developer. But his experience shows that JavaFX is approachable enough that someone without a formal software engineering background can build something genuinely impressive with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explaining Math Visually
&lt;/h3&gt;

&lt;p&gt;One of the most compelling examples shown during the interview is a visualization explaining the conversion from base 10 to base 5. It's a simple concept, but seeing it animated makes it click in a way that a textbook explanation often doesn't. This is exactly the philosophy behind JMathAnim and the channels that inspired it: a well-made animation can communicate in seconds what would take paragraphs to describe in writing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;JMathAnim:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://davidgutierrezrubio.codeberg.page/jmathanim/" rel="noopener noreferrer"&gt;Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codeberg.org/davidgutierrezrubio/jmathanim" rel="noopener noreferrer"&gt;Source code on Codeberg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bsky.app/profile/davidcalculin.bsky.social/post/3mlbvm4rlg22d" rel="noopener noreferrer"&gt;Video example on Bluesky&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Libraries used:

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/bobbylight/rsyntaxtextarea" rel="noopener noreferrer"&gt;RSyntaxTextArea&lt;/a&gt;: Syntax-highlighting text editor component for Java&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/opencollab/jlatexmath/" rel="noopener noreferrer"&gt;JLatexMath&lt;/a&gt;: LaTeX rendering for Java&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/bytedeco/javacv" rel="noopener noreferrer"&gt;JavaCV&lt;/a&gt;: Java interface to OpenCV and FFmpeg for video export&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Inspired by:

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.manim.community/" rel="noopener noreferrer"&gt;Manim&lt;/a&gt;: Python library for mathematical animations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;YouTube channel mentioned:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/@3blue1brown" rel="noopener noreferrer"&gt;3Blue1Brown&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Video content
&lt;/h2&gt;

&lt;p&gt;00:00 Who is David&lt;/p&gt;

&lt;p&gt;00:33 Goal of JMathAnim&lt;/p&gt;

&lt;p&gt;01:16 Demo of JMathAnim&lt;/p&gt;

&lt;p&gt;04:53 Different ways to create animations in the tool&lt;/p&gt;

&lt;p&gt;05:40 Why Ruby is used in the code editor&lt;/p&gt;

&lt;p&gt;06:24 More demos&lt;/p&gt;

&lt;p&gt;07:16 Demos and info on the website&lt;/p&gt;

&lt;p&gt;11:12 JavaFX learning curve&lt;/p&gt;

&lt;p&gt;13:46 Libraries used in the project&lt;/p&gt;

&lt;p&gt;14:30 Example to explain base 10 to base 5 conversion&lt;/p&gt;

&lt;p&gt;16:27 Conclusion&lt;/p&gt;

&lt;h2&gt;
  
  
  More JFX In Action...
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://webtechie.be/tags/jfx-in-action/" rel="noopener noreferrer"&gt;Click here for more posts with JFX In Action videos&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>javafx</category>
      <category>mathematics</category>
      <category>programming</category>
    </item>
    <item>
      <title>Systematic AI Coding: My Takeaways from the Eclipse Foundation Workshop in Brussels</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Wed, 24 Jun 2026 08:24:03 +0000</pubDate>
      <link>https://dev.to/fdelporte/systematic-ai-coding-my-takeaways-from-the-eclipse-foundation-workshop-in-brussels-5dd8</link>
      <guid>https://dev.to/fdelporte/systematic-ai-coding-my-takeaways-from-the-eclipse-foundation-workshop-in-brussels-5dd8</guid>
      <description>&lt;p&gt;Most developers using AI tools are still guessing. The Eclipse Foundation's first &lt;a href="https://aieclipse.org/ai-workshop/" rel="noopener noreferrer"&gt;AI Coding Workshop&lt;/a&gt; in Brussels was built to change that. It's a brand new format they launched in Brussels, which makes sense: most of the Eclipse event team is based there, right in the heart of Europe. The plan is to take it to more cities from here, so keep an eye out if you want to attend such a workshop in the future. They offered 10 free tickets to share with the BeJUG and Foojay community. And in all honesty, I used one for myself ;-). &lt;a href="https://www.linkedin.com/in/jonas-helming-76303b28/" rel="noopener noreferrer"&gt;Jonas Helming&lt;/a&gt; from &lt;a href="https://eclipsesource.com/" rel="noopener noreferrer"&gt;EclipseSource&lt;/a&gt;  led the workshop, with a fun quiz hosted by &lt;a href="https://www.linkedin.com/in/tfroment/" rel="noopener noreferrer"&gt;Thomas Froment&lt;/a&gt; in the afternoon. Here's what I took away.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnb2k80dm9vsvwt4useuz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnb2k80dm9vsvwt4useuz.jpg" alt="Jonas Helming in action" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  From Vibe to Systematic
&lt;/h2&gt;

&lt;p&gt;The workshop kicked off with an important framing question: where are we in the AI coding journey? Jonas positioned AI assistance on a scale from 1 (basic code suggestions) to 5 (fully autonomous). We are now at level 4 with tools like Claude Code. Level 5 is approaching when fully cloud-based autonomous agents will be available.&lt;/p&gt;

&lt;p&gt;Most developers today are still somewhere in the "vibe coding" zone. Vibe coding is the &lt;em&gt;what, not how&lt;/em&gt; approach: you describe what you want, don't look at the generated code too closely (or not all), and focus on the result. It can work well for POCs and low-complexity problems on well-understood domains. But it quickly crumbles once you move into real projects with real complexity.&lt;/p&gt;

&lt;p&gt;The fundamental shift the workshop is about, is moving beyond the experimentation phase toward something repeatable and systematic. That's what Jonas calls &lt;em&gt;Systematic AI Coding&lt;/em&gt;: understanding how coding agents actually work, and building workflows around them, not just prompting and hoping.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a Coding Agent Actually Works
&lt;/h2&gt;

&lt;p&gt;One of the most useful sessions was the breakdown of what happens inside a coding agent. It's easy to think of it as a magic box, but the mechanics matter a lot for using it well.&lt;/p&gt;

&lt;p&gt;A coding agent takes several inputs: the system message, user messages, assistant responses, your codebase, and any additional context you provide. That context includes things like project context, task context (your plan), and the skills or tools available to the agent. On top of that, you can have optional agent layering, like a model router that picks the right model for the task.&lt;/p&gt;

&lt;p&gt;From there, the agent uses tools, calls the LLM, and generates a change set: files, actions, context updates, MCP calls. Everything flows through what Jonas describes as part of the &lt;em&gt;Request Model&lt;/em&gt;: tools + messages + tool messages + tool responses. The whole thing boils down to one word: &lt;strong&gt;CONTEXT&lt;/strong&gt;. Context is everything.&lt;/p&gt;

&lt;p&gt;A key insight: &lt;strong&gt;the LLM is stateless and forgets immediately.&lt;/strong&gt; Every time it runs, you need to resend the full conversation history for it to understand what happened before. This has a real consequence as the context gets polluted and the cost rises because extra tokens are needed to handle the input. And there's a subtle trap called the "dumb zone": efficiency actually drops before you hit the context window limit. According to some experiments, this can already start at roughly ±40% of the context capacity. So a session that feels like it's still working might already be producing worse results.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Workflow
&lt;/h2&gt;

&lt;p&gt;Once you understand how agents work, the practical workflow makes a lot more sense. It looks roughly like this:&lt;/p&gt;

&lt;p&gt;Your AI Agent generates output, and you need to &lt;strong&gt;Review or Decide&lt;/strong&gt;. From there you have several options: escape (abort), refine (adjust the prompt), redo (start a fresh chat), divide the task further, compact the session, adjust the agent configuration, or commit what's working. Then repeat.&lt;/p&gt;

&lt;p&gt;Two important take-aways from Jonas here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't be afraid to throw away changes and start over.&lt;/strong&gt; A fresh session with a cleaner, better-scoped prompt will often outperform trying to rescue a session that's gone sideways. The bad feeling you may have of "lost coding work" is real, but irrelevant as it's not your work, but done by a tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compact the session yourself, don't rely on the agent to do it.&lt;/strong&gt; If you let the agent compact automatically, you lose control over what context gets dropped. Doing it yourself means you decide what's kept.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One tip I should follow: when your AI tool is working, don't start another session in another project. Look out the window and think about the actual problem you're solving within the project to better handle the result. Context-switching is expensive for humans too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time Changes When You Use AI
&lt;/h2&gt;

&lt;p&gt;Without AI, a developer typically spends roughly 70% of time on design and coding combined, and 30% on debugging. With AI, the split looks very different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design: ~30%&lt;/li&gt;
&lt;li&gt;Review: ~30%&lt;/li&gt;
&lt;li&gt;Debugging: ~35%&lt;/li&gt;
&lt;li&gt;Actual AI-generated code: ~5%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The work doesn't disappear, but it shifts. You spend more time thinking, reviewing, and debugging, and less time typing code. This has implications for how you approach a task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design&lt;/strong&gt; before you ever prompt the agent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Think about the task and if it should be split&lt;/li&gt;
&lt;li&gt;Describe your intent with precision&lt;/li&gt;
&lt;li&gt;Provide examples, relevant files, and existing implementations&lt;/li&gt;
&lt;li&gt;Give the agent a way to validate its own output&lt;/li&gt;
&lt;li&gt;Apply the "good friend" metaphor: share the tips and tricks from your own codebase that you'd tell a new colleague&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Review&lt;/strong&gt; isn't optional:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, find blockers&lt;/li&gt;
&lt;li&gt;Decide the follow-up action (refine, redo, split, etc.)&lt;/li&gt;
&lt;li&gt;Only if there are no remaining blockers: do a detailed review to finish the task
## Done ≠ Ready&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When an agent says it's done, that's not a green light to push. AI-generated code can drift on quality, introduce security risks, and produce "work-slop" that frustrates your coworkers. Before pushing, do a review the way a careful coworker would.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Companies Need to Enable This
&lt;/h2&gt;

&lt;p&gt;Jonas highlighted a few important requirements that a company needs to provide to its developers if it wants to make systematic AI coding actually happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt; (which cost money)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time&lt;/strong&gt; to learn and experiment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Space&lt;/strong&gt; to experiment and share learnings across the team&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That third one is often underrated. Individual experimentation is great, but if there's no mechanism to share what works, the team never levels up together.&lt;/p&gt;

&lt;h2&gt;
  
  
  On the Eclipse Side
&lt;/h2&gt;

&lt;p&gt;There was also a short quiz by Thomas Froment that covered some Eclipse Foundation projects worth knowing about. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open VSX&lt;/strong&gt; is an open-source, vendor-neutral alternative to the Visual Studio Marketplace: an &lt;a href="https://open-vsx.org/" rel="noopener noreferrer"&gt;open registry&lt;/a&gt;, an &lt;a href="https://projects.eclipse.org/projects/ecd.openvsx" rel="noopener noreferrer"&gt;open-source project&lt;/a&gt;, and a working group. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://theia-ide.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Theia IDE&lt;/strong&gt;&lt;/a&gt; built on the &lt;a href="https://theia-ide.org/theia-platform/" rel="noopener noreferrer"&gt;Theia Platform&lt;/a&gt;, ## a modern, AI-native IDE for cloud and desktop. It has many handy AI-tools for developers, like showing every step an agent takes, token usage, a &lt;code&gt;@PR Review&lt;/code&gt; agent that you can give a PR number to checkout, build, run, and create a review plan, etc.
## Final Thought&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to the Eclipse Foundation for the free tickets, for the perfect organization, and to everyone from BeJUG and Foojay who joined! This was their first workshop in this format, and I hope they bring it to many more cities soon. Also thanks to the sponsor as they allowed to have a good location with a pro tech team and good food during the whole day.&lt;/p&gt;

&lt;p&gt;It was a dense, practical day. This summary is only a small part of all the tips, tricks, hints, pitfalls, and all the other knowledge shared by Jonas, in over four hours. He also has a longer version of this workshop that he gives at companies and other events. If you have the opportunity to meet him or join one of those sessions, you should definitely do!&lt;/p&gt;

&lt;p&gt;The biggest shift for me wasn't any single tip but the importance of shifting from &lt;strong&gt;vibe&lt;/strong&gt; to &lt;strong&gt;systematic&lt;/strong&gt; coding. AI coding isn't magic and it isn't a shortcut. It's a different kind of engineering discipline, with its own workflows, its own failure modes, and its own learning curve. The developers who benefit most are the ones who take it seriously, build repeatable processes, and keep their engineering judgment front and center.&lt;/p&gt;

&lt;h2&gt;
  
  
  This Post Was Co-Authored With Claude Code
&lt;/h2&gt;

&lt;p&gt;Jonas also highlighted that you can use AI tools for much more than coding alone. So, again in all honesty, Claude Code wrote the initial version of this blog during my train ride from Brussels back to Kortrijk. The tool read my handwritten reMarkable notes, exported as a PDF. But, of course, with a full review, rewrite, and fine-tuning by yours truly :-).&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>llm</category>
      <category>developers</category>
    </item>
    <item>
      <title>A Fresh Design for webtechie.be</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Wed, 17 Jun 2026 11:48:22 +0000</pubDate>
      <link>https://dev.to/fdelporte/a-fresh-design-for-webtechiebe-3o45</link>
      <guid>https://dev.to/fdelporte/a-fresh-design-for-webtechiebe-3o45</guid>
      <description>&lt;p&gt;My website grew over many years into more than 260 posts, 220 videos, 100 podcasts, and 60 presentations. The old design buried most of that under a layout that no longer matched the way I write today. So I rebuilt it from the ground up, and the result puts the content first.&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="https://webtechie.be" rel="noopener noreferrer"&gt;webtechie.be&lt;/a&gt;, and you land on a cleaner home page that points you straight to the blog posts, podcasts, and my book. Those are things I spend most time on and deserve more attention. The new design also gives more space to the projects I work on, like Lottie4J, Pi4J, MelodyMatrix, and more. The old site had a lot of content but no clear way to find it. The new one makes it easier to discover what I have to share.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

&lt;p&gt;The redesign touches almost every part of the site. These are the changes you notice first.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A new theme&lt;/strong&gt;: The whole site moves to a terminal-inspired look that fits the topics I cover: Java, JavaFX, Raspberry Pi, and single-board computers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More focus on &lt;a href="https://dev.to/posts"&gt;blog posts&lt;/a&gt; and &lt;a href="https://dev.to/podcasts"&gt;podcasts&lt;/a&gt;&lt;/strong&gt;: The home page and navigation push the long-form content forward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A light and dark switch&lt;/strong&gt;: You pick the mode you prefer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A search box&lt;/strong&gt;: Find any post by keyword without scrolling through archive pages, using a redirect to DuckDuckGo's search engine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A table of contents&lt;/strong&gt;: Longer articles show a table of contents, so you jump straight to the section you need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better use of &lt;a href="https://dev.to/tags"&gt;tags&lt;/a&gt;&lt;/strong&gt;: The tags got reviewed and have a short introduction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More RSS feeds&lt;/strong&gt;: Each section and tag exposes its own feed, so you follow only the parts that interest you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href=""&gt;Open source projects&lt;/a&gt;&lt;/strong&gt;: Highlighted projects that I work on, like Lottie4J, Pi4J, MelodyMatrix, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On top of these, the redesign carries dozens of smaller tweaks to typography, spacing, images, table layouts, and the metadata that drives social sharing.&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%2Fad120sgubnw91paux3v8.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%2Fad120sgubnw91paux3v8.png" alt="New version with the dark theme" width="800" height="892"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Claude Code helped
&lt;/h2&gt;

&lt;p&gt;I built a large part of this redesign together with &lt;a href="https://www.claude.com/product/claude-code" rel="noopener noreferrer"&gt;Claude Design and Code&lt;/a&gt;. It handled the repetitive Hugo template work, generated the new theme partials, and helped me track down the small details that make a site feel finished. One example: the social preview images now resolve correctly for every page, which used to break when I shared a link on LinkedIn.&lt;/p&gt;

&lt;p&gt;Pairing with an AI assistant on this kind of project changes the pace. I describe what I want, Claude Code writes the template, and I review the result and adjust. The work that used to take an evening of fiddling now takes a focused hour.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tell me what you think
&lt;/h2&gt;

&lt;p&gt;The site keeps the same address and all the old links still work, so nothing you bookmarked should be broken. Take a look at the new &lt;a href="https://webtechie.be" rel="noopener noreferrer"&gt;webtechie.be&lt;/a&gt;, try the search box and the dark mode, and let me know what works for you and what does not. Your feedback helps me to further improve!&lt;/p&gt;

</description>
      <category>hugo</category>
      <category>blog</category>
      <category>claude</category>
    </item>
    <item>
      <title>Lottie4J Meets LottieFiles: A Conversation with Naail Abdul Rahman</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Thu, 04 Jun 2026 09:27:07 +0000</pubDate>
      <link>https://dev.to/fdelporte/lottie4j-meets-lottiefiles-a-conversation-with-naail-abdul-rahman-1gd3</link>
      <guid>https://dev.to/fdelporte/lottie4j-meets-lottiefiles-a-conversation-with-naail-abdul-rahman-1gd3</guid>
      <description>&lt;p&gt;Lottie animations run on Android, iOS, and the web. Getting them working on the JVM is a different story. &lt;a href="https://lottie4j.com" rel="noopener noreferrer"&gt;Lottie4J&lt;/a&gt; started as a question: can JavaFX render them without a WebView? That question turned into a library with a first release in March 2026! Since then, I received the first pull requests, recently added headless unit testing with JavaFX 26, and now this: a video conversation with Naail from the LottieFiles team.&lt;/p&gt;

&lt;p&gt;I got to sit down with &lt;a href="https://www.linkedin.com/in/kudanai/" rel="noopener noreferrer"&gt;Naail Abdul Rahman&lt;/a&gt;, R&amp;amp;D engineer at LottieFiles, the company behind the Lottie animation platform. We talked about where the format came from, where it is going, and what that means for a Java implementation like Lottie4J.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  What we talked about
&lt;/h2&gt;

&lt;p&gt;The conversation covers a lot, so here is a quick overview of the topics if you want to jump to a specific part:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;00:00 Introduction of Lottie and Naail&lt;/li&gt;
&lt;li&gt;04:57 Use cases for Lottie animations, e.g. sprites in games, on ESP32,...&lt;/li&gt;
&lt;li&gt;06:21 History of the Android Airbnb player&lt;/li&gt;
&lt;li&gt;08:07 About Lottie4J, the Java(FX) player&lt;/li&gt;
&lt;li&gt;10:31 Nice Lottie animation examples&lt;/li&gt;
&lt;li&gt;14:44 Early history of Lottie, started as Bodymovin&lt;/li&gt;
&lt;li&gt;15:54 .json Lottie versus .zip dotLottie formats&lt;/li&gt;
&lt;li&gt;18:24 "Example Drive Development" of Lottie4J and headless unit testing with JavaFX 26&lt;/li&gt;
&lt;li&gt;19:40 About the Lottie Animation Community (LAC)&lt;/li&gt;
&lt;li&gt;22:43 Lottie format documentation with live examples&lt;/li&gt;
&lt;li&gt;24:52 Taking a look at the web viewer and other tools on the LottieFiles website&lt;/li&gt;
&lt;li&gt;27:20 What the LottieFiles Team Plan offers&lt;/li&gt;
&lt;li&gt;29:07 Lottie animations can be exported from After Effects and Figma&lt;/li&gt;
&lt;li&gt;30:07 Experiments with AI to generate animations&lt;/li&gt;
&lt;li&gt;32:36 LottieFiles Marketspace with free available animations&lt;/li&gt;
&lt;li&gt;33:26 What should be the next steps for Lottie4J?&lt;/li&gt;
&lt;li&gt;35:50 What's on the LottieFiles roadmap&lt;/li&gt;
&lt;li&gt;39:38 Can Lottie4J be validated to be compliant with the community specification?&lt;/li&gt;
&lt;li&gt;41:47 Growing interest in Lottie for desktop applications (KDE)&lt;/li&gt;
&lt;li&gt;42:53 Where to start if you're interested in Lottie&lt;/li&gt;
&lt;li&gt;44:03 Pull requests received for Lottie4J&lt;/li&gt;
&lt;li&gt;47:34 Looking into a pending Lottie4J issue&lt;/li&gt;
&lt;li&gt;49:04 JavaFX gains more popularity as desktop applications become more important in AI use&lt;/li&gt;
&lt;li&gt;50:05 Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lottie: from Bodymovin to everywhere
&lt;/h2&gt;

&lt;p&gt;One thing I always find interesting about the Lottie format is that it did not start at LottieFiles. It started as &lt;a href="https://aescripts.com/bodymovin/" rel="noopener noreferrer"&gt;Bodymovin&lt;/a&gt;, an After Effects plugin for exporting animations to the web. Airbnb picked it up, built their Android player around it, and the name Lottie stuck. From there the format spread across platforms, communities, and now also into Java.&lt;/p&gt;

&lt;p&gt;The open-source specification lives at &lt;a href="https://lottie.github.io" rel="noopener noreferrer"&gt;lottie.github.io&lt;/a&gt;, driven by the Lottie Animation Community (LAC). That is the reference Lottie4J works against.&lt;/p&gt;

&lt;h2&gt;
  
  
  dotLottie: the format worth paying attention to
&lt;/h2&gt;

&lt;p&gt;Most Lottie work today happens with &lt;code&gt;.json&lt;/code&gt; files. The dotLottie format (&lt;code&gt;.lottie&lt;/code&gt;) is a ZIP container that can hold multiple animations, theming through slots, and interactive state machines, all in one file. It is where things are heading, and it is definitely what I need to add proper support for in Lottie4J.&lt;/p&gt;

&lt;p&gt;The difference matters practically. A &lt;code&gt;.lottie&lt;/code&gt; file compresses much better than the equivalent JSON, it can bundle assets cleanly, and the slots and states features open up real interactivity that a static JSON animation just cannot do.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for Lottie4J
&lt;/h2&gt;

&lt;p&gt;The conversation pushed me to think concretely about where to take the project next. Three areas stood out as important steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compliance checking against the LAC specification. Naail mentioned this is something the community wants more of. Knowing which features Lottie4J supports accurately gives the community a clear picture of where the project stands.&lt;/li&gt;
&lt;li&gt;Better dotLottie support, including multiple animations in a single file and eventually slots and state machines.&lt;/li&gt;
&lt;li&gt;The headless JavaFX 26 testing setup I recently documented is a real step forward for CI reliability. That blog post is &lt;a href="https://webtechie.be/post/2026-04-20-lottie4j-unit-test-with-headless-javafx/" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you want the details.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another important moment in the conversation: Naail noted that interest in Lottie for desktop applications is growing, including from projects like KDE. JavaFX is in good company there! Even more right now, considering the recent announcement by Oracle that are now offering extended JavaFX support. This is something &lt;a href="https://www.azul.com/blog/the-javafx-revival-good-news-for-the-community-business-as-usual-for-azul/" rel="noopener noreferrer"&gt;Azul has done for years&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links from the video
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Lottie_(file_format)" rel="noopener noreferrer"&gt;Lottie format Wikipedia article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Lottie4J

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lottie4j.com" rel="noopener noreferrer"&gt;Lottie4J&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lottie4j/" rel="noopener noreferrer"&gt;Sources on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://webtechie.be/post/2026-04-20-lottie4j-unit-test-with-headless-javafx/" rel="noopener noreferrer"&gt;Blog: Headless unit testing with JavaFX 26&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Lottie

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lottie.github.io/" rel="noopener noreferrer"&gt;Open-source specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lottie/lottie.github.io/issues" rel="noopener noreferrer"&gt;Animation Community issues and spec work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lottie.github.io/implementations/" rel="noopener noreferrer"&gt;Community implementations list&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;LottieFiles:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lottiefiles.com/free-animations/loading-bar" rel="noopener noreferrer"&gt;Free animations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lottiefiles.com/education" rel="noopener noreferrer"&gt;Education resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lottiefiles.com/integrations#embed-lottie-libraries" rel="noopener noreferrer"&gt;Integrations page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lottiefiles.github.io/lottie-docs/playground/json_editor/" rel="noopener noreferrer"&gt;Lottie JSON playground&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;LottieFiles Case Studies:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lottiefiles.com/case-studies/Walmart" rel="noopener noreferrer"&gt;Walmart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lottiefiles.com/case-studies/cnn-create" rel="noopener noreferrer"&gt;CNN Create&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lottiefiles.com/case-studies/robinhood" rel="noopener noreferrer"&gt;Robinhood&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apps.kde.org/glaxnimate/" rel="noopener noreferrer"&gt;Glaxnimate (KDE animation tool)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/alexzhirkevich/compottie" rel="noopener noreferrer"&gt;Compottie (Kotlin Multiplatform player)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.thorvg.org/" rel="noopener noreferrer"&gt;ThorVG (C++ rendering library)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The conversation confirmed something I suspected: Lottie4J is not a niche experiment. Desktop animation is getting serious attention across the Java and Linux ecosystems. If you want to help shape where Lottie4J goes next, head over to &lt;a href="https://lottie4j.com" rel="noopener noreferrer"&gt;lottie4j.com&lt;/a&gt;. Pull requests, bug reports, and questions are all welcome in the comments of the video or in the &lt;a href="https://github.com/lottie4j/" rel="noopener noreferrer"&gt;Lottie4J GitHub project&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>javafx</category>
      <category>lottie</category>
      <category>desktop</category>
    </item>
    <item>
      <title>Debugging BentoFX in MelodyMatrix with Matt Coley, Scenic View, and an Honest Look at AI-Generated Code</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Tue, 21 Apr 2026 10:01:21 +0000</pubDate>
      <link>https://dev.to/fdelporte/debugging-bentofx-in-melodymatrix-with-matt-coley-scenic-view-and-an-honest-look-at-ai-generated-27c9</link>
      <guid>https://dev.to/fdelporte/debugging-bentofx-in-melodymatrix-with-matt-coley-scenic-view-and-an-honest-look-at-ai-generated-27c9</guid>
      <description>&lt;p&gt;There are bugs you can solve by yourself, and bugs where you just need to sit down with someone who knows the internals. This video is in the second category. &lt;a href="https://melodymatrix.rocks/" rel="noopener noreferrer"&gt;MelodyMatrix&lt;/a&gt; uses &lt;a href="https://github.com/Col-E/BentoFX" rel="noopener noreferrer"&gt;BentoFX&lt;/a&gt; for its dockable panel layout. Branches, leaves, tabs on the side, content panels that open and close. It works well until something fights the layout. But I had some visual problems I could not explain, some code that felt more complicated than it should be, and no good explanation for why.&lt;/p&gt;

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

&lt;h1&gt;
  
  
  When Your Layout Library Misbehaves, Call the Person Who Wrote It
&lt;/h1&gt;

&lt;p&gt;So I asked &lt;a href="https://www.coley.software/" rel="noopener noreferrer"&gt;Matt Coley&lt;/a&gt; if he had time to take a look. Matt is the creator of BentoFX, but he is also known for &lt;a href="https://www.jfx-central.com/showcases/recaf" rel="noopener noreferrer"&gt;Recaf&lt;/a&gt;, a bytecode editor for Java that itself uses BentoFX heavily as its UI framework. That means when Matt looks at a BentoFX integration. He wrote the library and uses it heavily in his own project. If you want the full background on his work, there is an earlier interview: &lt;a href="https://webtechie.be/post/2025-10-30-jfxinaction-matt-coley-recaf-bentofx-treemapfx-glcanvasfx/" rel="noopener noreferrer"&gt;JavaFX In Action #22 with Matt Coley&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What BentoFX Actually Does
&lt;/h2&gt;

&lt;p&gt;BentoFX is a docking and layout library for JavaFX. The core idea is that you have a tree of containers: branches split the space horizontally (or vertically if you rotate them), and leaves hold the actual content. Tabs let you stack multiple panels in one leaf.&lt;/p&gt;

&lt;p&gt;In MelodyMatrix, this maps to a sidebar on the left, a main content area in the middle, and additional panels on the right. It is a clean model when you understand it, but there are some behaviors that are not immediately obvious. Pruning is one of them: when you close a panel, BentoFX removes the empty container and reorganizes the remaining branches. That is usually what you want, but if you are also managing widths or visibility yourself in code, things start to conflict. That was part of my problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenic View: Browser DevTools for JavaFX
&lt;/h2&gt;

&lt;p&gt;This session reminded me that &lt;a href="https://www.jfx-central.com/tools/scenicview" rel="noopener noreferrer"&gt;Scenic View&lt;/a&gt; exists and I should have been using it much earlier.&lt;/p&gt;

&lt;p&gt;If you have done any web development, you know how useful browser inspect tools are. You hover over an element, you can see exactly what CSS is applied, what the padding is, why something is shifted by 12 pixels. Scenic View does the same thing for a running JavaFX application. It attaches to your running application and shows the scene graph live with all the layout properties.&lt;/p&gt;

&lt;p&gt;We pulled it during the video to look at the tab header rotation issue I was having. Instead of guessing which CSS rule was causing the offset, we could see exactly what was happening in the layout tree. Embarrassingly, I had not used it before this session. It should be in your JavaFX debugging toolkit!&lt;/p&gt;

&lt;h2&gt;
  
  
  Some Honest Thoughts on AI-Generated Code
&lt;/h2&gt;

&lt;p&gt;We also spent some time looking at code that had been written or modified by Claude and Copilot. Matt spotted it quickly: the code had the patterns you recognize after reviewing AI-generated output. The rotation fix for the tab headers was one example. The code did technically work, but it was fragile: it used CSS class lookups that would break if BentoFX changed anything internally. Matt's take was pragmatic: if it works now, and you have a way to update it when it breaks, fine. But it is worth knowing that is what you are dealing with.&lt;/p&gt;

&lt;p&gt;The broader cleanup was straightforward once Matt explained how BentoFX manages its own leaf widths. I had added animation and width-tracking code essentially fighting the library. Removing it simplified things considerably and fixed one of the issues in the process. Not all AI-generated code is bad. But a code review from someone who knows the library beats prompting your way through it. This session was a good reminder of that.&lt;/p&gt;

&lt;h2&gt;
  
  
  We Might Have Found a Bug
&lt;/h2&gt;

&lt;p&gt;BentoFX did something unexpected with divider modes when re-opening a panel that had been closed. Matt looked at his own source and said he suspected something was not right there. It is a 0.x library, but it is actively maintained and used in production in Recaf. Matt's response was immediate: file a ticket with reproduction steps.&lt;/p&gt;

&lt;h1&gt;
  
  
  Timeline
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;00:00 Introduction: Matt Coley, Recaf, BentoFX&lt;/li&gt;
&lt;li&gt;02:19 How BentoFX is used in MelodyMatrix&lt;/li&gt;
&lt;li&gt;04:18 Visual problems with the BentoFX integration&lt;/li&gt;
&lt;li&gt;06:33 A look into the MelodyMatrix code&lt;/li&gt;
&lt;li&gt;09:15 Changing tab position from top to side, and why the project uses Kotlin&lt;/li&gt;
&lt;li&gt;16:25 Using Scenic View to debug a JavaFX layout live&lt;/li&gt;
&lt;li&gt;22:38 How pruning affects visual BentoFX components&lt;/li&gt;
&lt;li&gt;34:53 Cleaning up unneeded code: let BentoFX handle leaf widths, removing animations&lt;/li&gt;
&lt;li&gt;41:33 We probably found a bug in BentoFX, and a look into the BentoFX source&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Links
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://webtechie.be/post/2025-10-30-jfxinaction-matt-coley-recaf-bentofx-treemapfx-glcanvasfx/" rel="noopener noreferrer"&gt;JavaFX In Action #22 with Matt Coley, diving into bytecode and JARs with Recaf and JavaFX libraries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Matt Coley: 

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Col-E" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.coley.software/" rel="noopener noreferrer"&gt;Website&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jfx-central.com/people/m.coley" rel="noopener noreferrer"&gt;JFX Central&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JavaFX libraries by Matt: 

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Col-E/BentoFX" rel="noopener noreferrer"&gt;BentoFX&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Col-E/TreeMapFX" rel="noopener noreferrer"&gt;TreeMapFX&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Col-E/GLCanvasFX" rel="noopener noreferrer"&gt;GLCanvasFX&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;On JFX Central: 

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.jfx-central.com/libraries/bentofx" rel="noopener noreferrer"&gt;BentoFX&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.jfx-central.com/showcases/recaf" rel="noopener noreferrer"&gt;Recaf&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.jfx-central.com/libraries/pdffx" rel="noopener noreferrer"&gt;PDFViewFX&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jfx-central.com/tools/scenicview" rel="noopener noreferrer"&gt;Scenic View&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MelodyMatrix: 

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://melodymatrix.rocks/" rel="noopener noreferrer"&gt;Website&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/codewriterbv/melodymatrix-app-views" rel="noopener noreferrer"&gt;Open-source viewers on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>javafx</category>
      <category>bentofx</category>
      <category>melodymatrix</category>
    </item>
    <item>
      <title>Testing Lottie4J JavaFX Animations in GitHub Actions Without a Display: JavaFX 26 Headless to the Rescue</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Mon, 20 Apr 2026 06:44:35 +0000</pubDate>
      <link>https://dev.to/fdelporte/testing-lottie4j-javafx-animations-in-github-actions-without-a-display-javafx-26-headless-to-the-35ap</link>
      <guid>https://dev.to/fdelporte/testing-lottie4j-javafx-animations-in-github-actions-without-a-display-javafx-26-headless-to-the-35ap</guid>
      <description>&lt;p&gt;When I released &lt;a href="https://lottie4j.com/releases/#2026-03-10-110" rel="noopener noreferrer"&gt;Lottie4J 1.1.0&lt;/a&gt;, I mentioned something a bit embarrassing in the release notes and &lt;a href="https://webtechie.be/post/2026-03-10-new-release-of-lottie4j/" rel="noopener noreferrer"&gt;this blog post&lt;/a&gt;: there was a new unit test to compare the JavaFX player output against a JavaScript reference player, but it "&lt;em&gt;can not run on CI, because it requires a display output&lt;/em&gt;." A TODO. A known limitation. One of those notes you write hoping future-you will figure it out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gluonhq.com/javafx-26-is-now-available/" rel="noopener noreferrer"&gt;JavaFX 26 was released on March 17, 2026&lt;/a&gt; and includes a new headless platform, allowing me to get the test running on GitHub Actions without a display.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Test, and Why It Mattered
&lt;/h2&gt;

&lt;p&gt;The core challenge with Lottie4J is correctness. The Lottie format is complex with a lot of nested data, and my JavaFX renderer has to produce output that matches what a JavaScript player would show. Pixel-perfect is too ambitious, but "is this a close enough match" is a reasonable bar.&lt;/p&gt;

&lt;p&gt;During development, I use a separate application within the Lottie4J project: &lt;a href="https://github.com/lottie4j/lottie4j/blob/main/fxfileviewer/src/main/java/com/lottie4j/fxfileviewer/LottieFileDebugViewer.java" rel="noopener noreferrer"&gt;LottieFileDebugViewer&lt;/a&gt;. This is a JavaFX application that loads a Lottie file and renders it both with the JavaFX player, and inside a Webview with the official Lottie player. This makes it easy to compare the result and debug differences by diving into the data structure and different layers.&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%2Fcqg52ojiopcd7jhhnunb.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%2Fcqg52ojiopcd7jhhnunb.png" alt="Lottie4J debug viewer for local testing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on this debug viewer, I created a unit-test approach with two steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A &lt;a href="https://github.com/lottie4j/lottie4j/blob/main/fxfileviewer/src/test/java/com/lottie4j/fxfileviewer/WebViewScreenshotGenerator.java" rel="noopener noreferrer"&gt;WebViewScreenshotGenerator&lt;/a&gt; that I run once on my developer machine. It loads each animation in a JavaFX WebView using the LottieFiles JavaScript player, and captures screenshots of specific frames. These are the reference images and are committed to the repo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The unit test &lt;a href="https://github.com/lottie4j/lottie4j/blob/main/fxfileviewer/src/test/java/com/lottie4j/fxfileviewer/CompareFxViewWithWebViewTest.java" rel="noopener noreferrer"&gt;CompareFxViewWithWebViewTest&lt;/a&gt; then renders the same animations with the Lottie4J JavaFX player, takes screenshots at the same frames, and compares pixel data against the references.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The reference images are generated once and committed. The test just checks that the JavaFX output stays consistent with them. If something breaks in the renderer, the test will catch it.&lt;/p&gt;

&lt;p&gt;This was all working fine locally. The problem was GitHub Actions. The CI runner has no display and no graphics stack. So I disabled this test for CI with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@DisabledIfEnvironmentVariable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;named&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"CI"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What Changed in JavaFX 26
&lt;/h2&gt;

&lt;p&gt;JavaFX 26 added a &lt;a href="https://openjfx.io/highlights/26/" rel="noopener noreferrer"&gt;Headless Platform Prototype&lt;/a&gt; built directly into the &lt;code&gt;javafx.graphics&lt;/code&gt; module. No extra dependencies, no native libraries, no Monocle setup. You pass a single JVM flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-Dglass.platform=headless
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it. JavaFX starts up, you get a functional toolkit, you can create scenes, render nodes, take snapshots, and run animations, all without a display attached. The &lt;a href="https://gluonhq.com/" rel="noopener noreferrer"&gt;Gluon team&lt;/a&gt; did the heavy lifting on this for JavaFX 26, and it makes CI testing of JavaFX components much more practical. The flag works the same way as running your application normally. The difference is that there is nothing being drawn to a screen. For testing purposes, that is exactly what you want. It also opens the door to server-side rendering, for example, to generate a snapshot of a UI component without a display.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Catch: JavaFX 26 Requires Java 24
&lt;/h2&gt;

&lt;p&gt;Lottie4J targets &lt;a href="https://github.com/lottie4j/lottie4j/blob/main/pom.xml#L38" rel="noopener noreferrer"&gt;Java 21 and JavaFX 21&lt;/a&gt;. That is the LTS version most projects are still running on. As this version is widely adopted, I don't want to force users of the library to jump to a newer version just because I want fancier test infrastructure. So the main project stays on 21 (for now).&lt;/p&gt;

&lt;p&gt;But JavaFX 26 &lt;a href="https://openjfx.io/highlights/26/" rel="noopener noreferrer"&gt;requires Java 24 or higher&lt;/a&gt; to run. They bumped the compiled bytecode level to &lt;code&gt;--release 24&lt;/code&gt; in this release, so if you try to use it with an older JDK you get an error immediately. This means the test infrastructure has to use a different Java and JavaFX version than the main build. The solution I landed on was a Maven profile in the &lt;a href="https://github.com/lottie4j/lottie4j/blob/main/pom.xml#L50" rel="noopener noreferrer"&gt;root pom.xml&lt;/a&gt; that overrides both version properties and configures the surefire plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;profile&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Activates JavaFX 26 headless windowing for unit tests in CI. --&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Usage: mvn test -Pheadless-tests --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;headless-tests&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;java.version&amp;gt;&lt;/span&gt;25&lt;span class="nt"&gt;&amp;lt;/java.version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;javafx.version&amp;gt;&lt;/span&gt;26&lt;span class="nt"&gt;&amp;lt;/javafx.version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;surefire.argLine.headless&amp;gt;&lt;/span&gt;
            -Dglass.platform=headless --enable-native-access=javafx.graphics
        &lt;span class="nt"&gt;&amp;lt;/surefire.argLine.headless&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-surefire-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.0.0-M5&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;argLine&amp;gt;&lt;/span&gt;
                        --add-opens com.lottie4j.fxfileviewer/com.lottie4j.fxfileviewer=ALL-UNNAMED
                        -Dglass.platform=headless --enable-native-access=javafx.graphics
                    &lt;span class="nt"&gt;&amp;lt;/argLine&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/profile&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When this profile is active, Maven bumps &lt;code&gt;java.version&lt;/code&gt; to 25 and &lt;code&gt;javafx.version&lt;/code&gt; to 26, so the dependency resolution picks up JavaFX 26 for the test classpath while the main source still compiles to Java 21 targets. The surefire plugin then passes two JVM arguments to the test JVM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-Dglass.platform=headless&lt;/code&gt; tells JavaFX to use the new headless glass backend instead of trying to connect to a display.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--enable-native-access=javafx.graphics&lt;/code&gt; is required because the headless platform uses native code paths that the Java module system would otherwise block.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;--add-opens&lt;/code&gt; line gives the test runner access to the fxfileviewer module internals it needs to load and compare the rendered output.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/lottie4j/lottie4j/blob/main/fxfileviewer/pom.xml#L95" rel="noopener noreferrer"&gt;fxfileviewer/pom.xml&lt;/a&gt; and &lt;a href="https://github.com/lottie4j/lottie4j/blob/main/fxplayer/pom.xml#L52" rel="noopener noreferrer"&gt;fxplayer/pom.xml&lt;/a&gt; pick up the overridden &lt;code&gt;javafx.version&lt;/code&gt; property through normal Maven inheritance, so those modules automatically get JavaFX 26 on the test classpath when the profile is active.&lt;/p&gt;

&lt;h2&gt;
  
  
  The GitHub Actions Side
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/lottie4j/lottie4j/blob/main/.github/workflows/maven.yml#L26" rel="noopener noreferrer"&gt;Maven workflow&lt;/a&gt; sets up the environment with a Java 25 JDK so the JavaFX 26 runtime can load, and invokes Maven with the profile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-Pheadless-tests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rest of the build still compiles against Java 21 targets, so the library artifact itself is not affected. The profile only kicks in for the test run. The workflow does not need any display setup, no &lt;code&gt;Xvfb&lt;/code&gt;, no &lt;code&gt;DISPLAY&lt;/code&gt; environment variable tweaks. The headless flag handles all of that!&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Actually Tests
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/lottie4j/lottie4j/blob/main/fxfileviewer/src/test/java/com/lottie4j/fxfileviewer/CompareFxViewWithWebViewTest.java" rel="noopener noreferrer"&gt;unit test compares screenshots&lt;/a&gt; of Lottie animations rendered by the JavaFX player against the pre-generated reference images from the JavaScript player. It loads a set of known animation files, renders specific frames from each one, takes a snapshot using &lt;code&gt;WritableImage&lt;/code&gt; and &lt;code&gt;SnapshotParameters&lt;/code&gt;, and then does a pixel-level comparison with a configurable tolerance.&lt;/p&gt;

&lt;p&gt;The result is a regression test that runs on every push. If someone changes the rendering logic in a way that visibly breaks an animation, CI will catch it. This is more useful than it sounds, because Lottie rendering involves a lot of layered transformations, easing functions, and shape operations where subtle bugs are easy to introduce.&lt;/p&gt;

&lt;h2&gt;
  
  
  Would I Recommend This Pattern?
&lt;/h2&gt;

&lt;p&gt;Yes, with some caveats.&lt;/p&gt;

&lt;p&gt;The version juggling is real work. If you want to use JavaFX 26 headless for testing while keeping your library on an older Java version, you need to be careful about separating the test JVM configuration from the main build. Maven makes this doable but not exactly elegant.&lt;/p&gt;

&lt;p&gt;The reference image approach also requires discipline. The references need to be generated consistently, ideally on a reproducible setup, and you need to think about what tolerance makes sense for your comparisons. Too strict and you get flaky tests. Too loose and you miss real regressions.&lt;/p&gt;

&lt;p&gt;But the payoff is real. The test that I had marked "can not run on CI" now runs on CI. No virtual framebuffer, no Docker tricks, no manual intervention. JavaFX starts up, renders the animations, and the comparison happens cleanly.&lt;/p&gt;

&lt;p&gt;For any library that does visual rendering in JavaFX, this is the kind of testing infrastructure that was genuinely missing before. Good work, OpenJFX contributors!&lt;/p&gt;




&lt;p&gt;Links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lottie4j.com/" rel="noopener noreferrer"&gt;Lottie4J website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lottie4j/lottie4j" rel="noopener noreferrer"&gt;Lottie4J on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openjfx.io/highlights/26/" rel="noopener noreferrer"&gt;JavaFX 26 Highlights&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gluonhq.com/introducing-the-headless-platform-for-javafx/" rel="noopener noreferrer"&gt;Gluon: Introducing the Headless Platform for JavaFX&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gluonhq.com/javafx-26-is-now-available/" rel="noopener noreferrer"&gt;Gluon: JavaFX 26 is Now Available&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>javafx</category>
      <category>lottie</category>
      <category>lottie4j</category>
    </item>
    <item>
      <title>MelodyMatrix V1.0.0 Released: Shipping a JavaFX App with jDeploy, GitHub Actions, and Auto-Update</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Thu, 16 Apr 2026 09:57:28 +0000</pubDate>
      <link>https://dev.to/fdelporte/melodymatrix-v100-released-shipping-a-javafx-app-with-jdeploy-github-actions-and-auto-update-5dba</link>
      <guid>https://dev.to/fdelporte/melodymatrix-v100-released-shipping-a-javafx-app-with-jdeploy-github-actions-and-auto-update-5dba</guid>
      <description>&lt;p&gt;Some side projects take a while to get to a proper release. &lt;a href="https://melodymatrix.rocks/" rel="noopener noreferrer"&gt;MelodyMatrix&lt;/a&gt; is one of those. The app has been downloadable for quite some time thanks to &lt;a href="https://www.jdeploy.com/" rel="noopener noreferrer"&gt;jDeploy&lt;/a&gt;, but there was no official V1.0.0 yet. No tagged release. No moment of "okay, this is it." Just a rolling build on every commit to the &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;

&lt;p&gt;That changed now: live, on camera, together with Steve Hannah, the creator of jDeploy.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  What Is MelodyMatrix?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://melodymatrix.rocks/" rel="noopener noreferrer"&gt;MelodyMatrix&lt;/a&gt; is a JavaFX application for musicians. It connects to MIDI devices, lets you practice and record, and has a set of views that help you understand what you are playing. Those views are open source and available on &lt;a href="https://github.com/codewriterbv/melodymatrix-app-views" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. The full app is free, but has some features that are only available with a license. The download packages are published via &lt;a href="https://github.com/codewriterbv/melodymatrix-app-releases/releases" rel="noopener noreferrer"&gt;GitHub Releases&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Building it has been a long journey. JavaFX, MIDI, and musical theory in one app, keeping it working across Windows, macOS, and Linux, while also building and distributing it automatically from GitHub Actions. That last part is where jDeploy comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is jDeploy?
&lt;/h2&gt;

&lt;p&gt;If you have not heard of jDeploy yet, Steve explains it very well in a few sentences: "&lt;em&gt;Once you finish building a desktop application, you hit a wall. How do you share it? How does your user install it? And when you update it, how do they get the new version without manually downloading and reinstalling?&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;jDeploy solves all of that. It creates native installers for Windows (&lt;code&gt;.exe&lt;/code&gt;), macOS (&lt;code&gt;.dmg&lt;/code&gt;), and Linux, handles auto-update on launch, bundles its own JVM so users do not need Java installed, and uses GitHub Releases as the distribution backend. No Maven Central, no NPM account required. Your GitHub repo is your distribution channel.&lt;/p&gt;

&lt;p&gt;I did a full interview with Steve earlier where he explains the background of the tool: &lt;a href="https://webtechie.be/post/2024-12-12-jfxinaction-steve-hannah-jdeploy/" rel="noopener noreferrer"&gt;JavaFX In Action #12 with Steve Hannah about jDeploy&lt;/a&gt;. Worth watching if you want the full picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Video: Preparing and Triggering the First Release Together
&lt;/h2&gt;

&lt;p&gt;This new video is about an hour long and covers the whole process of getting MelodyMatrix ready for V1.0.0. Steve joined me, and we walked through the project configuration together, fixed a few things in the GitHub Actions workflow, discussed best practices around git tags, and then actually triggered the first release build while the camera was still running.&lt;/p&gt;

&lt;p&gt;Some of the things we covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How jDeploy is configured in the MelodyMatrix project, including how JavaFX preview features are enabled.&lt;/li&gt;
&lt;li&gt;npm versus GitHub for the release packages (short version: npm was much easier to get started with than Maven, and Steve modeled the GitHub metadata format on the npm package format).&lt;/li&gt;
&lt;li&gt;Why the Windows installer is an &lt;code&gt;.exe&lt;/code&gt; file and not a zip (user experience: download, click, done).&lt;/li&gt;
&lt;li&gt;How jDeploy manages its own JVM per platform (default is Zulu, with some platform-specific exceptions for Windows ARM and Linux).&lt;/li&gt;
&lt;li&gt;Why Maven is not used for application distribution, and why Steve holds his breath every time he does a Maven deploy.&lt;/li&gt;
&lt;li&gt;How to set the version number for a release without breaking the path to your jar file.&lt;/li&gt;
&lt;li&gt;How to prevent multiple jDeploy workflows from running simultaneously.&lt;/li&gt;
&lt;li&gt;Best practices around git tags, including the capital V versus lowercase v debate.&lt;/li&gt;
&lt;li&gt;Customizing the installer and launcher splash screen with a custom HTML page.&lt;/li&gt;
&lt;li&gt;How jDeploy can use a local build to test the installation before pushing to GitHub.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And around the 57-minute mark, the release build finished on GitHub Actions and &lt;strong&gt;MelodyMatrix V1.0.0 was live&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why jDeploy, and Why It Is Free
&lt;/h2&gt;

&lt;p&gt;jDeploy is completely free! Steve wants Java desktop apps to be easy to deploy, and any barrier to entry works against that goal. He is working on a paid tier with private repositories and deployment authentication, but the core tool stays free.&lt;/p&gt;

&lt;p&gt;For a solo developer building a side project like MelodyMatrix, that matters. I can push a new version by tagging a commit, and within minutes there is a new installer available for every platform. Users get it automatically on the next launch. No manual distribution, no "please re-download the installer" emails.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Side Note on Lottie4J
&lt;/h2&gt;

&lt;p&gt;While waiting for the GitHub Actions build to finish, Steve mentioned he had been experimenting with adding Lottie animation support to the jDeploy splash screen, and we talked about &lt;a href="https://lottie4j.com/" rel="noopener noreferrer"&gt;Lottie4J&lt;/a&gt; for a bit. That is the kind of thing that happens in a live session. :-) Steve even built a Claude Code skill for creating a custom HTML splash screen with a LottieFiles animation. If you want to try it: &lt;a href="https://github.com/shannah/jdeploy-claude" rel="noopener noreferrer"&gt;jdeploy-claude on GitHub&lt;/a&gt; and the &lt;a href="https://github.com/shannah/jdeploy-claude/tree/main/plugins/jdeploy/skills/custom-launcher-splash" rel="noopener noreferrer"&gt;custom launcher splash screen skill&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timeline
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;00:00 Introduction&lt;/li&gt;
&lt;li&gt;00:48 Who is Steve Hannah and why he created jDeploy to distribute Java applications with automatic updates&lt;/li&gt;
&lt;li&gt;05:42 How Frank uses jDeploy for MelodyMatrix, demo of the application&lt;/li&gt;
&lt;li&gt;07:26 jDeploy configuration in the MelodyMatrix project, how JavaFX preview features are enabled, GitHub Actions&lt;/li&gt;
&lt;li&gt;08:32 How new versions get distributed, npm versus Maven versus GitHub&lt;/li&gt;
&lt;li&gt;10:56 A look into the GitHub Actions flow for MelodyMatrix&lt;/li&gt;
&lt;li&gt;13:38 Why Maven is not used for application distribution&lt;/li&gt;
&lt;li&gt;16:38 Why the Windows installer is an &lt;code&gt;.exe&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;23:13 The JVM runtimes used by a jDeploy application&lt;/li&gt;
&lt;li&gt;26:05 Modifying the splash screen of the installer and application&lt;/li&gt;
&lt;li&gt;28:23 The jDeploy desktop app to configure your project&lt;/li&gt;
&lt;li&gt;31:46 Preparing the MelodyMatrix project for the first release, how to set the release version number, and improving the GitHub workflow&lt;/li&gt;
&lt;li&gt;40:45 Info about the open-source part of the MelodyMatrix project and the struggle between Gradle and Maven&lt;/li&gt;
&lt;li&gt;42:59 Checking the GitHub Actions for the release, and more improvements to prevent multiple simultaneous jDeploy workflows&lt;/li&gt;
&lt;li&gt;45:39 Best practices regarding the use of git tags&lt;/li&gt;
&lt;li&gt;48:42 Starting the build of the first MelodyMatrix release as V1.0.0!&lt;/li&gt;
&lt;li&gt;49:40 While the build process is running on GitHub Actions, experimenting with jDeploy locally&lt;/li&gt;
&lt;li&gt;54:34 Release builds on GitHub Actions are still busy, so another side step to LottieFiles and Lottie4J, and how they could be integrated in the jDeploy splash screen&lt;/li&gt;
&lt;li&gt;57:41 The first release is ready. Installing and trying it...&lt;/li&gt;
&lt;li&gt;01:00:40 jDeploy is free! Steve just wants Java to be easy to deploy&lt;/li&gt;
&lt;li&gt;01:02:31 Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://webtechie.be/post/2024-12-12-jfxinaction-steve-hannah-jdeploy/" rel="noopener noreferrer"&gt;JavaFX In Action #12 with Steve Hannah about jDeploy, to distribute your Java app as a native bundle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Steve Hannah: 

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.linkedin.com/in/sjhannah/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://x.com/shannah78" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://sjhannah.com/blog/" rel="noopener noreferrer"&gt;Personal blog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MelodyMatrix: 

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://melodymatrix.rocks/" rel="noopener noreferrer"&gt;Website&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/codewriterbv/melodymatrix-app-views" rel="noopener noreferrer"&gt;Open-source viewers on GitHub&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/codewriterbv/melodymatrix-app-releases/releases" rel="noopener noreferrer"&gt;Download packages on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;jDeploy: 

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.jdeploy.com/" rel="noopener noreferrer"&gt;Website&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shannah/jdeploy" rel="noopener noreferrer"&gt;Sources on GitHub&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jdeploy.substack.com/" rel="noopener noreferrer"&gt;Newsletter&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jdeploy.substack.com/p/jdeploy-vs-jpackage" rel="noopener noreferrer"&gt;jDeploy vs jpackage&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://jdeploy.substack.com/p/now-you-can-deploy-your-app-as-a" rel="noopener noreferrer"&gt;Now you can deploy your app as a DMG&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shannah/jdeploy-claude" rel="noopener noreferrer"&gt;Claude Code plugin for jDeploy&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/shannah/jdeploy-claude/tree/main/plugins/jdeploy/skills/custom-launcher-splash" rel="noopener noreferrer"&gt;Custom launcher splash screen skill&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Lottie4J: 

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://lottie4j.com/" rel="noopener noreferrer"&gt;Website&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lottie4j/" rel="noopener noreferrer"&gt;Sources on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>javafx</category>
      <category>kotlin</category>
      <category>melodymatrix</category>
    </item>
    <item>
      <title>Lottie4J 1.2.0: dotLottie Support, Marker Playback, Cropping, and a Big Speed Boost</title>
      <dc:creator>Frank Delporte</dc:creator>
      <pubDate>Fri, 20 Mar 2026 10:48:55 +0000</pubDate>
      <link>https://dev.to/fdelporte/lottie4j-120-dotlottie-support-marker-playback-cropping-and-a-big-speed-boost-3o06</link>
      <guid>https://dev.to/fdelporte/lottie4j-120-dotlottie-support-marker-playback-cropping-and-a-big-speed-boost-3o06</guid>
      <description>&lt;p&gt;Version 1.2.0 of &lt;a href="https://lottie4j.com" rel="noopener noreferrer"&gt;Lottie4J&lt;/a&gt; is out, and it's again a big release! The headline feature is support for the &lt;code&gt;.lottie&lt;/code&gt; container format, but that's just the start. This release also brings marker-based playback, cropping, adaptive rendering, significant performance improvements, and a lot of core model fixes driven by testing more complex real-world animations.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  dotLottie File Support
&lt;/h2&gt;

&lt;p&gt;Until now, Lottie4J only supported the plain JSON format (&lt;code&gt;.json&lt;/code&gt;). That's the original Lottie format, but LottieFiles also introduced a newer container format: &lt;code&gt;.lottie&lt;/code&gt;. It's essentially a ZIP archive that can hold one or more animations, embedded images, sounds, and a manifest file that describes the contents.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;.lottie&lt;/code&gt; format is a practical improvement: it makes Lottie files smaller and self-contained, bundling images and other assets alongside the animation data instead of relying on external references. Lottie4J now supports loading &lt;code&gt;.lottie&lt;/code&gt; files directly via the core &lt;code&gt;FileLoader&lt;/code&gt;. There are two loading modes available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Load the first animation from a .lottie file (simplest path)&lt;/span&gt;
&lt;span class="nc"&gt;LottieAnimation&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LottieFileLoader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Load the full .lottie container to access the manifest and all animations&lt;/span&gt;
&lt;span class="nc"&gt;DotLottie&lt;/span&gt; &lt;span class="n"&gt;lottie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LottieFileLoader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadDotLottie&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Lottie&lt;/code&gt; object gives you access to the manifest (author, version metadata) and the full list of animations. At the moment, most real-world &lt;code&gt;.lottie&lt;/code&gt; files I found, only bundle a single animation, but the API is ready for multi-animation files when they appear.&lt;/p&gt;

&lt;h2&gt;
  
  
  New Player Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Play Between Markers
&lt;/h3&gt;

&lt;p&gt;Lottie animations can embed named markers. Those are timestamp labels inside the animation JSON that indicate points of interest or looping regions. This is a feature Lottie4J previously parsed but didn't expose in the player. Now it does.&lt;/p&gt;

&lt;p&gt;The new &lt;code&gt;play(startMarker, endMarker)&lt;/code&gt; method makes the player start at frame 1, and then loop between the two named positions in the timeline. &lt;/p&gt;

&lt;h3&gt;
  
  
  Cropping Support
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;LottiePlayer&lt;/code&gt; now supports cropping via &lt;code&gt;crop(top, right, bottom, left)&lt;/code&gt;. This lets you clip the rendered output to a sub-region of the animation canvas, which is handy when you want to embed only part of an animation into a layout without modifying the original file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resizable Player
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;LottiePlayer&lt;/code&gt; is now properly resizable and adjusts its rendering accordingly. Resizing also has a secondary effect: smaller sizes reduce the rendering load, so you can trade size for performance when needed.&lt;/p&gt;

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

&lt;p&gt;Rendering speed has improved significantly in this release. The main gains come from reducing the number of rendering passes per frame and adding a caching layer for layer and precomp render metadata, which avoids redundant recalculation on heavy animations.&lt;/p&gt;

&lt;p&gt;The difference is measurable: one test animation that previously played back at around 20–30 FPS now runs at ~50 FPS. A heavier animation that struggled at 11 FPS now reaches ~31 FPS at full size, and scales higher as the player is resized smaller.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adaptive Rendering Mode
&lt;/h3&gt;

&lt;p&gt;A new adaptive rendering toggle &lt;code&gt;setAdaptiveOffscreenScalingEnabled(enabled)&lt;/code&gt; trades rendering sharpness for speed. In adaptive mode, JavaFX uses a faster rendering path that can introduce slight blurring on some elements (particularly sharp text or fine detail at certain sizes). In non-adaptive mode, rendering is pixel-precise but slower.&lt;/p&gt;

&lt;p&gt;Which mode works better depends on the animation: simpler animations often look fine in adaptive mode and benefit from the speed, while text-heavy or detail-rich animations are better left in the default mode. The toggle is exposed in both the &lt;code&gt;LottiePlayer&lt;/code&gt; and the file viewers so you can test your specific animations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Model Improvements
&lt;/h2&gt;

&lt;p&gt;A lot of work went into the core library this release, driven by testing more complex real-world Lottie files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Merge and modifier shape support&lt;/strong&gt;: a shape layer feature used in more complex animations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blend mode support&lt;/strong&gt;: layers can now carry blend mode instructions that affect compositing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spatial bezier interpolation&lt;/strong&gt;: position animations now correctly interpolate using bezier curves rather than linear paths, which produces the characteristic easing motion that makes Lottie animations feel polished.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing model fields&lt;/strong&gt;: mask, layer, and animation objects had gaps that caused incorrect rendering on specific files, these are now filled in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved JSON output&lt;/strong&gt;: when recreating a Lottie JSON from the model (write path), value ordering is now more consistent, and the reconstructed file more closely matches the original.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Jackson 3 Upgrade
&lt;/h3&gt;

&lt;p&gt;The core library has been upgraded to Jackson 3. This is a major version bump: the group ID changes from &lt;code&gt;com.fasterxml.jackson&lt;/code&gt; to &lt;code&gt;tools.jackson&lt;/code&gt;, so if you depend on the core directly and also pull in Jackson yourself, you'll want to align on version 3. The upgrade also includes CVE-related dependency updates and follow-up compatibility fixes that came out of the migration.&lt;/p&gt;

&lt;p&gt;Note that &lt;code&gt;jackson-annotations&lt;/code&gt; has not yet moved to the &lt;code&gt;tools.jackson&lt;/code&gt; group ID and remains on its previous coordinates for now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debug Tooling Updates
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;LottieFileDebugViewer&lt;/code&gt; has been refactored to extract the duplicated WebView JavaScript bridge code into reusable components. The FX versus JS side-by-side views are improved, and the comparison test has better frame synchronization. A new validation mode tests the player at a resized dimension to verify that rendering holds up under scaling.&lt;/p&gt;

&lt;p&gt;The automated &lt;code&gt;CompareFxViewWithWebViewTest&lt;/code&gt;, which renders both the JavaFX and JavaScript players frame by frame and checks visual similarity, now also uses &lt;code&gt;.lottie&lt;/code&gt; files. &lt;/p&gt;

&lt;h2&gt;
  
  
  Trying It Out
&lt;/h2&gt;

&lt;p&gt;Update your Maven dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Just the core model, no player --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.lottie4j&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;core&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.2.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- JavaFX player --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.lottie4j&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;fxplayer&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.2.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full list of changes is &lt;a href="https://github.com/lottie4j/lottie4j/compare/v1.1.0...v1.2.0" rel="noopener noreferrer"&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The automated comparison test still can't run on GitHub Actions because it requires a display. JavaFX 26 (released alongside Java 26 this week) includes headless rendering support, which may make it possible to run the visual regression tests on GitHub Actions. That's the next thing to investigate...&lt;/p&gt;

&lt;p&gt;As always: if you run into a Lottie file that doesn't render correctly, please open an issue and attach screenshots. The more real-world files get tested, the better the library gets.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://lottie4j.com" rel="noopener noreferrer"&gt;lottie4j.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/lottie4j/lottie4j" rel="noopener noreferrer"&gt;github.com/lottie4j/lottie4j&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Release notes: &lt;a href="https://lottie4j.com/releases/index.html" rel="noopener noreferrer"&gt;lottie4j.com/releases&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>javafx</category>
      <category>lottie</category>
      <category>animation</category>
    </item>
  </channel>
</rss>
