<?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: Jen Looper</title>
    <description>The latest articles on DEV Community by Jen Looper (@jenlooper).</description>
    <link>https://dev.to/jenlooper</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%2F9819%2Fd0d0dc5d-031b-43fe-85a4-469def492123.jpg</url>
      <title>DEV Community: Jen Looper</title>
      <link>https://dev.to/jenlooper</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jenlooper"/>
    <language>en</language>
    <item>
      <title>Build a Tiny Virtual Pet on Arduino in 60 Minutes 🐾</title>
      <dc:creator>Jen Looper</dc:creator>
      <pubDate>Tue, 06 Oct 2026 00:47:44 +0000</pubDate>
      <link>https://dev.to/heraistudio/build-a-tiny-virtual-pet-on-arduino-in-60-minutes-2cf</link>
      <guid>https://dev.to/heraistudio/build-a-tiny-virtual-pet-on-arduino-in-60-minutes-2cf</guid>
      <description>&lt;p&gt;What if your first hardware project wasn't another blinking LED, but a tiny pet that gets hungry, plays with you, falls asleep, and reacts to what you type?&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;Kiku&lt;/strong&gt;. 🌸&lt;/p&gt;

&lt;p&gt;Kiku is the mascot and in-house pet of &lt;strong&gt;Her AI Studio&lt;/strong&gt;, a community program helping the next generation of women learn and build with AI.&lt;/p&gt;

&lt;p&gt;In this mini workshop, we're shrinking Kiku down until the entire pet can live on an &lt;strong&gt;Arduino Uno Q&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Full tutorial is available in the &lt;strong&gt;&lt;a href="https://her-ai-studio.github.io/curriculum/mini-workshop.html" rel="noopener noreferrer"&gt;Her AI Studio curriculum&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an Arduino Uno Q&lt;/li&gt;
&lt;li&gt;a USB cable&lt;/li&gt;
&lt;li&gt;your laptop&lt;/li&gt;
&lt;li&gt;Arduino App Lab&lt;/li&gt;
&lt;li&gt;about 60 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip! To celebrate Hacktoberfest 2026, swag packs from Major League Hacking are shipping with these Arduinos, so use this workshop for your Hack Day as an introduction to hardware hacking.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Shhh, Kiku is sleeping&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By the end, you'll have a tiny Tamagotchi-style pet whose face lives on the board's LED matrix. You'll be able to &lt;strong&gt;feed it, play with it, and put it to sleep from your keyboard&lt;/strong&gt;. More importantly, you'll see how a surprisingly small amount of code can produce behavior that feels alive.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you'll learn
&lt;/h2&gt;

&lt;p&gt;This project brings together several useful embedded-programming concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;flashing code onto physical hardware&lt;/li&gt;
&lt;li&gt;communicating with a microcontroller over Serial&lt;/li&gt;
&lt;li&gt;drawing graphics on an LED matrix&lt;/li&gt;
&lt;li&gt;tracking application state&lt;/li&gt;
&lt;li&gt;responding to user input&lt;/li&gt;
&lt;li&gt;creating simple animations&lt;/li&gt;
&lt;li&gt;building a tiny state machine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've mostly written software that stays inside your laptop, there's something especially satisfying about seeing your code suddenly appear on physical hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Make sure the board is alive
&lt;/h2&gt;

&lt;p&gt;Before building a virtual pet, start with the embedded developer's version of &lt;code&gt;"Hello, world!"&lt;/code&gt;: &lt;strong&gt;Blink an LED.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Connect your Uno Q to your laptop over USB and open Arduino App Lab which you've downloaded. Login to your board.&lt;/p&gt;

&lt;p&gt;Create a new app, and take a look at the scaffolded code. Open &lt;code&gt;sketch.ino&lt;/code&gt;, and write a basic blink sketch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;pinMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LED_BUILTIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OUTPUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LED_BUILTIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LED_BUILTIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Press &lt;code&gt;run&lt;/code&gt; in App Lab.&lt;/p&gt;

&lt;p&gt;If the built-in LED turns on and off every second, &lt;strong&gt;it's aliiiiive!&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the board isn't detected, check your USB cable. Some USB cables provide power but don't carry data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Part 2: Give your Arduino a way to listen
&lt;/h2&gt;

&lt;p&gt;Now we need Kiku to hear us. We could add buttons or sensors (and we do, in our full workshop with our full AI Kit), but there's a much simpler interface already available: &lt;strong&gt;Serial communication&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The same USB connection used to upload your program can carry messages between your laptop and your Arduino while the program is running. In App Lab, it looks like this:&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%2Fy9mfzadg4xz0eh4jn5iv.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%2Fy9mfzadg4xz0eh4jn5iv.png" alt="Serial Monitor" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Start Serial communication in &lt;code&gt;setup()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then check for incoming characters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;typed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typed&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'f'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// feed Kiku&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typed&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'p'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// play with Kiku&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typed&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'s'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// sleep or wake up&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your keyboard has effectively become the controller for a physical device.&lt;/p&gt;

&lt;p&gt;To interact with Kiku, we'll use 3 keystrokes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f → feed
p → play
s → sleep / wake
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 3: Give Kiku some feelings
&lt;/h2&gt;

&lt;p&gt;A virtual pet needs more than commands. It needs &lt;strong&gt;state&lt;/strong&gt;. Kiku tracks three simple stats:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;hunger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;joy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;energy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;asleep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll treat each stat as a value from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;10&lt;/code&gt;. Now actions can change the pet by incrementing or decrementing these values. Feeding Kiku, for example, reduces hunger (but don't overfeed!):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;hunger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hunger&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;joy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;joy&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Playing might make Kiku happier while consuming energy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;joy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;joy&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;energy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;energy&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;hunger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hunger&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Make time matter
&lt;/h2&gt;

&lt;p&gt;If Kiku's stats only changed when we typed something, the pet wouldn't feel particularly alive.&lt;/p&gt;

&lt;p&gt;So we introduce time! Every few seconds, a &lt;code&gt;tick()&lt;/code&gt; function updates Kiku's state, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asleep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// regain energy&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// lose energy&lt;/span&gt;
    &lt;span class="c1"&gt;// gradually lose joy&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// gradually become hungry&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your code, use a short interval so changes are easy to observe (and change this later when you want your pet to chill out):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;TICK_MS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's one update every ten seconds. Walk away from Kiku and come back later, and its state will definitely be different - they can get cranky when left alone!&lt;/p&gt;

&lt;h2&gt;
  
  
  Give the state a face
&lt;/h2&gt;

&lt;p&gt;Kiku turns its internal state into facial expressions on the Uno Q's LED matrix. We can define its eyes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Eyes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;EYES_OPEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;EYES_CLOSED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;EYES_HAPPY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;EYES_PEEK&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And mouth poses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Mouth&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;MOUTH_FLAT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;MOUTH_SMILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;MOUTH_FROWN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;MOUTH_OPEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;MOUTH_DOT&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our program can translate state into emotion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;Mouth&lt;/span&gt; &lt;span class="nf"&gt;moodMouth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hunger&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;joy&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;MOUTH_FROWN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;joy&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;MOUTH_SMILE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;MOUTH_FLAT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kiku isn't actually experiencing happiness or hunger, of course, but a handful of variables and conditionals suddenly starts to look like personality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect actions to behavior
&lt;/h2&gt;

&lt;p&gt;Now the pieces come together. Your main loop has three jobs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Listen for commands.&lt;/li&gt;
&lt;li&gt;Update Kiku's state over time.&lt;/li&gt;
&lt;li&gt;Draw the appropriate expression.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In simplified form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;typed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typed&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'f'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typed&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'p'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;play&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typed&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'s'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;toggleSleep&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// update stats when enough time has passed&lt;/span&gt;

  &lt;span class="c1"&gt;// calculate blinking&lt;/span&gt;

  &lt;span class="c1"&gt;// redraw Kiku&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the core architecture of your Kiku. Try it with your own device!&lt;/p&gt;

&lt;p&gt;Open the Serial Monitor in App Lab and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kiku eats.&lt;/p&gt;

&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kiku plays.&lt;/p&gt;

&lt;p&gt;And:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kiku goes to sleep.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Try to make some changes that alters Kiku's personality. &lt;/p&gt;

&lt;h3&gt;
  
  
  1. Change time
&lt;/h3&gt;

&lt;p&gt;Modify &lt;code&gt;TICK_MS&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Invent an expression
&lt;/h3&gt;

&lt;p&gt;Make Kiku wink, act surprised, or act sad.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Add another command
&lt;/h3&gt;

&lt;p&gt;Maybe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;c → clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What did we actually build?
&lt;/h2&gt;

&lt;p&gt;On the surface, we built a cute virtual pet. Underneath, we explored several concepts that appear in much larger systems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input handling&lt;/strong&gt;: Serial commands become events.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State management&lt;/strong&gt;: Variables remember what's happening between iterations of the loop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State transitions&lt;/strong&gt;: Actions modify that state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time-based behavior&lt;/strong&gt;: The system changes even without direct input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rendering&lt;/strong&gt;: Internal state becomes visible through the LED matrix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Human-computer interaction&lt;/strong&gt;: Animation and timing make simple logic feel expressive.&lt;/p&gt;




&lt;p&gt;If you build your own Kiku for Hacktoberfest, we'd love to see what personality you give it.🌸&lt;/p&gt;




&lt;p&gt;This article is presented as a gift to Hacktoberfest hackers by &lt;strong&gt;Her AI Studio&lt;/strong&gt;, a community program for the next generation of women in AI.&lt;/p&gt;

&lt;p&gt;The complete Kiku workshop, including the full Arduino sketch, exercises, knowledge checks, and additional resources, is available in the &lt;strong&gt;&lt;a href="https://her-ai-studio.github.io/curriculum/mini-workshop.html" rel="noopener noreferrer"&gt;Her AI Studio curriculum&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>arduino</category>
      <category>beginners</category>
      <category>programming</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Building an Offline Arduino UNO Q Cyberdeck That Identifies Birdsong and Draws Vintage Field Notes</title>
      <dc:creator>Jen Looper</dc:creator>
      <pubDate>Wed, 30 Sep 2026 19:36:21 +0000</pubDate>
      <link>https://dev.to/cloudinary/building-an-offline-arduino-uno-q-cyberdeck-that-identifies-birdsong-and-draws-vintage-field-notes-1cjg</link>
      <guid>https://dev.to/cloudinary/building-an-offline-arduino-uno-q-cyberdeck-that-identifies-birdsong-and-draws-vintage-field-notes-1cjg</guid>
      <description>&lt;p&gt;In this post, I walk through &lt;strong&gt;B.L.O.O.M.&lt;/strong&gt; (Bridging Local Observations, Openly Mapped), an offline cyberdeck built on the &lt;strong&gt;Arduino UNO Q&lt;/strong&gt; that helps naturalists capture field notes, identify birdsong with &lt;strong&gt;Edge Impulse&lt;/strong&gt;, and generate vintage field sketches with &lt;strong&gt;Cloudinary's image generation API&lt;/strong&gt;. It stores everything locally and syncs to a community site only when you choose.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fezxxqe0immid0smna93b.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%2Fezxxqe0immid0smna93b.jpg" alt="full deck" width="605" height="628"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What you'll learn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How to wire an Arduino UNO Q cyberdeck with a USB hub, camera, mic and HDMI screen&lt;/li&gt;
&lt;li&gt;How to run a local Gemma LLM and an audio classifier with Arduino App Lab bricks&lt;/li&gt;
&lt;li&gt;How to retrain an Edge Impulse birdsong model with balanced data&lt;/li&gt;
&lt;li&gt;How to sync SQLite entries to GitHub pull requests from a Netlify Function&lt;/li&gt;
&lt;li&gt;How to generate style-matched images with Cloudinary's image_to_image API with reference images&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cyberdecks are back. The 80s sci-fi dream of a portable, hackable computer rig has been picked back up, especially by nature-loving corners of the internet that want tech that works offline, respects privacy, and looks cool doing it. The one I built for this project lives in a $10 vintage makeup train case and creates &lt;a href="https://autumn-society.org/writing/codex/field-notes/" rel="noopener noreferrer"&gt;Grinnell style field notes&lt;/a&gt; as you tiptoe through the tulips.&lt;/p&gt;

&lt;p&gt;This post covers the &lt;strong&gt;hardware-to-cloud pipeline&lt;/strong&gt;, with the most detail on the part where Cloudinary comes in. The full build (wiring, enclosure, every step) is on &lt;a href="https://www.hackster.io/agent-hawking-1/b-l-o-o-m-a-community-cyberdeck-for-your-field-notes-8dba4c" rel="noopener noreferrer"&gt;Hackster&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The architecture at a glance&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────── In the field (offline) ────────────┐        ┌────────────── Back online ──────────────┐
│                                                │        │                                          │
│  Mic ─► Edge Impulse birdsong model            │        │  Netlify Function                        │
│  Camera ─► photo                               │  POST  │   ├─► Cloudinary image_to_image          │
│  Keyboard/mouse ─► sketch + notes    ─► SQLite ├───────►│   │     (Nano Banana → field sketch)      │
│  Gemma LLM ─► AI note                          │        │   └─► Octokit: open PR on GitHub         │
│                                                │        │          │                               │
│  Arduino UNO Q (App Lab, Chromium kiosk)       │        │   merge ─► Astro rebuild ─► live site    │
└────────────────────────────────────────────────┘        └──────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Nothing leaves the device unless you press Sync to Cloud. That was a hard requirement, as this project is affiliated as well with the nonprofit I founded, &lt;a href="https://heraistudio.org" rel="noopener noreferrer"&gt;Her AI Studio&lt;/a&gt;, where we talk a lot about data governance, security, and privacy, working primarily with local AI on device.&lt;/p&gt;

&lt;p&gt;Here's the full schematic:&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%2F77ysso9nq7xty5r1dyta.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%2F77ysso9nq7xty5r1dyta.png" alt="schematic" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The core of the cloud side is a single POST to Cloudinary:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Create a field sketch illustration in the style of the reference image [1]..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reference_images"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"source_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your reference sketch&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"family"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nano-banana"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"premium"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"managed_asset"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"public_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"field-notes/&amp;lt;slug&amp;gt;-ai"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The full function is below.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hardware: the Arduino UNO Q parts list
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Arduino UNO Q (4 GB)&lt;/li&gt;
&lt;li&gt;5" HDMI screen + 6" HDMI cable&lt;/li&gt;
&lt;li&gt;USB 5-in-1 hub&lt;/li&gt;
&lt;li&gt;USB camera&lt;/li&gt;
&lt;li&gt;USB microphone&lt;/li&gt;
&lt;li&gt;Power bank + USB-A to Micro-USB cable&lt;/li&gt;
&lt;li&gt;Bluetooth keyboard with built-in mouse pad&lt;/li&gt;
&lt;li&gt;Vintage train case (or the enclosure you like best! This is the fun part)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://docs.arduino.cc/hardware/uno-q/" rel="noopener noreferrer"&gt;Arduino UNO Q&lt;/a&gt; runs everything. The 4 GB variant can run a small language model and an audio classifier fully offline, which is what makes the device useful on a forest trail with no signal...and to explore offline, local AI models on hardware!&lt;/p&gt;

&lt;p&gt;Because it's a cyberdeck, there are peripherals, and those are all connected to the USB hub: screen, mic, camera and power go into the hub, and the hub's USB-C plug goes into the UNO Q. Pair the keyboard and mouse over Bluetooth in Debian and you get those USB ports back.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At &lt;a href="https://heraistudio.org" rel="noopener noreferrer"&gt;Her AI Studio&lt;/a&gt;, students will get access to this AI Kit.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Running Gemma and birdsong detection on the UNO Q with App Lab
&lt;/h2&gt;

&lt;p&gt;The app is built in Arduino App Lab from three "bricks", which are modular code available pre-built for the Arduino Uno Q:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web UI for the interface with camera and sketching interface&lt;/li&gt;
&lt;li&gt;LLM brick running Gemma, downloaded locally to the board&lt;/li&gt;
&lt;li&gt;Audio Classification brick for birdsong&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Web UI brick helps you build a tidy interface with a little JS and HTML that runs on your local board via Arduino App Lab. This is how you write your field notes. The LLM brick creates a little space to chat with an LLM and learn more about the flora and fauna photos that you take with the build-in camera.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Side Quest: Fixing Chromium popups on Debian with a kiosk brick&lt;/strong&gt;&lt;br&gt;
On Debian, the stock Web UI brick opened Chromium popups behind other windows. It worked fine on desktop but not on the device. I fixed it with a small custom brick that waits for the local server and then launches Chromium in kiosk mode:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_kiosk_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;system&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Linux&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chromium-browser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--kiosk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--noerrdialogs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--disable-infobars&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--app={url}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;launch_kiosk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ready_timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;wait_for_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;ready_timeout&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server never became reachable at {url}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;None&lt;/span&gt;
    &lt;span class="nx"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build_kiosk_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Launching: {' '.join(cmd)}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The interface is presented full-screen without desktop chrome, so the screen is just the field notebook, like this:&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%2Fxmnv0mfcumfo1sredio3.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%2Fxmnv0mfcumfo1sredio3.png" alt=" " width="800" height="783"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Listening for birds
&lt;/h2&gt;

&lt;p&gt;I wanted to give my cyberdeck some "ears", so I turned to a platform that works well to add local, custom-trained models to Arduino via App Lab: Edge Impulse.&lt;/p&gt;

&lt;p&gt;I started from a birdsong classifier in the Edge Impulse community gallery. It had class imbalance and too few samples, so I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplicated the project and removed unusable clips&lt;/li&gt;
&lt;li&gt;Pulled at least 20 recordings each of Blue Jay, Mourning Dove and Northern Cardinal from &lt;a href="https://xeno-canto.org/" rel="noopener noreferrer"&gt;xeno-canto&lt;/a&gt;, a birdsong database&lt;/li&gt;
&lt;li&gt;Converted everything to WAV, labeled it, and uploaded it&lt;/li&gt;
&lt;li&gt;Rebalanced the train/test split and retrained&lt;/li&gt;
&lt;li&gt;Dropped the new model into the App Lab project&lt;/li&gt;
&lt;/ul&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%2Ffbprwzm6qzid0t0mqloh.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%2Ffbprwzm6qzid0t0mqloh.png" alt="birdsong model" width="799" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When your USB microphone picks up a bird singing, you tap a button, the model classifies the audio, and the result is saved into a field note. The model is &lt;a href="https://studio.edgeimpulse.com/public/1062343/live" rel="noopener noreferrer"&gt;public and cloneable&lt;/a&gt; if you want to add your local species.&lt;/p&gt;
&lt;h2&gt;
  
  
  Syncing: from SQLite to a pull request
&lt;/h2&gt;

&lt;p&gt;Every observation is stored in a local SQLite database, but maybe you want to showcase your field notes to our public repository. When you choose to share, the device posts the entry to a Netlify Function. Photos and sketches are base64-encoded so the whole entry travels as one JSON payload:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sync_entry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;_db_lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DB_PATH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT id, timestamp, photo, sketch, ai_note, locality, weather, habitat &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FROM entries WHERE id = ?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry_id&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fetchone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;eid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;photo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ai_note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;locality&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;habitat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;catalog_no&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;catalog_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;note&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ai_note&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;locality&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;locality&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weather&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;weather&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;habitat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;habitat&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;photo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;photo&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;photo&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sketch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sketch&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sketch&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CLOUD_SYNC_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CLOUD_SYNC_TIMEOUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;does&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;It&lt;/span&gt; &lt;span class="n"&gt;opens&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;pull&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="n"&gt;against&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;Octokit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;octokit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pulls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OWNER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;REPO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sb"&gt;`New field note: ${catalog_no}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;branchName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BASE_BRANCH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Submitted automatically from a Bloom device.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sb"&gt;`**Locality:** ${locality || "—"}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sb"&gt;`**Weather:** ${weather || "—"}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sb"&gt;`**Habitat:** ${habitat || "—"}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;aiSketchPath&lt;/span&gt; &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;_AI-generated sketch included._&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;device-submission&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This process makes it easier for the community site to get human moderation: a maintainer reviews the PR, merges it, and Netlify rebuilds the Astro site. You can see the results at &lt;a href="https://community-field-notes.netlify.app" rel="noopener noreferrer"&gt;community-field-notes.netlify.app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9zb7iq4qls6jqr6s7cp0.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%2F9zb7iq4qls6jqr6s7cp0.png" alt="community web" width="800" height="572"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Generating AI field sketches with Cloudinary's image_to_image API&lt;br&gt;
Naturalists in the Grinnell tradition paired written notes with drawings. I wanted every synced note to come with an illustration in that vintage style, even if the person who wrote it can't draw.&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%2Fjgqbgy3zz7146h7a0dbg.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%2Fjgqbgy3zz7146h7a0dbg.jpg" alt="AI Field Note" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before the PR is opened, the Netlify Function sends the note text to Cloudinary's image generation API using the image_to_image endpoint and the Nano Banana model. I also pass a reference image, an old-style field sketch already stored in my Cloudinary account, so every output matches the same look:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateAiSketch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;noteText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Create a field sketch illustration in the style of the reference image [1].&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The sketch should depict:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;noteText&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A natural world observation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Use a vintage field journal aesthetic with earthy tones, hand-drawn quality, and scientific illustration style.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CLOUDINARY_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CLOUDINARY_API_SECRET&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://api.cloudinary.com/v2/generate/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CLOUDINARY_CLOUD_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/image_to_image`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Basic &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;reference_images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;source_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;REFERENCE_IMAGE_URL&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nano-banana&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;premium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;target_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;managed_asset&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;public_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`field-notes/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-ai`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ...handle response, return the asset path for the PR&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  A few things I like about this setup:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The use of the reference image keeps the style consistent, and you can either choose the model, or keep it set to 'auto' - so that the model is chosen for you based on your use case. &lt;/li&gt;
&lt;li&gt;The prompt describes what to draw, and the reference image sets how it should look. Swap the reference and every future note gets a new visual identity.
The target_type: "managed_asset" saves the output straight into my Cloudinary media library under a predictable public_id (field-notes/-ai). I don't have to download and re-upload anything, and the image is ready for delivery to my community field notes app.&lt;/li&gt;
&lt;li&gt;After that it's a normal Cloudinary asset, so the site can deliver it with the usual transformations: f_auto,q_auto, resizing for cards and thumbnails, and so on.&lt;/li&gt;
&lt;li&gt;It's one fetch call. No SDK and no extra infrastructure, which suits a serverless function.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Setup tips
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Keep CLOUDINARY_CLOUD_NAME, CLOUDINARY_API_KEY and CLOUDINARY_API_SECRET in Netlify environment variables. Never put them on the device.&lt;/li&gt;
&lt;li&gt;Upload your reference sketch to Cloudinary first and use its delivery URL as REFERENCE_IMAGE_URL.&lt;/li&gt;
&lt;li&gt;The Image Generation API has a free monthly allowance, which covers a community project like this. If you don't have an account yet, sign up for free.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The enclosure: no 3D printer needed
&lt;/h2&gt;

&lt;p&gt;Instead of printing a case, I reused one (preferable for cyberdecks!): a vintage Lancôme makeup train case, costing about $10 on eBay. Here's what I did to fit everything in the case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cut a small hole in the side for the camera lens&lt;/li&gt;
&lt;li&gt;Build shelves from recycled foam and fabric&lt;/li&gt;
&lt;li&gt;Zip-tie the USB hub in place&lt;/li&gt;
&lt;li&gt;Made a cardboard backing for the screen, with room for cables&lt;/li&gt;
&lt;li&gt;Gave the UNO Q its own spot, with airflow in mind (foam and fabric trap heat, so watch temperatures or use an open weave like rattan - I've even used a sushi rolling mat for this type of shelf)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tall case also leaves room for a magnifier, pressed flowers, a small watercolor set, or a leaf guide.&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%2F9nl6zhy3wsoq1wcpl7me.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9nl6zhy3wsoq1wcpl7me.jpeg" alt="in the field" width="412" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the author enjoying a Fall day of field notes&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Go touch grass: using B.L.O.O.M. in the field
&lt;/h2&gt;

&lt;p&gt;Power it on, head outside, and record what you find: birdsong, photos, sketches, questions for the LLM, locality, weather and habitat. When you're back on Wi-Fi, press sync to send the note to GitHub, get a Cloudinary-generated sketch, and add it to a shared natural-history record.&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%2Faweupf1wnvo0ko75w7sx.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faweupf1wnvo0ko75w7sx.jpeg" alt="cat" width="416" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Discover new fauna&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;📖 Full build on Hackster: &lt;a href="https://www.hackster.io/agent-hawking-1/b-l-o-o-m-a-community-cyberdeck-for-your-field-notes-8dba4c" rel="noopener noreferrer"&gt;B.L.O.O.M.: A Community Cyberdeck for your Field Notes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 Device code:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Her-AI-Studio" rel="noopener noreferrer"&gt;
        Her-AI-Studio
      &lt;/a&gt; / &lt;a href="https://github.com/Her-AI-Studio/BLOOM-code" rel="noopener noreferrer"&gt;
        BLOOM-code
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      This is the codebase for use in Arduino App Lab, for the Arduino Uno Q in a cyberdeck
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;B.L.O.O.M — an offline field journal&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Bridging Local Observations, Openly Mapped&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B.L.O.O.M&lt;/strong&gt; turns an Arduino® UNO Q into a self-powered, offline field-journal cyberdeck: point it at a plant, an animal, or anything worth noticing on a hike, capture a photo, sketch on top of it, and talk through what you're observing with a fully local AI model. Every entry — photo, sketch, and note — is saved to the board itself and stays there unless you deliberately choose to sync it to a companion website. No connectivity is required to use it in the field.&lt;/p&gt;

&lt;p&gt;Built for Her AI Studio's curriculum and submitted for hackathons including the &lt;a href="https://www.hackster.io/contests/invent-the-future-with-arduino-uno-q-and-app-lab" rel="nofollow noopener noreferrer"&gt;Invent the Future with Arduino UNO Q and App Lab&lt;/a&gt; contest, Best Social Impact category — the pitch is a countermeasure to phone-and-camera culture: a single-purpose device that makes you stop, point, and wait for a note instead of snapping and swiping past.&lt;/p&gt;

&lt;p&gt;…&lt;/p&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Her-AI-Studio/BLOOM-code" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;🌐 &lt;a href="https://community-field-notes.netlify.app" rel="noopener noreferrer"&gt;Community web app (Astro + Netlify)&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Her-AI-Studio" rel="noopener noreferrer"&gt;
        Her-AI-Studio
      &lt;/a&gt; / &lt;a href="https://github.com/Her-AI-Studio/field-notes" rel="noopener noreferrer"&gt;
        field-notes
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      This is the core code of the offline, locally-powered cyberdeck for use when hiking
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Field Notes&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A digital field journal — a collection of natural history observations, surveys, and records from the field.&lt;/p&gt;
&lt;p&gt;Built with &lt;a href="https://astro.build" rel="nofollow noopener noreferrer"&gt;Astro&lt;/a&gt; and Markdown content collections.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Project Structure&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;/
├── public/
│   └── favicon.svg
├── src/
│   ├── content/
│   │   ├── config.ts
│   │   └── notes/
│   │       ├── observation-of-the-red-shouldered-hawk.md
│   │       ├── botanical-survey-of-coastal-dune-ecology.md
│   │       ├── geological-observations-along-the-appalachian-trail.md
│   │       └── nocturnal-insect-survey-june.md
│   ├── layouts/
│   │   └── Layout.astro
│   ├── pages/
│   │   ├── index.astro
│   │   └── notes/
│   │       └── [...slug].astro
│   └── styles/
│       └── global.css
└── package.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Adding a New Note&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Create a new &lt;code&gt;.md&lt;/code&gt; file in &lt;code&gt;src/content/notes/&lt;/code&gt; with frontmatter:&lt;/p&gt;
&lt;div class="highlight highlight-source-yaml notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;---
&lt;span class="pl-ent"&gt;title&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Your Note Title&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-ent"&gt;date&lt;/span&gt;: &lt;span class="pl-c1"&gt;2026-07-21&lt;/span&gt;
&lt;span class="pl-ent"&gt;location&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Location, State&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-ent"&gt;excerpt&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;A brief summary of the observation.&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-ent"&gt;image&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;/images/your-image.jpg&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-ent"&gt;tags&lt;/span&gt;: &lt;span class="pl-s"&gt;["tag1", "tag2"]&lt;/span&gt;
---&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The note will automatically appear on the…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Her-AI-Studio/field-notes" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;🐦 &lt;a href="https://studio.edgeimpulse.com/public/1062343/live" rel="noopener noreferrer"&gt;Edge Impulse birdsong model&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;Overall, Arduino&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Did you know the Arduino Uno Q runs Linux when it's a single-board computer? Without open source, we'd be locked into a proprietary sandbox. Instead, we can build in the open, and enhance the tools and models that others have generously open-sourced.&lt;/p&gt;




&lt;p&gt;If you build a nature-loving cyberdeck like this, contribute a note to the website, or retrain the model for birds near you, share it in the comments. I'd like to see what other people's field notes look like and what you're looking at in your region. 🌿&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Cloudinary ❤️ developers&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ready to level up your media workflow? Start using Cloudinary for free and build better visual experiences today.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👉 &lt;strong&gt;&lt;a href="https://link.cloudinary.com/utcCA" rel="noopener noreferrer"&gt;Create your free account&lt;/a&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>arduino</category>
      <category>iot</category>
      <category>ai</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Is AI Cheugy?</title>
      <dc:creator>Jen Looper</dc:creator>
      <pubDate>Mon, 21 Sep 2026 04:00:00 +0000</pubDate>
      <link>https://dev.to/heraistudio/is-ai-cheugy-1j01</link>
      <guid>https://dev.to/heraistudio/is-ai-cheugy-1j01</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;cheu·​gy&lt;/strong&gt; ˈchü-gē - cheugier; cheugiest. slang: uncool, unfashionable&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's happened enough times that I'm starting to call it a trend: I talk about something - anything - AI-related, and my listener screws their face into a scowl, gives me a robust side eye glare, and beats a hasty retreat. It's as if, when I mention AI, people suddenly are accosted by a bad smell...the stench of the dangerous and icky.&lt;/p&gt;

&lt;p&gt;The AI-pilled amongst us, of course, don't really see this. So caught up in their bubble, so sure of the rightness of their course, so excited by the newness of the tech and so enthused by its promise, they are often blind to the legitimate concerns that many (many!) so-called "normies" have about AI. Anyway, they don't talk to normies.&lt;/p&gt;

&lt;h3&gt;
  
  
  So let's talk about it.
&lt;/h3&gt;

&lt;p&gt;At Her AI Studio, for which this is an interesting inaugural blogpost, our mission is to empower high school aged girls to learn about AI in a safe space - a space for women, coached by female mentors near their age, using physical AI to build cyberdecks. By using locally-run hardware on which we can run small local AI models, we create a "walled garden" where students can safely experiment with local AI. In doing so, we can also discuss weighty topics of privacy, security, data governance, and the ethical questions surrounding AI.&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%2Fpbxjggkm4uqi4ryh1gsr.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%2Fpbxjggkm4uqi4ryh1gsr.png" alt="Her AI Studio AI Kit" width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A cyberdeck built with our kit, including an Arduino Uno Q board, small keyboard and monitor, microphone, camera, and USB Hub. Every student can create their own, this is just my fluffy iteration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That doesn't make AI any less cheugy (and, increasingly, political, although that's a topic for another day). There are serious question about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From where the training data that has fed the models is sourced&lt;/li&gt;
&lt;li&gt;What this technology means for the environment, from training, sourcing materials for hardware, water use, pollution, land use, and more &lt;/li&gt;
&lt;li&gt;How AI is &lt;em&gt;really&lt;/em&gt; screwing up education (my own particular hot take) and is being actively banned in some districts&lt;/li&gt;
&lt;li&gt;How deepfakes are ruining lives&lt;/li&gt;
&lt;li&gt;How powerful algorithms are feeding propaganda machines and influencing political outcomes&lt;/li&gt;
&lt;li&gt;How copyright rules and ethical concerns about plagiarism are caught up in this new technology&lt;/li&gt;
&lt;li&gt;How skills are decaying due to being replaced by a technology that can outsource work in a flash&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...and more&lt;/p&gt;

&lt;h3&gt;
  
  
  Headwinds
&lt;/h3&gt;

&lt;p&gt;It's really important to acknowledge these important headwinds and concerns and understand them. Rather than brush anything aside, I propose to address these head on in our cohorts with full transparency and with the understanding that there are many unsavory aspects of this tech. Reactions such as this from Gen Z commenters crystalize the moment. When seeking applicants for our Youth Board, here's a reaction:&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%2Fykc7gp3b3d585oe8tgom.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fykc7gp3b3d585oe8tgom.jpeg" alt="slop board" width="709" height="1536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ouch. But point well taken, and gone are the AI images from the site. We are listening.&lt;/p&gt;

&lt;p&gt;It's a fine line we're threading, and the gulf is enormous. At one end, we have folks insisting that AI will be so powerful that in a few years it will end us all. At the other end we have folks who advocate banning it entirely. &lt;/p&gt;

&lt;p&gt;There has to be some kind of middle ground. The companies making foundational models aren't doing us any favors by promoting the idea that somehow they have created something that will imminently cause a world cataclysm. By not sufficiently creating robust guardrails to protect users from abuse, they are creating a hostile environment for large swaths of the population. &lt;/p&gt;

&lt;p&gt;This is precisely why we founded Her AI Studio. We want to ensure that women will have a role to play in the &lt;em&gt;creation&lt;/em&gt; of AI, in the design of its guardrails, in the ethics around the kind of data on which it is trained. Without radical inclusion of these voices, we risk creating an "intelligence" that is stunted, that does not resemble our reality, and that cannot meet the needs of 50% of the world's population.&lt;/p&gt;

&lt;h3&gt;
  
  
  A new approach
&lt;/h3&gt;

&lt;p&gt;We do not approach the topic from a place of weakness or fear. We are not evangelizing AI, or really any particular product. Instead, we use open models, run locally, on hardware that we own, and talk about what this means. We study how data is used, from where it's sourced, what ethical concerns are raised by both building and using AI, and more. &lt;/p&gt;

&lt;p&gt;Because if we stay on our current path, we are going to build an AI that is not only unrecognizable, it's not going to be built to serve the best interests of a lot of people. And we find that unacceptable. Unacceptable and truly cheugy.&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="https://heraistudio.org" rel="noopener noreferrer"&gt;HerAIStudio.org&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl0n8oklzeejcy9d6ykn9.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%2Fl0n8oklzeejcy9d6ykn9.png" alt="Her AI Studio logo" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>career</category>
    </item>
    <item>
      <title>Kitchen-Sune: A Community Cookbook</title>
      <dc:creator>Jen Looper</dc:creator>
      <pubDate>Sun, 16 Aug 2026 03:35:03 +0000</pubDate>
      <link>https://dev.to/jenlooper/kitchen-sune-a-community-cookbook-5fea</link>
      <guid>https://dev.to/jenlooper/kitchen-sune-a-community-cookbook-5fea</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/frontend-2026-07-29"&gt;Frontend Challenge - Comfort Food Edition, Perfect Landing&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;This is a blast from the past, but it's so lovely I couldn't resist submitting it for this challenge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kitchen-sune.netlify.app/" rel="noopener noreferrer"&gt;Kitchen-Sune&lt;/a&gt; is a community-driven international recipe book built in collaboration with Front-End Foxes members when we pivoted our nonprofit's efforts from in-person workshops to an international online boot camp during the pandemic. It brings together comfort food recipes from around the globe into a sleek, accessible, and user-friendly Vuepress (later refactored to Vitepress) web application where food lovers and developers alike can discover new dishes.&lt;/p&gt;

&lt;p&gt;We were happy to host recipes from Ukraine, Kenya, Nigeria, and everywhere in between. Between Jalebi Babies, Moin-Moin, Puff Puff, and Strawberry Mush, we've got you covered for comfort food!&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Live Demo: &lt;a href="https://kitchen-sune.netlify.app/" rel="noopener noreferrer"&gt;Kitchen-Sune App&lt;/a&gt;&lt;br&gt;
GitHub Repo: &lt;a href="https://github.com/FrontEndFoxes/kitchen-sune" rel="noopener noreferrer"&gt;https://github.com/FrontEndFoxes/kitchen-sune&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out a preview of the recipe book (this recipe for maple syrup candy came with a video):&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%2Fdhbk0ha2788ov0jgddlu.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%2Fdhbk0ha2788ov0jgddlu.png" alt="Candy video" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;p&gt;Revisiting and showcasing this project was a nostalgic process. Working on a community recipe project taught me the importance of building inclusive, easy-to-navigate web interfaces for diverse content as an educatioal tool. We used to use this repo as a way to train boot camp enrollees in how to use GitHub and make a PR to a repo. &lt;/p&gt;

&lt;p&gt;What I Learned: No matter where we are in our journey, food brings us together.&lt;/p&gt;

&lt;p&gt;What I'm Proud Of: How timeless and clean the aesthetic remains, making it easy for anyone to find a warm, cozy meal to cook or a snack to throw together (Pandemic Cookies, anyone?).&lt;/p&gt;

&lt;p&gt;What's Next: Let's keep going! Add your recipe via a PR to the GitHub repo. And I'd love to have more photos to show off your work. &lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>frontend</category>
      <category>showdev</category>
      <category>vue</category>
    </item>
    <item>
      <title>Resize One Image into 6 Social Media Formats Automatically Using Cloudinary Claimable Clouds</title>
      <dc:creator>Jen Looper</dc:creator>
      <pubDate>Wed, 05 Aug 2026 21:30:34 +0000</pubDate>
      <link>https://dev.to/cloudinary/resize-one-image-into-6-social-media-formats-automatically-using-cloudinary-claimable-clouds-3gfc</link>
      <guid>https://dev.to/cloudinary/resize-one-image-into-6-social-media-formats-automatically-using-cloudinary-claimable-clouds-3gfc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Claimable Clouds are temporary Cloudinary environments for AI workflows that let AI Agents safely manage media with no signup required.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine you're a busy designer, with many satisfied clients who depend on you to take their images and make them look great across social media. All that manual cropping and scaling, it's enough to make a body cry.&lt;/p&gt;

&lt;p&gt;On top of that, you know that AI can give you a hand here, but managing the handoff between your AI, your own skilled hands and artistic taste and style, and your always-in-a-hurry client list is another big pain.&lt;/p&gt;

&lt;p&gt;Enter the concept of the Cloudinary Claimable Cloud, just released today.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://cloudinary.com/documentation/claimable_cloud_provisioning" rel="noopener noreferrer"&gt;Take a look at the docs&lt;/a&gt; about these new temporary instances available now&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What we built and why
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Provision a disposable Cloudinary cloud with no signup, using &lt;code&gt;npx @cloudinary/cloud&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Auto-detect a dropped image and upload it to that temporary cloud&lt;/li&gt;
&lt;li&gt;Auto-crop it into 6+ social formats (Instagram, LinkedIn, X, Facebook, Stories) using AI-based smart cropping&lt;/li&gt;
&lt;li&gt;Generate a side-by-side gallery of results automatically&lt;/li&gt;
&lt;li&gt;Hand off a Claim URL so a client can make the cloud permanent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, you can hand off the main pain points to AI - the resizing and reshaping of your images for the various social media platforms, while giving your clients a clean handoff via a temporary Cloud environment that they can use to create a Cloudinary account and start using these assets.&lt;/p&gt;

&lt;p&gt;One side effect: this also nudges your whole client base toward the same toolset - Cloudinary. The bigger deal is working with an AI agent that makes your life easier but ALSO allows you to keep control of the output. &lt;/p&gt;

&lt;p&gt;Let's walk through how this works! It all boils down to a new command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @cloudinary/cloud
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type that into your terminal to kick off the process. &lt;/p&gt;

&lt;p&gt;I built a &lt;a href="http://github.com/jlooper/social-me" rel="noopener noreferrer"&gt;small app&lt;/a&gt; around this concept to provide this AI agent with a simple harness, so let me show how that looks. The user experience is to drop any image you want resized into the &lt;code&gt;/drop&lt;/code&gt; folder. Under the cover, there are a few more processes at work: &lt;/p&gt;

&lt;h2&gt;
  
  
  Provisioning: Spin Up a Temporary Cloudinary Cloud
&lt;/h2&gt;

&lt;p&gt;On the first run, the app spins up a disposable Cloudinary "Claimable Cloud" via &lt;code&gt;npx @cloudinary/cloud&lt;/code&gt; with temporary credentials, so no signup is required. The generated credentials are saved temporarily in a .env file locally. This gives the tool a live upload/delivery endpoint without any manual account setup. These credentials are refreshed when you start the app: &lt;code&gt;npm i &amp;amp;&amp;amp; npm start&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch &amp;amp; Transform: Auto-Crop for Each Social Platform
&lt;/h2&gt;

&lt;p&gt;The app watches the &lt;code&gt;drop&lt;/code&gt; folder for new images. When a high-resolution master image lands there, it's uploaded to this temporary Cloudinary instance. &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%2Ffnb9cfto74uahxogcb89.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffnb9cfto74uahxogcb89.jpeg" alt="a Nano Banana image" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The image we want to resize&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then it's run through a set of predefined social-media format specs (Instagram Square, Portrait, Story/Reels/TikTok, LinkedIn, X/Twitter, Facebook) using dynamic transformations like c_fill,g_auto for smart auto-cropping to each platform's exact aspect ratio and dimensions, focusing on the most important element. Control these formats and transformations in the &lt;code&gt;src/formats.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FORMATS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;instagram-square&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Instagram Square Post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1:1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;buildTransformation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;subjectFill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;instagram-portrait&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Instagram Feed Portrait&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4:5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1350&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;buildTransformation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;subjectFill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1350&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;instagram-story&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Instagram Story / Reels / TikTok&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;9:16&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1920&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;buildTransformation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;padWithBlurredBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1920&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Render Results &amp;amp; Send to Client: Share a Claim URL
&lt;/h2&gt;

&lt;p&gt;The temporary Claimable Cloud is provisioned using the temporary credentials stored in .env:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Ensures a usable CLOUDINARY_URL is in process.env, provisioning a disposable&lt;/span&gt;
&lt;span class="c1"&gt;// cloud on demand. Returns { claimUrl } (claimUrl is undefined when a cloud&lt;/span&gt;
&lt;span class="c1"&gt;// was already configured before this run).&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ensureCloud&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;loadEnv&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CLOUDINARY_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;claimUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CLOUDINARY_CLOUD_CLAIM_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;provisioned&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No Cloudinary cloud configured yet — provisioning a disposable one (no signup needed)...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;execFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;npx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-y&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@cloudinary/cloud&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--no-agent-metadata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;combined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;redact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;combined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseKeyValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;loadEnv&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CLOUDINARY_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cloud provisioning did not produce a CLOUDINARY_URL.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;claimUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CLAIM_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;provisioned&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generated variant URLs are written to manifest.json and rendered into an auto-generated side-by-side HTML gallery, which opens automatically. The output also includes a Claim URL, letting the disposable cloud be handed off (e.g., to a client) and made permanent at any time.&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%2Fvntpjxpac7lcfhshn7z4.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%2Fvntpjxpac7lcfhshn7z4.png" alt="The results" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The temporary link and generated gallery of images to pick from. Note the fancy Instagram one!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now you can pass that Claim URL right on to your client and start the process of allowing them to claim the results and start working with them. &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%2Fmqmu2njweqs5sqfsd2xv.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%2Fmqmu2njweqs5sqfsd2xv.png" alt="login box for claimable cloud" width="800" height="677"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an early feature, with more agent-based tools coming from Cloudinary soon. Watch for more interesting work around AI agents in the near future!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Cloudinary ❤️ developers&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ready to level up your media workflow? Start using Cloudinary for free and build better visual experiences today.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👉 &lt;strong&gt;&lt;a href="https://link.cloudinary.com/ur1AT" rel="noopener noreferrer"&gt;Create your free account&lt;/a&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Cloudinary's New Image Generation API: One API, Multiple AI Models, and Built-in Asset Management</title>
      <dc:creator>Jen Looper</dc:creator>
      <pubDate>Wed, 08 Jul 2026 13:02:03 +0000</pubDate>
      <link>https://dev.to/cloudinary/cloudinarys-new-image-generation-api-one-api-multiple-ai-models-and-built-in-asset-management-3ldl</link>
      <guid>https://dev.to/cloudinary/cloudinarys-new-image-generation-api-one-api-multiple-ai-models-and-built-in-asset-management-3ldl</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;At conference booths, developers often ask whether we support image generation at Cloudinary, given our emphasis on media management. As of now, I can say "YES! yes, we do" - here's how!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cloudinary's Image Generation API lets developers generate images from text prompts using multiple AI model families, then store the result as a managed Cloudinary asset for delivery, optimization, resizing, and transformation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Original image copyright © REUTERS/ABC Affiliate WABC&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this tutorial, we'll use Python to call the API, generate an image, and save the final result to Cloudinary.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you'll build
&lt;/h2&gt;

&lt;p&gt;A Python script that can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate an image from a text prompt&lt;/li&gt;
&lt;li&gt;Choose a model family like &lt;code&gt;flux&lt;/code&gt;, &lt;code&gt;recraft&lt;/code&gt;, &lt;code&gt;gpt-image&lt;/code&gt;, &lt;code&gt;ideogram&lt;/code&gt;, or &lt;code&gt;nano-banana&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Save generated output as a managed Cloudinary asset&lt;/li&gt;
&lt;li&gt;Print the final image URL, public ID, size, and file size&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;First, follow &lt;a href="https://cloudinary.com/documentation/image_generation_addon" rel="noopener noreferrer"&gt;the instructions on Cloudinary docs&lt;/a&gt; to install the image generation add-on to your account. While you're in the Cloudinary console, make note of your API key, secret and the cloud name where you want assets to be stored.&lt;/p&gt;

&lt;p&gt;Install the Python dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Export your Cloudinary credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLOUDINARY_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-api-key"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLOUDINARY_API_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-api-secret"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLOUDINARY_CLOUD_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-cloud-name"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's your &lt;a href="https://gist.github.com/jlooper/4ef0ac33a6bd6e943d953f523d606412" rel="noopener noreferrer"&gt;script&lt;/a&gt;. Save it as 'generate.py'.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate your first AI image
&lt;/h2&gt;

&lt;p&gt;Run the script with a prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 generate.py &lt;span class="s2"&gt;"A medieval monk"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Farplam1tplas8pfkhdaf.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%2Farplam1tplas8pfkhdaf.png" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This image was generated with the default Flux model&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The script sends a request to Cloudinary's Image Generation API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;family&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model_family&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tier&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tier&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;managed_asset&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;public_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;public_id&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it calls the API using HTTP Basic Auth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;IMAGE_GEN_BASE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/generate/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cloud_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/text_to_image&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CLOUDINARY_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CLOUDINARY_API_SECRET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Choose an AI image model
&lt;/h2&gt;

&lt;p&gt;This is the fun part. You can pick the image generation model that best suits your use case. For example, I find that nano-banana works well with images that include text.&lt;/p&gt;

&lt;p&gt;You can switch model families without changing the rest of your application code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 generate.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"A futuristic Tokyo skyline at sunset"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model&lt;/span&gt; flux &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tier&lt;/span&gt; premium
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supported model families include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flux
gpt-image
ideogram
recraft
nano-banana
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe9vz84u8iq56c3vs7lfv.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%2Fe9vz84u8iq56c3vs7lfv.png" alt="Another monk" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This was the same prompt, done with Ideogram model&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That makes it easier to test different visual styles while keeping one integration path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Save generated images as Cloudinary assets
&lt;/h2&gt;

&lt;p&gt;The important part of the request is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;managed_asset&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;public_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;public_id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Cloudinary to save the generated image as a managed asset on your account, instead of returning only a temporary output.&lt;/p&gt;

&lt;p&gt;After generation, the script prints something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Image ready!
Public ID: generated/fox-hiking
URL: https://res.cloudinary.com/...
Size: 1024×1024 px
File size: 840 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the image is in Cloudinary, you can resize it, optimize it, crop it, transform it, and deliver it through Cloudinary's CDN. Wicked fast and easy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Full usage examples
&lt;/h2&gt;

&lt;p&gt;Generate a new image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 generate.py &lt;span class="s2"&gt;"Marie de France playing pool"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuv5iwudlfmr3567cibqm.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%2Fuv5iwudlfmr3567cibqm.png" alt="Marie de France" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I love this image! Marie de France was a 12th century author of some famous french literature that I particularly like. I don't think she ever played pool, though. Also this pool table is awesomely 'AI-pilled"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Use a premium model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 generate.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"A cinematic product photo of a sneaker floating over water"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model&lt;/span&gt; flux &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tier&lt;/span&gt; premium
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why this is useful
&lt;/h2&gt;

&lt;p&gt;Most image generation APIs return an output.&lt;/p&gt;

&lt;p&gt;Cloudinary's Image Generation API returns an output that can immediately become part of your media pipeline.&lt;/p&gt;

&lt;p&gt;That means developers can generate an image and then use the same platform to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store it&lt;/li&gt;
&lt;li&gt;Transform it&lt;/li&gt;
&lt;li&gt;Optimize it&lt;/li&gt;
&lt;li&gt;Resize it&lt;/li&gt;
&lt;li&gt;Deliver it&lt;/li&gt;
&lt;li&gt;Reuse it across applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For apps that already manage media with Cloudinary, AI image generation becomes part of the existing workflow instead of a separate one-off process. The pipeline just got way simplified for you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;This Python script is small, but it covers the core production workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Authenticate with Cloudinary&lt;/li&gt;
&lt;li&gt;Send a prompt to the Image Generation API&lt;/li&gt;
&lt;li&gt;Choose a model family and tier&lt;/li&gt;
&lt;li&gt;Save the result as a managed asset&lt;/li&gt;
&lt;li&gt;Return a usable image URL&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're building developer tools, e-commerce workflows, campaign generators, or AI-powered creative apps, this approach gives you both image generation and image delivery in the same pipeline.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Cloudinary ❤️ developers&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ready to level up your media workflow? Start using Cloudinary for free and build better visual experiences today.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👉 &lt;strong&gt;&lt;a href="https://link.cloudinary.com/urmty" rel="noopener noreferrer"&gt;Create your free account&lt;/a&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>ai</category>
      <category>nanobanana</category>
      <category>codenewbie</category>
      <category>images</category>
    </item>
    <item>
      <title>Magnificent Humanity, Building Cities, and a Special Announcement!</title>
      <dc:creator>Jen Looper</dc:creator>
      <pubDate>Fri, 05 Jun 2026 19:37:39 +0000</pubDate>
      <link>https://dev.to/jenlooper/magnificent-humanity-building-cities-and-a-special-announcement-54pf</link>
      <guid>https://dev.to/jenlooper/magnificent-humanity-building-cities-and-a-special-announcement-54pf</guid>
      <description>&lt;p&gt;I'm back from a great vacation and side-quest experience in Asia, where one can always find brilliant human interactions even with imperfect linguistic competence. For example, having a haircut at a random salon in Taipei where the little nephew of the stylist offered fashion advice on the spot, gravely shaking his head at short haircuts for ladies, and anyway why didn't I dye it purple? Or a &lt;a href="https://x.com/jenlooper/status/2061302787963535710?s=20" rel="noopener noreferrer"&gt;photoshoot&lt;/a&gt; on a bamboo raft on the Li river in the Zhuang autonomous region, with full-on Chinese style makeup in local costume for a solid two hours in the boiling sun with a patient photog.&lt;/p&gt;

&lt;p&gt;While I was on vacation, Pope Leo published something important. It turns out, the "Woke Pope" is participating in an ever-more-woke religious discourse straight outta the Vatican, and as a borderline agnostic Protestant, I found it incredibly empowering. His "Magnifica Humanitas" encyclical is the thought leadership core document that many of us have looked for - a work that doesn't land on either the AI-hater or the All-In-AI extreme, but, in the best devout tradition, looks to religious texts for guidance to discover narratives that can guide our steps as we try to build with AI while not wrecking the world. Let's talk about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Encyclical
&lt;/h2&gt;

&lt;p&gt;This &lt;a href="https://www.vatican.va/content/leo-xiv/en/encyclicals/documents/20260515-magnifica-humanitas.html" rel="noopener noreferrer"&gt;document&lt;/a&gt; is long and wide-ranging. It's broken into five chapters; the first two discuss the Catholic Church's evolving concept of Social Doctrine, the third talks about how AI is being built and dives into the narratives surrounding this building effort, the fourth discusses concepts of human dignity and freedom within this evolving ecosystem, and the final chapter offers a critique of the current ever-more ferocious culture of war and the aggressive exercise of raw power, citing the need to "disarm" these systems to build a "civilization of love". It's a beautiful vision, and a multimedia experience; there are videos and infographics - this is a Pope who well-understands the internet and the power of imagery.&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%2Fznmrds507j1pg16el7h5.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%2Fznmrds507j1pg16el7h5.png" alt="Risks vs Humane AI" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Risks vs Humane AI&lt;/p&gt;

&lt;p&gt;I didn't have it in my 2026 Bingo card to have the Pope exhorting software engineers: "Developers ... bear a particular ethical and spiritual responsibility, for every design choice reflects a vision of humanity. Just as the creator of an artistic or literary work must consider the values it conveys, so developers are called to embed values in their projects with due seriousness: with transparency, responsibility toward affected communities and careful attention to ensuring that what is being cultivated is a genuine good."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Parables and Exemplars
&lt;/h2&gt;

&lt;p&gt;One motif that stood out to me is the Pope's insistence that, as part of the magnificence of humanity, every person is of value. But how can that value be measured? Rather than valuing the human by their output, society is better served by valuing the dignity of work itself. Stemming from the crisis of work triggered by the industrial revolution, the Church's social doctrine is evolving to cover a similar crisis around ensuring that everyone is afforded the ability to contribute to the social good via their work. "The human person is an end, not a means" flies directly in the face of much of the &lt;a href="https://www.adventuresinoss.com/aws-four-years/" rel="noopener noreferrer"&gt;toxic corporate culture&lt;/a&gt; prevailing today.&lt;/p&gt;

&lt;p&gt;The focus on recentering human beings within this high-tech moment has led some folks to closely examine the narratives presented in the document. One thing that longstanding religious traditions do well is use stories and parables to teach underlying values. The Pope leans on the well-known story of the Tower of Babel and the less well-known story of Nehemiah's rebuilding of Jerusalem to show 'exemplars'. Rather than creating a grandiose, yet dehumanizing tower where communication breaks down, we are encouraged to look at the way Nehemiah organized the collaborative rebuilding of a city for the greater good. This is a model of building software - AI or other - that benefits the many, rather than just a few oligarchs.&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%2Fqbr8433ftzwerwq0asdo.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%2Fqbr8433ftzwerwq0asdo.png" alt="Two Cities, Two Models" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Two Cities, Two Models&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One interesting aspect of this encyclical is the use of inclusive language and the special attention paid to those left behind by technological advances. The Pope takes care to address "men and women of goodwill" - an improvement on similar writing of the past, and notes that "there is still a long way to go to ensure that the rights of a great many, namely women, are equally and genuinely guaranteed throughout the world." But there is little acknowledgement about the specific ways that women have backslid in recent years or what specifically we should do to ensure equity.&lt;/p&gt;

&lt;p&gt;I'll be honest here. I'm really worried about how people who identify as women are showing up in this new world. Starting in the mid 2010s, we worked at the grass roots to build community, launch initiatives, press companies for diversity programming, and create inclusive education. Today I'm seeing women-focused grass-roots orgs shut down or sucked into a corporation completely divorced from their grass-roots origin (WWC, I'm looking at you). In today's climate of oligarchy, technocracy, bare-knuckled corporate competition, and the dominance of silicon valley in AI discourse, I'm hard pressed to name 20+ visible female leaders who are influencing how AI is being built from an engineering standpoint. We all saw &lt;a href="https://www.ndtv.com/world-news/donald-trump-xi-jinping-summit-sparks-backlash-over-one-striking-detail-no-women-on-table-11502112" rel="noopener noreferrer"&gt;that awful photo&lt;/a&gt; of the Trump/Xi summit, with ZERO women at the table. This image says 1000 words. It's time to muscle back in to make sure we have a seat at the table so that we can build the kind of AI reality the Pope is envisioning.&lt;/p&gt;

&lt;p&gt;We are in fact entering a perfect storm of underrepresentation, gaps in perception, and disproportional impact of AI on women's careers. According to &lt;a href="https://www.forbes.com/sites/joemckendrick/2025/04/22/women-make-gains-in-ai-but-roadblocks-remain" rel="noopener noreferrer"&gt;Forbes&lt;/a&gt;, &lt;a href="https://www.axios.com/2026/04/01/leanin-sheryl-sandberg-ai-women-men-work" rel="noopener noreferrer"&gt;Axios&lt;/a&gt;, and &lt;a href="https://www.weforum.org/stories/2025/06/amnc25-what-to-know-about-ai-and-the-gender-gap" rel="noopener noreferrer"&gt;panels at Davos&lt;/a&gt;, growth is slow, gaps remain large, and women are especially hard-hit by AI disruption.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Women in AI engineering and research: slowly increasing but still underrepresented&lt;/li&gt;
&lt;li&gt;Women in AI leadership: Increasing, but leadership gap remains large&lt;/li&gt;
&lt;li&gt;Women using GenAI at work: Lower adoption than men&lt;/li&gt;
&lt;li&gt;Women receiving recognition for AI use: Lower than men, even when usage is similar&lt;/li&gt;
&lt;li&gt;Jobs most exposed to AI disruption: Disproportionately female-dominated occupations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  So what are we going to do to close this gender gap?
&lt;/h3&gt;

&lt;h2&gt;
  
  
  A New City
&lt;/h2&gt;

&lt;p&gt;Pope Leo leans on a comparison between two polar opposite models of building. But I propose that there's a third model that was described in the late Middle Ages by one of the first feminist writers in the West: Christine de Pizan, who wrote a rebuttal to the current fashionable narrative of her times, the Roman de la Rose. Rejecting this misogynistic (albeit wildly popular) book, she wrote her own vision of a new city: &lt;strong&gt;The City of Ladies&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.amazonaws.com%2Fuploads%2Farticles%2Fj4nn4cj9a0zlwg54p0pq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4nn4cj9a0zlwg54p0pq.jpg" alt="Christine listens, learns, and builds" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Christine listens, learns, and builds&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In Christine's vision, completed around 1405, the goddesses Reason, Rectitude and Justice all confer with the author to construct a new city populated by the virtuous women of history. Armed with the 'spade of intelligence' Christine sets to work to build the city, telling the stories of righteous women while building the walls, houses, and appointing a queen to rule them all.&lt;/p&gt;

&lt;p&gt;These positive examplars of women of noble character continue the biblical tradition of providing instructive stories - and we can use this late medieval vision to provide a roadmap into something that I'm proud to launch as of today: &lt;strong&gt;a new nonprofit initiative that I'm calling &lt;a href="https://heraistudio.org/" rel="noopener noreferrer"&gt;Her AI Studio&lt;/a&gt;&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.amazonaws.com%2Fuploads%2Farticles%2Fwmm94d18fikyd9qa6ncz.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%2Fwmm94d18fikyd9qa6ncz.png" alt="Her AI Studio" width="500" height="643"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://heraistudio.org" rel="noopener noreferrer"&gt;https://heraistudio.org&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As an experienced nonprofit and educational founder (Wellesley Chinese Language School Co-Founder, Vue Vixens, Inc. Founder and CEO, &lt;a href="https://ff-school.jenlooper.com/" rel="noopener noreferrer"&gt;Front-End Foxes School&lt;/a&gt; Founder and CEO, &lt;a href="https://beanpotstudio.com/" rel="noopener noreferrer"&gt;Beanpot Studio&lt;/a&gt; CEO) I know what it takes to launch nonprofits and keep them going through funding and mission challenges (hello COVID). So what will we build, exactly?&lt;/p&gt;

&lt;p&gt;I'm inspired with a conversation with my daughter about the new interest in Cyber decks that's causing a renewed grass roots community to build hardware projects. I want this nonprofit organization to go global, opening cohorts for high-school aged students who identify as women mentored by college-aged students (and older) who will get girls building, fast. Staying on device, offline, and local, we will learn about protecting data, building ethically with locally-hosted models, and conserving our energy. We will focus on a four-beat cadence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Beginners: Discover - learn about AI by discovering the women who influenced and built the field, while building your first locally powered AI app.&lt;/li&gt;
&lt;li&gt;Intermediate: Create - build a local AI project bridging hardware and software focusing on image, text, and voice.&lt;/li&gt;
&lt;li&gt;Advanced: Engineer - build your cyber deck with your own kit, learning to program with AI and using AI to program.&lt;/li&gt;
&lt;li&gt;Capstone: Showcase your project in international celebrations - you're now ready to pay it forward!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What are we looking for?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interest&lt;/strong&gt; - do you want to mentor? would you like to join me in crafting curriculum? are you a teacher curious about the initiative, or a student who'd like to potentially join? Sign the interest form at heraistudio.org.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Funding&lt;/strong&gt; - we can't go it alone. Each student kit is going to cost about $250 - we are looking for sponsors. Please reach out!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expertise&lt;/strong&gt; - I've been working with hardware for years but chatting with you helps me stay up to date. I'd love to chat and learn your perspective on building with this model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Join our Discord: &lt;a href="https://discord.gg/jRkR2t4UpC" rel="noopener noreferrer"&gt;https://discord.gg/jRkR2t4UpC&lt;/a&gt; and let's chat.&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%2Fau7kfc3tayyegrq345bq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fau7kfc3tayyegrq345bq.jpg" alt="Get in, losers, we're gonna build a nonprofit" width="369" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Get in, losers, we're gonna build a nonprofit&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>wecoded</category>
      <category>programming</category>
      <category>iot</category>
    </item>
    <item>
      <title>Say It With Flowers: BouqAIs with the Tussie-Mussie Generator</title>
      <dc:creator>Jen Looper</dc:creator>
      <pubDate>Sat, 09 May 2026 17:19:01 +0000</pubDate>
      <link>https://dev.to/cloudinary/say-it-with-flowers-bouqais-with-the-tussie-mussie-generator-3do0</link>
      <guid>https://dev.to/cloudinary/say-it-with-flowers-bouqais-with-the-tussie-mussie-generator-3do0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;&lt;a href="https://tussie-mussies.netlify.app" rel="noopener noreferrer"&gt;Tussie-Mussie Generator&lt;/a&gt;&lt;/strong&gt; is a web app for anyone who wants to send a meaningful floral e-card with an AI-generated "tussie mussie", a type of small nosegay. It uses the Victorian language of flowers to compose a bouquet, generates an image with Gemini, and sends it via Resend. This post covers &lt;br&gt;
a Mother's Day relaunch: fixing a broken email integration and swapping the AI image model.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What changed in this relaunch
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Migrated email sending from Mailgun to Resend, including a Cloudflare serverless function&lt;/li&gt;
&lt;li&gt;Fixed DNS configuration across Porkbun, Netlify, and Resend for a custom subdomain&lt;/li&gt;
&lt;li&gt;Replaced the previous image generator with Gemini for accurate tussie mussie generation&lt;/li&gt;
&lt;li&gt;Refactored the UI with Astro + Vue and impeccable.style for AI-assisted critique&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Have you ever wanted to build an e-card system that would allow you to send little ai-generated bouquets to your friends? No? Yes? Read on, gentle reader!&lt;/p&gt;

&lt;p&gt;Last year, I onboarded to my new job by building this sample app that lets you use the Victorian language of flowers to compose a bouquet. An image-heavy app like this is a great candidate for hosting and optimizing via Cloudinary, so all the flower images are stored there. An image of the composed bouquet is generated by Gemini, and then sent via Resend to the recipient of your choice. The app looks like this:&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%2Fj3w0zh47qr8wxul07kfk.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%2Fj3w0zh47qr8wxul07kfk.png" alt="Tussie Mussie Generator" width="800" height="722"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and the generated e-card looks like this:&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%2F9hl2hu7bcummpftq8k7x.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%2F9hl2hu7bcummpftq8k7x.png" alt="demo" width="800" height="1245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I launched this app a year ago, and it's had an interesting lifespan. I wanted to relaunch it for Mother's Day and realized there was some refactoring to do! &lt;/p&gt;

&lt;p&gt;Here are a few of the gotchas I dealt with:&lt;/p&gt;

&lt;p&gt;Keeping the core: The basis of this app is its dataset, which I created a while ago on &lt;a href="https://www.kaggle.com/datasets/jenlooper/language-of-flowers" rel="noopener noreferrer"&gt;Kaggle&lt;/a&gt; as a useful version of the Victorian "Language of Flowers", scraped from the &lt;a href="https://www.almanac.com/flower-meanings-language-flowers#flower-meanings" rel="noopener noreferrer"&gt;Farmer's Almanac&lt;/a&gt;. Here's an example of what that looks like:&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%2Fz5l8fjmwlta0yy1trhoa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz5l8fjmwlta0yy1trhoa.jpg" alt="Almanac version of florilege" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your idea is centered around a solid dataset, you can't go wrong. Once I had the list, it took me a while to scrape images of the flowers in question and store them, optimized, on Cloudinary. But that work was done a year ago. So two things remained for the relaunch: refactoring the UI and fixing the bits that stopped working, namely the e-card generator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring the UI
&lt;/h2&gt;

&lt;p&gt;This app is built using my preferred stack, namely Astro + Vue. After a year, it was definitely time to upgrade, including fixing the tailwind integration which relied on an outdated package. Cursor made short work of that - it's one of the best uses of AI software agents.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: periodically ask your AI to plan the removal of any redundant files or code while you complete refactors. There are usually vestiges that can be deleted.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I used a wildly useful AI skill to refactor my admittedly basic UI: &lt;a href="https://impeccable.style/" rel="noopener noreferrer"&gt;impeccable.style&lt;/a&gt;. Install these skills on your machine and as you work with any AI generated UI suggestions, run &lt;code&gt;/impeccable critique&lt;/code&gt; to reality-check your work for taste and style. I'm now using impeccable on all my UIs - it also helped me tidy &lt;a href="https://jenlooper.com" rel="noopener noreferrer"&gt;my portfolio&lt;/a&gt;. The UI went from this: &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%2Fx6luq0346nkg7qkrvbv2.webp" 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%2Fx6luq0346nkg7qkrvbv2.webp" alt="old UI" width="800" height="638"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;...to the UI shown above. I like it a lot. &lt;/p&gt;




&lt;h2&gt;
  
  
  Fixing the E-Card functionality
&lt;/h2&gt;

&lt;p&gt;This app caused me a horrible panic after launch last year, ruining an anniversary dinner, due to a kerfuffle with Mailgun, the original e-card sending mechanism. I was shocked by an enormous overage charge due to hacking of their systems, and I shut the entire thing down as fast as I could. To relaunch, I needed to find a new service to send email via API. Once again, Cursor to the rescue. &lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://resend.com/" rel="noopener noreferrer"&gt;Resend&lt;/a&gt;, a new email service that is much more solid than my previous choice. Let us hope that we have smooth sailing from now on! The integration includes a serverless function that you can host on Cloudflare, and works well as soon as you verify a domain. That last part took me the longest time - the gotcha is that since I bought the domain on Porkbun, I had to edit DNS records there to serve emails from a subdomain. The site is hosted on Netlify, so I had to build the subdomain there, and then the DNS verified on Resend. It's the kind of task that you don't do often, so it's easy to miss a step. But all is set now, and the emails are sending!&lt;/p&gt;

&lt;p&gt;I also had to reconsider how to build the AI generated bouquets. I'm out of credits on the service I previously chose to generate the bouquets, and they were never quite right anyway (generated as standard bouquets rather than true tussie mussies which have a silver filigree holder). It's crazy to see how AI has evolved for this esoteric imagery over the past year - now Gemini can accurately compose a tussie mussie in its holder, given a specific prompt.&lt;/p&gt;

&lt;p&gt;Enjoy these little bouquets! &lt;a href="https://tussie-mussies.netlify.app/" rel="noopener noreferrer"&gt;Send one to your Mom today&lt;/a&gt;!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Cloudinary ❤️ developers&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ready to level up your media workflow? Start using Cloudinary for free and build better visual experiences today.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👉 &lt;strong&gt;&lt;a href="https://link.cloudinary.com/uoTiK" rel="noopener noreferrer"&gt;Create your free account&lt;/a&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>ai</category>
      <category>gemini</category>
      <category>astro</category>
      <category>vue</category>
    </item>
    <item>
      <title>How to Win a Hackathon</title>
      <dc:creator>Jen Looper</dc:creator>
      <pubDate>Sun, 03 May 2026 03:43:08 +0000</pubDate>
      <link>https://dev.to/cloudinary/how-to-win-a-hackathon-1377</link>
      <guid>https://dev.to/cloudinary/how-to-win-a-hackathon-1377</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A sponsor’s perspective&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This blogpost is written on the heels of a few amazing weekends spent knee-deep in students in Toronto and Los Angeles at Hack Canada and LA Hacks, engaging almost 2000 students in person in total. Managing a sponsor track, I have some thoughts on good ways to present yourselves when angling your project towards a sponsor prize.&lt;/p&gt;

&lt;p&gt;For those not as familiar with how student hackathons work, they are usually comprised of an organized weekend populated by college undergrads (or older, or younger! high schoolers are increasingly getting into the mix). Over about 36 hours, students form teams and try to build software that meets a need, solves a problem, or proves a point. Some hackathons focus on themes around social good, like Hack Canada which challenged students to build something of special interest to Canada. Others have several themes and a full roster of sponsored options. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hackathons are a bastion of the cozy web! It’s a delight to see students embracing the freedom to create weird, useless, and wildly creative apps like AeroMaxx, a way to gauge influencers’ aerodynamic-maxxing (Taylor Swift is more aerodynamic than Clavicular, did you know?). LA Hacks even had a track embracing the “most questionable” hack, won by “Yes? Or Yes!”, a hack that had literal goldfish helping make decisions and trigger AI agents to do things like break up with a girl friend, quit a job, and post to social media. Great projects. Please keep building this kind of weird stuff.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgn9ghxj1wt5pctpuhve0.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%2Fgn9ghxj1wt5pctpuhve0.png" alt="MagByte" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a cozy interface for roommates to manage their shopping lists: &lt;a href="https://devpost.com/software/magbite?_gl=1*1nkfo64*_gcl_au*MjA0ODI2ODI1OC4xNzcyOTAyNTc4*_ga*Mzk1NTQ4NjAwLjE3NzI5MDI1Nzk.*_ga_0YHJK3Y10M*czE3Nzc3Nzc1MDMkbzM4JGcxJHQxNzc3Nzc3NjM5JGo0OCRsMCRoMA.." rel="noopener noreferrer"&gt;MagByte&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s a great moment to let your creativity run wild:&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%2Fi55ce5tfipfpjajllj59.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%2Fi55ce5tfipfpjajllj59.png" alt="goldfish q&amp;amp;a" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://devpost.com/software/yes-or-yes?_gl=1*nv0asj*_gcl_au*MjA0ODI2ODI1OC4xNzcyOTAyNTc4*_ga*Mzk1NTQ4NjAwLjE3NzI5MDI1Nzk.*_ga_0YHJK3Y10M*czE3Nzc3Nzc1MDMkbzM4JGcxJHQxNzc3Nzc4MTA2JGo1NiRsMCRoMA.." rel="noopener noreferrer"&gt;Yes? Or Yes!&lt;/a&gt; LA Hacks most unhinged hack winner - goldfish help you make decisions and then trigger agentic workflows. Good luck!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ve been working the hackathon circuit as a developer advocate for at least ten years, including the mess during COVID, and the major difference nowadays between the earlier events is, unsurprisingly, the heavy use of AI tooling that both speeds up delivery, polishes the final product, and gets more software shipped, way faster. Instead of watching demo videos, judges can actively interact with an almost production-ready app, shockingly quickly.&lt;/p&gt;

&lt;p&gt;Still, there are some tips and tricks that I’d like to share based on a few recent observations of these very fun events. Here are five things to keep in mind as you go for a win!&lt;/p&gt;

&lt;h2&gt;
  
  
  Who’s it for?
&lt;/h2&gt;

&lt;p&gt;A lot of folks are attracted to social-good type projects, and that’s very laudable. I love them, personally, and tend to mark them highly in my judging rubric. I just want to caution hackathon participants against going after this vector with a “tech savior complex”. It’s easy to think that tech can solve all the things. And tech has made great strides on devices such as most smart phones to help people with various accessibility issues such as those who are blind, color blind, experience hearing loss, or are mobility-challenged. &lt;/p&gt;

&lt;p&gt;But if you are going to create a project for a given sector of users, it’s critical to come at these projects with an open mindset and humility, and to work with people who have these actual challenges. Working on an app for older people? Call your Grandma or Grandpa before you start building. It’s likely they can guide you to refining your app to make it much more useful.&lt;/p&gt;

&lt;p&gt;At Hack Canada, teams succeeded who spent time talking to local security guards as they built, to ensure that their safety-oriented hack would be useful. It’s all about finding your customer and/or user, and building backwards from that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Power to the People
&lt;/h2&gt;

&lt;p&gt;Sponsors and mentors are often available to help you all the way through the event, so make use of them! Take some time before you start working to talk to sponsors and see if they can help you start to ideate. Learn about the various sponsors and what they are looking for. Some are looking for product feedback, some are hiring, others may have another agenda. &lt;/p&gt;

&lt;p&gt;Maybe you’ll find a product that you never heard of and will make a nice professional connection. Get your LinkedIn app ready to scan codes! This is a great moment to network.&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%2F82424uizvh1gzcbpfr3z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82424uizvh1gzcbpfr3z.jpg" alt="Jen and Raya" width="582" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;At your service at the booth!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Skill Up
&lt;/h2&gt;

&lt;p&gt;The use of AI tools has accelerated the build phase of a hackathon almost beyond recognition. When I was judging hackathons around 2016 or so, the projects produced were super shaky - often the hacker created a video at the moment that the app worked, and showed that to a judge as it was highly unlikely they could ever get it working again! This has all changed when AI has become such an important build partner.&lt;/p&gt;

&lt;p&gt;The use of AI, however, shifts the focus of a hackathon away from the software engineering tasks that now can be offloaded to agents (with supervision, of course!). Now, you need to spend a good amount of time getting set up to make your AI as successful and efficient as you can. Many vendors have created tools to help; we at Cloudinary produced a Skills Pack for this purpose: &lt;a href="https://github.com/cloudinary-devs/skills" rel="noopener noreferrer"&gt;https://github.com/cloudinary-devs/skills&lt;/a&gt;. Using tools such as these will effectively give official context to your app, preventing hallucinations and other wasting of time. &lt;/p&gt;

&lt;h2&gt;
  
  
  Sponsormaxxing and platformmaxxing
&lt;/h2&gt;

&lt;p&gt;There’s a trend towards “sponsormaxxing” - LA Hacks even had a track for this. The term refers to the incorporation of as many sponsors’ platforms as possible in a given hack. I think it’s a fun challenge, but there’s a risk: if you want to win a sponsor track, you’ll likely be judged on deep integration with their platform. &lt;/p&gt;

&lt;p&gt;In our case at Cloudinary, I’m looking for not just the use of the platform as a place to dump images and video, but a deep use of the APIs, for example optimizing and transforming images in an AI pipeline with the goal of constructing videos (as you can do with our winning hack from LA Hacks, StudyO!). Going for a sponsor track prize? Focus on deep integrations.&lt;/p&gt;

&lt;p&gt;Going deep, however, can also be risky! There’s the risk of “platformmaxxing” - using every bell and whistle of a platform to try it out. You may need to be a bit strategic here, as you might max out your credits by piling on as many platform aspects as you can. Watch out for signs of maxing out your credits and plan accordingly.&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%2Folgg9609kdf96demfwx8.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%2Folgg9609kdf96demfwx8.png" alt="AeroMaxx" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Speaking of maxxing: &lt;a href="https://devpost.com/software/aeromaxx?_gl=1*vb7ib8*_gcl_au*MjA0ODI2ODI1OC4xNzcyOTAyNTc4*_ga*Mzk1NTQ4NjAwLjE3NzI5MDI1Nzk.*_ga_0YHJK3Y10M*czE3Nzc3Nzc1MDMkbzM4JGcxJHQxNzc3Nzc3OTE0JGoxNiRsMCRoMA.." rel="noopener noreferrer"&gt;AeroMaxx&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Perfect the Pitch
&lt;/h2&gt;

&lt;p&gt;Judges have only a few minutes per team so you need to make your best impression right away. Come ready to demo with your storytelling skills well in hand. Do some trial runs prior, and get feedback on your presentation skills. Lead with the use case, show the demo, and field questions. A good strategy for a 2-3 minute hackathon pitch is to focus on the problem you see, the solution you propose, and the impact you predict. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hook (15 seconds): Introduce yourself, state the problem you are solving, and share a relatable scenario or story.&lt;/li&gt;
&lt;li&gt;Demo (60-90 seconds): Walk the audience through your core feature&lt;/li&gt;
&lt;li&gt;Tech (30 seconds): Briefly explain the most impressive technical hurdle you overcame or the tech stack that powers the hack.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: Consider recording a video of your demo just in case there’s a horrible glitch, and practice getting over a glitchy demo. You can do it!&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Pitching can be intense!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Winning a hackathon is a great goal, but don’t forget that being accepted into some of these selective hackathons, participating, and building a piece of software that you can be proud of is very laudable as well. Wishing you the best of luck! And maybe we will see you there.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Cloudinary ❤️ developers&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ready to level up your media workflow? Start using Cloudinary for free and build better visual experiences today.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👉 &lt;strong&gt;&lt;a href="https://link.cloudinary.com/uoBac" rel="noopener noreferrer"&gt;Create your free account&lt;/a&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>career</category>
      <category>community</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>6 Free Cloudinary Courses That Teach You to Build Media-Optimized Apps</title>
      <dc:creator>Jen Looper</dc:creator>
      <pubDate>Thu, 30 Apr 2026 18:33:51 +0000</pubDate>
      <link>https://dev.to/cloudinary/6-free-cloudinary-courses-that-teach-you-to-build-media-optimized-apps-51m2</link>
      <guid>https://dev.to/cloudinary/6-free-cloudinary-courses-that-teach-you-to-build-media-optimized-apps-51m2</guid>
      <description>&lt;p&gt;The Cloud to Crowd (C2C) curriculum is Cloudinary's free 6-course learning suite for developers who want to build and ship applications with production-quality image and video handling. It covers everything from Cloudinary basics to AI-powered transformations paired with hands-on projects at every step and a free certificate when you complete each course.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fun fact: community member Jerome Hardaway of Vets Who Code, one of our nonprofit partners in the Creators Community program, coined the "Cloud to Crowd" term!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What You'll Be Able to Build After This Curriculum
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Upload, manage, and transform media assets using the Cloudinary API&lt;/li&gt;
&lt;li&gt;Optimize images and video for performance in a Next.js app&lt;/li&gt;
&lt;li&gt;Apply AI-powered features: background removal, generative fill, auto-tagging&lt;/li&gt;
&lt;li&gt;Use the Python SDK to automate media workflows on the backend&lt;/li&gt;
&lt;li&gt;Deliver video efficiently with format and quality auto-selection&lt;/li&gt;
&lt;li&gt;Ship a real portfolio project that demonstrates all of the above&lt;/li&gt;
&lt;li&gt;Earn a Cloudinary certificate and qualify for the Creators Community&lt;/li&gt;
&lt;/ul&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%2Fevy6pbfnmkb347ezgdgs.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%2Fevy6pbfnmkb347ezgdgs.png" alt="Cloudinary Academy Courseware" width="800" height="577"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We Built This
&lt;/h2&gt;

&lt;p&gt;Getting images and video right in a production app is harder than most tutorials suggest. Resize, format, optimize, deliver — each step has tradeoffs, and most learning resources skip the messy middle. The C2C courses are designed to fill that gap: structured, project-driven, and free.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 6 Free Courses
&lt;/h2&gt;

&lt;p&gt;All courses are self-paced and free at &lt;a href="https://training.cloudinary.com/pages/c2c" rel="noopener noreferrer"&gt;https://training.cloudinary.com/pages/c2c&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Course 1: Media IQ for Developers
&lt;/h3&gt;

&lt;p&gt;Enroll: &lt;a href="https://training.cloudinary.com/learn/course/devrel-c2c-intro" rel="noopener noreferrer"&gt;https://training.cloudinary.com/learn/course/devrel-c2c-intro&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The starting point for the first three courses in this suite. This course covers the core Cloudinary concepts: cloud name, API keys, the Media Library, and your first upload and transformation. No prior Cloudinary experience needed. By the end, you'll have a free account set up and understand how assets move through the Cloudinary pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You'll learn to:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose the right image formats for your use case, understanding when to use JPEG, PNG, WebP, AVIF, or SVG based on content type, browser support, and performance trade-offs&lt;/li&gt;
&lt;li&gt;Apply strategic optimization techniques including responsive images with automatic format/quality selection and intelligent cropping with gravity detection&lt;/li&gt;
&lt;/ul&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%2Fry0mgv63008yznpxadxa.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%2Fry0mgv63008yznpxadxa.png" alt="Heavy Watch image" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Course 2: Media IQ for Developers with Next.js
&lt;/h3&gt;

&lt;p&gt;Enroll: &lt;a href="https://training.cloudinary.com/learn/course/devrel-c2c-next" rel="noopener noreferrer"&gt;https://training.cloudinary.com/learn/course/devrel-c2c-next&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The flagship course of the C2C curriculum. You'll build a storefront application (the "CapZone" e-commerce store) using Next.js and the Cloudinary Next.js SDK, applying real-world image optimization patterns throughout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You'll learn to:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build an image-optimized web application using Cloudinary to upload, store, transform, and deliver images on-the-fly through URL-based transformations and CDN delivery&lt;/li&gt;
&lt;li&gt;Apply strategic optimization techniques including responsive images with automatic format/quality selection and intelligent cropping with gravity detection&lt;/li&gt;
&lt;li&gt;Create Next.js components that handle image uploading, display optimized images with overlays and watermarks, and serve different sizes for different contexts&lt;/li&gt;
&lt;/ul&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%2Fhhpe6j2tmei2fq4ao40v.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%2Fhhpe6j2tmei2fq4ao40v.png" alt="CapZone store" width="800" height="676"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The kind of component you'll be writing by the end of this course:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CldImage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-cloudinary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductImage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;publicId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;publicId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CldImage&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;publicId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;crop&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"fill"&lt;/span&gt;
      &lt;span class="na"&gt;gravity&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"auto"&lt;/span&gt;
      &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"auto"&lt;/span&gt;
      &lt;span class="na"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"auto"&lt;/span&gt;
      &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Course 3: Media IQ for Developers with AI
&lt;/h3&gt;

&lt;p&gt;Enroll: &lt;a href="https://training.cloudinary.com/learn/course/devrel-c2c-ai" rel="noopener noreferrer"&gt;https://training.cloudinary.com/learn/course/devrel-c2c-ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cloudinary's AI-powered transformation features are some of its most practical and useful. This course covers the tools that save the most time in real projects: background removal, generative fill, object-aware cropping, and auto-tagging. This course follows the Next.js course, building AI into the CapZone store by adding a color picker to colorize the hats.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You'll learn to:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove or replace backgrounds using e_background_removal&lt;/li&gt;
&lt;li&gt;Use generative fill to extend or recompose images&lt;/li&gt;
&lt;li&gt;Apply smart cropping with gravity: "auto" for face- and object-aware results&lt;/li&gt;
&lt;li&gt;Auto-tag assets using AI analysis to make large libraries searchable&lt;/li&gt;
&lt;/ul&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%2Fb4ryvwuokux6f54ai35k.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%2Fb4ryvwuokux6f54ai35k.png" alt="AI CapZone" width="800" height="811"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Course 4: Media IQ for Developers with Video
&lt;/h3&gt;

&lt;p&gt;Enroll: &lt;a href="https://training.cloudinary.com/learn/course/devrel-c2c-video" rel="noopener noreferrer"&gt;https://training.cloudinary.com/learn/course/devrel-c2c-video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Video is a different beast from images; you manage larger files, adaptive bitrates, more delivery complexity. This course covers the Cloudinary video pipeline from upload to playback. It's the third and final part of the progressive enhancement of the CapZone e-commerce web app that you started prior. In this course you'll add a video to one of the products.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You'll learn to:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upload and transcode video using the Cloudinary API&lt;/li&gt;
&lt;li&gt;Apply video transformations: trim, resize, overlay, add subtitles&lt;/li&gt;
&lt;li&gt;Build playlists and seekbars with subtitles&lt;/li&gt;
&lt;/ul&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%2F2xo1znkfbl48ywp9zu6d.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%2F2xo1znkfbl48ywp9zu6d.png" alt="Video with playlist on CapZone" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Course 5: Media IQ for Developers with Python
&lt;/h2&gt;

&lt;p&gt;For less JavaScript-focused developers, this course covers Cloudinary's Python SDK: uploading, managing, and transforming assets from any Python environment.&lt;br&gt;
Enroll: &lt;a href="https://training.cloudinary.com/learn/course/devrel-c2c-python" rel="noopener noreferrer"&gt;https://training.cloudinary.com/learn/course/devrel-c2c-python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You'll learn to:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authenticate and configure the Python SDK&lt;/li&gt;
&lt;li&gt;Upload and tag assets for organization&lt;/li&gt;
&lt;li&gt;Build a small pet store app&lt;/li&gt;
&lt;/ul&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%2Fq1f7brwa80h9bjk2p7yy.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%2Fq1f7brwa80h9bjk2p7yy.png" alt="pet store app" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Course 6: Building a Developer Portfolio with Cloudinary and Next.js
&lt;/h2&gt;

&lt;p&gt;Enroll: &lt;a href="https://training.cloudinary.com/learn/course/devrel-c2c-portfolio" rel="noopener noreferrer"&gt;https://training.cloudinary.com/learn/course/devrel-c2c-portfolio&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The capstone course. You'll apply everything from the earlier modules: upload, transformation, optimization, and AI features — to build a complete portfolio site using React and TypeScript that demonstrates your Cloudinary skills to employers. Focus on your own skills and show them off to the world in a media-rich website.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You'll learn to:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architect a media-rich portfolio app from scratch&lt;/li&gt;
&lt;li&gt;Combine multiple Cloudinary transformations into a polished UI&lt;/li&gt;
&lt;li&gt;Optimize for performance: lazy loading, responsive breakpoints, format auto-selection&lt;/li&gt;
&lt;li&gt;Deploy a production-ready app you can link from your resume&lt;/li&gt;
&lt;/ul&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%2F4891ntoh6m30xoqdmsvh.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%2F4891ntoh6m30xoqdmsvh.png" alt="portfolio" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Who's this for?
&lt;/h2&gt;

&lt;p&gt;The C2C curriculum works for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Early-career developers who want structured, project-based learning beyond "hello world" tutorials&lt;/li&gt;
&lt;li&gt;Career changers building a portfolio they can point to during job interviews&lt;/li&gt;
&lt;li&gt;Frontend developers who've used Cloudinary but want to understand the optimization and AI layers&lt;/li&gt;
&lt;li&gt;Backend developers looking to add media handling to their Python projects&lt;/li&gt;
&lt;li&gt;Bootcamp graduates who want to go from tutorial-follower to someone who can build production media pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Enroll for Free
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to training.cloudinary.com/pages/c2c&lt;/li&gt;
&lt;li&gt;Create a free Cloudinary Academy account — you just need an email address&lt;/li&gt;
&lt;li&gt;Start with Course 1 or jump to the course that matches your current skill level&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All 6 courses are free. Each comes with a completion certificate. Finishing any course and passing its final assessment at 80%+ earns you a credential that qualifies you to apply to the Cloudinary Creators Community, a network with mentorship, Discord access, mini-hack events, and connections to developers worldwide.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Cloudinary Creators Community
&lt;/h2&gt;

&lt;p&gt;The Cloudinary Creators Community (CCC) is a selective, cohort-based program for developers who've completed the C2C curriculum. &lt;/p&gt;

&lt;p&gt;It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access to private Discord channels with Cloudinary's Developer Relations team&lt;/li&gt;
&lt;li&gt;Monthly mini-hack challenges to apply and extend your skills&lt;/li&gt;
&lt;li&gt;Peer review and mentorship from a global network of developers&lt;/li&gt;
&lt;li&gt;Badges, certificates, and holopins with social media shout-outs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can join the Discord server now and participate in community activities even while you're working through the curriculum.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ready to start? → &lt;a href="//training.cloudinary.com/pages/c2c"&gt;training.cloudinary.com/pages/c2c&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This blogpost was crafted with the help of Claude. Banner image by Nano Banana.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Cloudinary ❤️ developers&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ready to level up your media workflow? Start using Cloudinary for free and build better visual experiences today.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👉 &lt;strong&gt;&lt;a href="https://link.cloudinary.com/un3am" rel="noopener noreferrer"&gt;Create your free account&lt;/a&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Surviving as a Human in the Age of AI</title>
      <dc:creator>Jen Looper</dc:creator>
      <pubDate>Tue, 31 Mar 2026 02:43:37 +0000</pubDate>
      <link>https://dev.to/jenlooper/surviving-as-a-human-in-the-age-of-ai-1p1b</link>
      <guid>https://dev.to/jenlooper/surviving-as-a-human-in-the-age-of-ai-1p1b</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/wecoded-2026"&gt;2026 WeCoded Challenge&lt;/a&gt;: Echoes of Experience&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There's a palpable feeling of anxiety in developer communities right now as concrete programming skills that we have painstakingly built either through study or experience appear to now be ... kaput. Outdated. Irrelevant. Passé. &lt;/p&gt;

&lt;p&gt;Andrej Karpathy described the feeling of watching his manual coding ability "slowly degenerating," as a personal sense of loss as AI tools take over coding work: "I've already noticed that I am slowly starting to atrophy my ability to write code manually".&lt;a href="https://x.com/karpathy/status/2015883857489522876?s=43" rel="noopener noreferrer"&gt;source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxz6l00imz99dsqmmmxfn.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%2Fxz6l00imz99dsqmmmxfn.png" alt="Karpathy freaking out about coding on X" width="800" height="665"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ex-Google CEO Eric Schmitt expresses shock at watching AI zip through programming tasks that he used to have to hand-code: "I've been doing programming for 55 years. To see something something start and end in front of your own life is really profound." &lt;a href="http://timesofindia.indiatimes.com/articleshow/126304028.cms" rel="noopener noreferrer"&gt;source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Developers of all stripes are coming to the realization that being "just a coder" is no longer enough; new skills of systems thinking and architecture, plus that vague concept of 'taste' are starting to factor heavily in success in this industry. Students, as usual, are quickest to come to this realization, and Computer Science programs are rapidly either evolving or depopulating. Students are also feeling the brunt of this rapid change as narratives they were told as freshmen no longer hold true by the time they reach their senior year.&lt;/p&gt;

&lt;p&gt;It's a tough time to [just] 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.amazonaws.com%2Fuploads%2Farticles%2Fpo91j4ncgu47ujuuco8m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpo91j4ncgu47ujuuco8m.gif" alt="Kristen Bell laughing and crying" width="160" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Laughs in Humanities PhD. &lt;/p&gt;

&lt;p&gt;Plus ça change, plus c'est la même chose [The more things change, the more they remain the same]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A tale of two pathways
&lt;/h2&gt;

&lt;p&gt;Let me tell you a little story. It's the tale of someone who followed her heart her entire career.&lt;/p&gt;

&lt;p&gt;When I was 16, I went to France, and was swept away while visiting Chartres cathedral. True story. Growing up in a pretty privileged environment, with parents encouraging me to follow my dream, I studied for 6 years post-bachelors degree before achieving my PhD in French literature from Cal Berkeley in 1998. &lt;/p&gt;

&lt;p&gt;Even during my tenure in graduate school in the 90s, it was clear that Silicon Valley was the hub of some really exciting stuff and that a seismic shift was occurring in the dot-com-boom. But we in our ivory tower looked slightly askance at the fellow in Scandinavian Studies who ditched his PhD program to join a hot startup way back then. We were that confident that our skills would be valued. Anyway Scandinavian Studies is far less relevant than French Studies, everybody knows that.&lt;/p&gt;

&lt;p&gt;We of course didn't realize that humanities PhD programs in the languages are primarily designed to ensure a stream of cost-effective [read: crazy cheap] TAs (GSIs - graduate student instructors, as we called ourselves after unionizing). We were on the front lines of language learning, teaching a section of French 1 or 2 every day, coupled with mandatory pedagogy training, so that Cal undergrads could get through their language requirement. With the hope that we'd be able to graduate and land a tenure-track position, we put up with a lot, relying on this scanty income to keep food on the table and rent checks covered for a room in a West Berkeley two-storey.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here is some lore: that house on Roosevelt Ave had a can of peaches that had to have been a decade old, a gift from every successive wave of grad students who rented the house. I wonder if it's still there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most of us were unwilling to understand that the academic job market was weak and getting weaker by the year, although there were signs. &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%2Fijk63im6ql9gx4h13s8e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijk63im6ql9gx4h13s8e.jpg" alt="monk and dragon" width="408" height="235"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We &lt;em&gt;really&lt;/em&gt; didn't want to hear the gospel&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One wake-up call to me was watching a colleague and her husband, after graduating, accept &lt;em&gt;one&lt;/em&gt; teaching job between them. Another was watching another colleague getting thinner and thinner as he was quite literally going hungry to cover his family's expenses while part-time teaching.&lt;/p&gt;

&lt;p&gt;Unsurprisingly, given our blinders, the bottom falling out from what was left of the job market, and the other considerable headwinds (I see you, Adjuncting!), the academic job market kicked my rear. Within a few years I threw in the towel and retrained as a web developer, catching that dot-com-boom at its tail end, restarting from scratch. In those days, you could take courses in web design online from Macromedia University, an early training program, and find an entry-level job in a completely new industry.&lt;/p&gt;

&lt;p&gt;I worked my way up the corporate ladder (stories for another day) over the subsequent 25 years, but I won't say that I haven't yearned every day for what I gave up. Mourning the loss of a dream. Wondering "what might have been". Reconsidering the choice to pivot every time I hit a career bump, and being tempted to try to go back to some form of teaching. Coping with accusations of having sold out.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ubi Sunt
&lt;/h2&gt;

&lt;p&gt;This long preamble is meant to emphasize that where you come from will most likely have very little relationship to where you are going in your career in the long run, especially in this fast-moving age of dramatic technical change - much faster and probably even more disruptive than the dot-com-boom of the early 2000s.&lt;/p&gt;

&lt;p&gt;The current anxiety and nostalgia permeating the tech discourse boils down to this tweet:&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%2Fvdhtngrl4nsuxsny29cy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvdhtngrl4nsuxsny29cy.jpg" alt="useless" width="800" height="955"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One benefit of having a background in a field other than where you wind up working is that you can lean on your previous knowledge base to bring insights to your work. Because really, there is nothing new here. The sentiment of loss and nostalgic mourning is explored over and over again in literature - the motif even has a name, 'Ubi sunt'. The 10th century poem The Wanderer expresses this trope with exquisite sadness:&lt;/p&gt;

&lt;p&gt;"Where is the horse gone? Where the rider? Where the giver of treasure?&lt;br&gt;
Where are the seats at the feast? Where are the revels in the hall?&lt;br&gt;
[...] How that time has passed away,&lt;br&gt;
grown dark under cover of night, as if it had never been."&lt;/p&gt;

&lt;p&gt;In a world grown old and dark, where is the greatness of our past? And was the past great at all, if it can disappear without a trace, as if it had never existed? &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%2Fm8funcc6yxjvnosj6i11.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm8funcc6yxjvnosj6i11.jpg" alt="The Wanderer manuscript, from the Exeter Book" width="492" height="765"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The 10th century manuscript containing The Wanderer, the &lt;a href="https://en.wikipedia.org/wiki/The_Wanderer_(Old_English_poem)" rel="noopener noreferrer"&gt;Exeter Book&lt;/a&gt;. The word "Eardsteppan" translates to "Wanderer", in the usual Old English "kenning" where two words are put together to refer to one thing. In this case the "earth stepper" is the wanderer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the 15th century in Middle French, François Villon borrows the Ubi Sunt trope to mourn the great ladies of the past, comparing them to those of the present day:&lt;/p&gt;

&lt;p&gt;"Where is the very wise Héloïse,&lt;br&gt;
For whom was castrated, and then made a monk,&lt;br&gt;
Peter Abelard in Saint-Denis?&lt;br&gt;
For his love he suffered this sentence.&lt;br&gt;
Similarly, where is the Queen&lt;br&gt;
Who ordered that Buridan&lt;br&gt;
Be thrown in a sack into the Seine?&lt;br&gt;
Oh, where are the snows of yesteryear!"&lt;/p&gt;

&lt;p&gt;Villon was a slippery character who had several run-ins with the law, and he seems to be not so much mourning the past as reminding us that returning to it might get you chucked into the Seine. &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%2Fhuhtma7pu3x4utwpo42v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhuhtma7pu3x4utwpo42v.jpg" alt="print edition of Villon's Testament" width="800" height="1257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Student, poet, housebreaker" - an early print manuscript of Villon's works from 1489, in &lt;a href="https://data.bnf.fr/ark:/12148/cb119284140" rel="noopener noreferrer"&gt;Paris BNF&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Still, if 10th century Anglo Saxon poets dwelling in a much more uncomfortable world felt a profound sense of regret for a (probably) even more uncomfortable past, we in our ergonometric chairs battling Cursor also have the right to feel a degree of loss, a "slow degeneration" à la Karpathy. We can perhaps express ourselves using a literary trope that's over 1000 years old. But &lt;strong&gt;we ought to be able to put this anxiety into perspective&lt;/strong&gt;, as Villon insinuates that we should. This brings me to my second point.&lt;/p&gt;

&lt;h2&gt;
  
  
  All The Feels
&lt;/h2&gt;

&lt;p&gt;We have the right to feel all the feels that AI is making us feel - sad, useless, confused, stressed at its speed-of-light implementations, upset at the instability in the job market as we are threatened with AI-powered [sic] wave after wave of layoffs, worried for the next generation of early-career folks clawing their way up through the ranks in a very different world.&lt;/p&gt;

&lt;p&gt;But I would posit that &lt;strong&gt;we, the dispossessed diaspora of ex-Humanities academics, have something to contribute here&lt;/strong&gt;. We, too, trained for years only to be met with a job market that resolutely turned its back on us. And there isn't a day that I don't mourn that this happened, as I mentioned above. &lt;strong&gt;But I found ways to cope, and that has been to bring the skills of my own lived and learned experience to bear on an ever-evolving professional landscape&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One coping mechanism for me has been to attempt to bridge these two worlds by bringing the humanities into tech, because the lessons I learned there apply universally - such as those lessons around close reading, translating syntax, and &lt;strong&gt;the power of interdisciplinarity&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Interdisciplinarian
&lt;/h2&gt;

&lt;p&gt;Consider your past experience as a way to inform your present situation. In the near future, tech is going to look very different from how it does now. The job of the programmer will lean into more architecture than hand-coding. But your hard-won skills will still resonate in your day to day activities; rather than becoming obsolete, your programming skills will simply be applied in a different context. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You will have to lean into your accumulation of knowledge. Know that parts of it will apply, be ready to learn anew, and accept that the only thing that never changes is the fact that things will change.&lt;/strong&gt; Well, and also death. And probably taxes.&lt;/p&gt;

&lt;p&gt;As Emily Dickinson (whose poetry is well-studied &lt;a href="https://python.plainenglish.io/emily-dickinson-and-the-meter-of-mood-an-experiment-in-text-analysis-ff0f6efae290" rel="noopener noreferrer"&gt;from a data science context&lt;/a&gt;) well knew:&lt;/p&gt;

&lt;p&gt;All but Death can be&lt;br&gt;
Adjusted ;&lt;br&gt;
Dynasties repaired,&lt;br&gt;
Systems settled in their&lt;br&gt;
Sockets,&lt;br&gt;
Centuries removed, —&lt;/p&gt;

&lt;p&gt;Wastes of lives resown&lt;br&gt;
With colors&lt;br&gt;
By superior springs,&lt;br&gt;
Death — unto itself exception —&lt;br&gt;
Is exempt from change.&lt;/p&gt;

&lt;p&gt;-- &lt;a href="https://poets.org/poem/all-death-can-be-89" rel="noopener noreferrer"&gt;89&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To put a corporate stamp on it, the old exhortation to bring your whole self to work applies, now more than ever. The workplace has need of all of us with all of our interesting, strange, diverse, warty, emotional, and overwhelmingly human perspectives as our professions will be shaped increasingly by the collective that is AI. Embrace your interdisciplinarity, lean into it. I wish you great success. And please take care of yourself and each other.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>career</category>
      <category>wecoded</category>
    </item>
    <item>
      <title>Improve Web Performance: Image Formats, Responsive Images, and Core Web Vitals</title>
      <dc:creator>Jen Looper</dc:creator>
      <pubDate>Wed, 11 Mar 2026 18:43:45 +0000</pubDate>
      <link>https://dev.to/cloudinary/your-images-are-probably-slowing-down-your-website-heres-how-to-fix-it-23je</link>
      <guid>https://dev.to/cloudinary/your-images-are-probably-slowing-down-your-website-heres-how-to-fix-it-23je</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Because images typically account for the majority of total page weight, this technical guide provides actionable strategies for web performance optimization. It details modern image formats like WebP and AVIF, implements responsive delivery via &lt;code&gt;srcset&lt;/code&gt;, establishes lazy loading best practices, and explains the impact of media on Core Web Vitals (LCP, CLS, and INP) for production-level development.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What you’ll get
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;mental model&lt;/strong&gt;: how &lt;strong&gt;bytes&lt;/strong&gt; (file size) relate to what you &lt;em&gt;see&lt;/em&gt; (pixels on screen) and to &lt;strong&gt;LCP&lt;/strong&gt; / &lt;strong&gt;CLS&lt;/strong&gt; / &lt;strong&gt;INP&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;format cheat sheet&lt;/strong&gt; (photos, UI, icons, fallbacks) and when &lt;strong&gt;lossy&lt;/strong&gt; vs &lt;strong&gt;lossless&lt;/strong&gt; makes sense.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When to lazy-load&lt;/strong&gt; (and when &lt;strong&gt;not&lt;/strong&gt; to—so you don’t hurt LCP).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three fixes to try first&lt;/strong&gt; on a real page (largest image, format mix, mobile percentiles).
&lt;/li&gt;
&lt;li&gt;How to use &lt;strong&gt;Cloudinary’s Web Speed Test&lt;/strong&gt; to turn gut feel into numbers.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Cloudinary ❤️ developers&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ready to level up your media workflow? Start using Cloudinary for free and build better visual experiences today.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👉 &lt;strong&gt;&lt;a href="https://link.cloudinary.com/umq4j" rel="noopener noreferrer"&gt;Create your free account&lt;/a&gt;&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The hidden performance problem on most websites
&lt;/h2&gt;

&lt;p&gt;This article explains how &lt;strong&gt;image bytes&lt;/strong&gt; affect &lt;strong&gt;LCP&lt;/strong&gt;, &lt;strong&gt;CLS&lt;/strong&gt;, and &lt;strong&gt;INP&lt;/strong&gt;, and what to change first.&lt;/p&gt;

&lt;p&gt;Open Chrome DevTools on almost any modern site and check the &lt;strong&gt;Network tab&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What you’ll usually see is something surprising:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Images dominate the payload.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The average homepage ships &lt;strong&gt;around 1 MB of images&lt;/strong&gt;, often &lt;strong&gt;more than JavaScript, CSS, and HTML combined&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%2Fmedia.thoughtindustries.com%2Fcourse-uploads%2F4338ce4e-f809-4f5a-80f4-1d317c4a390d%2Fj0bb7waszgtt-Screenshot2025-11-25at12.31.09PM.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%2Fmedia.thoughtindustries.com%2Fcourse-uploads%2F4338ce4e-f809-4f5a-80f4-1d317c4a390d%2Fj0bb7waszgtt-Screenshot2025-11-25at12.31.09PM.png" alt="watches in a web site" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A super heavy page with a lot of big product images. Lazy loading and optimization would help here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That product page with 20 images?&lt;br&gt;
Each one is an opportunity to either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deliver a fast, polished experience&lt;/li&gt;
&lt;li&gt;Or frustrate users with slow loading and layout shifts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you care about &lt;strong&gt;Core Web Vitals, SEO, and user experience&lt;/strong&gt;, image optimization is one of the &lt;strong&gt;highest-impact improvements you can make&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article was generated from our &lt;a href="https://link.cloudinary.com/umq4g" rel="noopener noreferrer"&gt;Cloud to Crowd: Media IQ with Next.js&lt;/a&gt; curriculum, built by Cloudinary Developer Relations. Go through this curriculum and pass the certification exam to qualify to become an official &lt;a href="https://link.cloudinary.com/umq4h" rel="noopener noreferrer"&gt;Cloudinary Creator&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Why images matter (and when they don’t)
&lt;/h2&gt;

&lt;p&gt;Humans process images much faster than text.&lt;/p&gt;

&lt;p&gt;A well-chosen image can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explain a product instantly&lt;/li&gt;
&lt;li&gt;Replace paragraphs of documentation&lt;/li&gt;
&lt;li&gt;Capture attention in fast-scrolling feeds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But images can also &lt;strong&gt;hurt your product experience&lt;/strong&gt; when used poorly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Too many images slow down page loads&lt;/li&gt;
&lt;li&gt;Poor cropping hides important information&lt;/li&gt;
&lt;li&gt;Large files damage &lt;strong&gt;Core Web Vitals&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Undisclosed AI or edited images reduce user trust&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you need to follow this simple rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Right format + right size + smart delivery&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F41mtd49vkcucf25n7lid.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%2F41mtd49vkcucf25n7lid.png" alt="Images in a correct format" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check out the way these images are delivered to the browser&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Images and Core Web Vitals
&lt;/h2&gt;

&lt;p&gt;Images heavily influence Google's &lt;strong&gt;Core Web Vitals&lt;/strong&gt;, particularly:&lt;/p&gt;
&lt;h3&gt;
  
  
  Largest Contentful Paint (LCP)
&lt;/h3&gt;

&lt;p&gt;Measures how long it takes for the &lt;strong&gt;largest visible element&lt;/strong&gt; on the page to load.&lt;/p&gt;

&lt;p&gt;This is often your &lt;strong&gt;hero image&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A good LCP target is under 2.5 seconds.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cumulative Layout Shift (CLS)
&lt;/h3&gt;

&lt;p&gt;Images without defined dimensions can cause layout shifts while loading.&lt;/p&gt;
&lt;h3&gt;
  
  
  Interaction to Next Paint (INP)
&lt;/h3&gt;

&lt;p&gt;Heavy pages delay responsiveness.&lt;/p&gt;

&lt;p&gt;Optimizing images can dramatically improve &lt;strong&gt;all three metrics&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  The current state of images on the web
&lt;/h2&gt;

&lt;p&gt;Nearly &lt;strong&gt;every webpage (99.9%) loads at least one image&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Average number of images per page:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Device&lt;/th&gt;
&lt;th&gt;Avg Images&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Desktop&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Common formats used across the web:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Usage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JPEG&lt;/td&gt;
&lt;td&gt;32.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PNG&lt;/td&gt;
&lt;td&gt;28.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GIF&lt;/td&gt;
&lt;td&gt;16.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebP&lt;/td&gt;
&lt;td&gt;12%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SVG&lt;/td&gt;
&lt;td&gt;6.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AVIF&lt;/td&gt;
&lt;td&gt;1%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;But these numbers reflect &lt;strong&gt;habit, not best practices&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Performance-focused teams are already shifting toward modern formats.&lt;/p&gt;

&lt;p&gt;Example data from optimized platforms shows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Usage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;WebP&lt;/td&gt;
&lt;td&gt;49.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JPEG&lt;/td&gt;
&lt;td&gt;19.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AVIF&lt;/td&gt;
&lt;td&gt;13.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HEIC / PNG&lt;/td&gt;
&lt;td&gt;8.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The takeaway:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modern image formats are replacing JPEG-first strategies.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Choosing the right image format
&lt;/h2&gt;

&lt;p&gt;Different formats solve different problems.&lt;/p&gt;
&lt;h3&gt;
  
  
  Lossy compression
&lt;/h3&gt;

&lt;p&gt;Reduces file size by permanently discarding some data.&lt;/p&gt;

&lt;p&gt;Formats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JPEG&lt;/li&gt;
&lt;li&gt;WebP&lt;/li&gt;
&lt;li&gt;AVIF&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Much smaller file sizes&lt;/li&gt;
&lt;li&gt;Ideal for photos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slight quality loss&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  Lossless compression
&lt;/h3&gt;

&lt;p&gt;Reduces size &lt;strong&gt;without losing data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Formats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PNG&lt;/li&gt;
&lt;li&gt;SVG&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Perfect image quality&lt;/li&gt;
&lt;li&gt;Ideal for UI graphics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Larger file sizes&lt;/li&gt;
&lt;/ul&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%2F7tu5adjaeuss92qfydpv.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%2F7tu5adjaeuss92qfydpv.png" alt="quality varying in images" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check out the difference between a lower res image vs JPEG XL&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  Quick developer cheat sheet
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use case&lt;/th&gt;
&lt;th&gt;Best format&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Photos&lt;/td&gt;
&lt;td&gt;WebP / AVIF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graphics&lt;/td&gt;
&lt;td&gt;PNG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Icons&lt;/td&gt;
&lt;td&gt;SVG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legacy fallback&lt;/td&gt;
&lt;td&gt;JPEG&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Modern formats like &lt;strong&gt;WebP and AVIF can reduce file size by 40–60% compared to JPEG&lt;/strong&gt; while keeping similar visual quality.&lt;/p&gt;


&lt;h2&gt;
  
  
  Delivering images efficiently
&lt;/h2&gt;

&lt;p&gt;Choosing the right format is only part of the story.&lt;br&gt;
Delivery strategy matters just as much.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloudinary&lt;/strong&gt; can automate &lt;strong&gt;format and size&lt;/strong&gt; selection for delivery so you’re not hand-tuning every URL. It helps you &lt;strong&gt;optimize, transform, and deliver&lt;/strong&gt; images for your users. See how on the &lt;a href="https://link.cloudinary.com/umq4i" rel="noopener noreferrer"&gt;Developers Hub&lt;/a&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  1. Use responsive images
&lt;/h3&gt;

&lt;p&gt;Don't force mobile users to download desktop-sized images.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"hero.avif"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/avif"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"hero.webp"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/webp"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"hero.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Product hero image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser automatically chooses the &lt;strong&gt;best supported format and size&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Use a CDN
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Content Delivery Network (CDN)&lt;/strong&gt; reduces the physical distance between your users and your images.&lt;/p&gt;

&lt;p&gt;Modern image CDNs can also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resize images automatically&lt;/li&gt;
&lt;li&gt;Convert formats (WebP / AVIF)&lt;/li&gt;
&lt;li&gt;Adjust compression&lt;/li&gt;
&lt;li&gt;Crop dynamically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows you to store &lt;strong&gt;one high-quality original&lt;/strong&gt; while serving optimized versions.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Lazy-load images (strategically)
&lt;/h3&gt;

&lt;p&gt;Lazy loading delays images until they approach the viewport.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"gallery.jpg"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Gallery image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there is one important rule:&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Never lazy-load above-the-fold images.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Doing so hurts &lt;strong&gt;Largest Contentful Paint&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Lazy loading should only be used for &lt;strong&gt;below-the-fold content&lt;/strong&gt;. Do not lazy-load the &lt;strong&gt;hero&lt;/strong&gt; or other &lt;strong&gt;above-the-fold&lt;/strong&gt; &lt;strong&gt;LCP&lt;/strong&gt; candidates.&lt;/p&gt;




&lt;h2&gt;
  
  
  Responsible image usage
&lt;/h2&gt;

&lt;p&gt;Performance isn't the only consideration.&lt;/p&gt;

&lt;p&gt;Developers should also use images &lt;strong&gt;ethically and accessibly&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Avoid misleading visuals
&lt;/h3&gt;

&lt;p&gt;Don't use edited or cropped images that misrepresent a product.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Disclose AI-generated images
&lt;/h3&gt;

&lt;p&gt;Transparency builds trust with users.&lt;br&gt;
The banner at the top of this article was generated using Nano Banana.&lt;/p&gt;


&lt;h3&gt;
  
  
  3. Make images accessible
&lt;/h3&gt;

&lt;p&gt;Always include descriptive alt text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"dashboard.png"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Analytics dashboard showing user growth trends"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. Respect privacy and licensing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Check image licenses&lt;/li&gt;
&lt;li&gt;Get consent when photographing people&lt;/li&gt;
&lt;li&gt;Remove sensitive EXIF metadata&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  5. Balance aesthetics and performance
&lt;/h3&gt;

&lt;p&gt;A beautiful image that takes &lt;strong&gt;8 seconds to load&lt;/strong&gt; isn't beautiful.&lt;/p&gt;

&lt;p&gt;It's broken.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common image optimization myths
&lt;/h2&gt;

&lt;h3&gt;
  
  
  “A CDN replaces responsive images”
&lt;/h3&gt;

&lt;p&gt;False.&lt;/p&gt;

&lt;p&gt;Responsive images help the &lt;strong&gt;browser choose the correct size&lt;/strong&gt;, while CDNs deliver optimized assets.&lt;/p&gt;

&lt;p&gt;You need &lt;strong&gt;both&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  “More images mean more engagement”
&lt;/h3&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;Images should &lt;strong&gt;help users make decisions&lt;/strong&gt;, not clutter the interface.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three practical tips for developers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Start with your largest image
&lt;/h3&gt;

&lt;p&gt;Open &lt;strong&gt;DevTools → Network&lt;/strong&gt; and find the biggest image.&lt;/p&gt;

&lt;p&gt;Check if delivered size == display size.&lt;/p&gt;

&lt;p&gt;A common mistake: 3000px image displayed in a 600px container.&lt;/p&gt;

&lt;p&gt;That’s wasted bandwidth.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Measure your format mix
&lt;/h3&gt;

&lt;p&gt;Check what formats your pipeline actually delivers.&lt;/p&gt;

&lt;p&gt;If you're still mostly serving JPEG, there's likely a &lt;strong&gt;huge optimization opportunity&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Don’t assume mobile is optimized
&lt;/h3&gt;

&lt;p&gt;Mobile networks amplify performance problems.&lt;/p&gt;

&lt;p&gt;Check your &lt;strong&gt;75th and 90th percentile metrics&lt;/strong&gt;, not just averages.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try this: Analyze a website’s image performance
&lt;/h2&gt;

&lt;p&gt;You can test any website using &lt;strong&gt;Cloudinary’s Web Speed Test&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="https://webspeedtest.cloudinary.com" rel="noopener noreferrer"&gt;https://webspeedtest.cloudinary.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then analyze:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance score&lt;/li&gt;
&lt;li&gt;Total image weight&lt;/li&gt;
&lt;li&gt;Largest Contentful Paint&lt;/li&gt;
&lt;li&gt;Potential size reductions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll often discover &lt;strong&gt;massive performance gains from simple fixes&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Images are often the &lt;strong&gt;largest performance lever on a webpage&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you remember only three things:&lt;/p&gt;

&lt;p&gt;1️⃣ Optimize your &lt;strong&gt;largest image first&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
2️⃣ Use &lt;strong&gt;modern formats like WebP and AVIF&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
3️⃣ Deliver &lt;strong&gt;responsive images with proper sizing&lt;/strong&gt; and explicit dimensions when you can (helps &lt;strong&gt;CLS&lt;/strong&gt;)&lt;/p&gt;

&lt;p&gt;Small improvements in image delivery can produce &lt;strong&gt;huge gains in performance and user experience&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What’s the biggest image optimization issue you’ve found on a website?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>frontend</category>
      <category>codenewbie</category>
    </item>
  </channel>
</rss>
