<?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: lumm</title>
    <description>The latest articles on DEV Community by lumm (@lumm_7b4812001a80f4b531cf).</description>
    <link>https://dev.to/lumm_7b4812001a80f4b531cf</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%2F3385512%2Fb8d7f1b7-7cd4-4474-8c67-7fd9256ac452.png</url>
      <title>DEV Community: lumm</title>
      <link>https://dev.to/lumm_7b4812001a80f4b531cf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lumm_7b4812001a80f4b531cf"/>
    <language>en</language>
    <item>
      <title>How I got an AI video model to change outfits exactly on the fan blade</title>
      <dc:creator>lumm</dc:creator>
      <pubDate>Wed, 28 Oct 2026 02:21:52 +0000</pubDate>
      <link>https://dev.to/lumm_7b4812001a80f4b531cf/how-i-got-an-ai-video-model-to-change-outfits-exactly-on-the-fan-blade-3592</link>
      <guid>https://dev.to/lumm_7b4812001a80f4b531cf/how-i-got-an-ai-video-model-to-change-outfits-exactly-on-the-fan-blade-3592</guid>
      <description>&lt;p&gt;There is a TikTok trend where the camera looks straight down at someone lying on a carpet, a ceiling fan turns above them, and every time a blade sweeps across the lens their outfit changes. I built it as an effect on &lt;a href="https://blinkpop.video/?utm_source=devto&amp;amp;utm_medium=promo" rel="noopener noreferrer"&gt;BlinkPop&lt;/a&gt;, a site that turns one photo into the AI video trend of the week. It looked simple. It took three rounds to get right, and the fix was not a better prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pipeline
&lt;/h2&gt;

&lt;p&gt;Every effect on the site follows the same shape:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Compose.&lt;/strong&gt; An image model places the user's photo into the scene: the overhead shot, the carpet, the sofa, the person in outfit one. For the fan effect the user uploads one photo per outfit, so we make one still per outfit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Animate.&lt;/strong&gt; A video model (Seedance 2.0 Mini) turns the stills into a short vertical clip.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The site runs on Cloudflare Workers with D1 and R2. Jobs have two or three steps, and each step's callback starts the next one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 1: describe the timing in the prompt
&lt;/h2&gt;

&lt;p&gt;The first version gave the video model the stills and a prompt like &lt;em&gt;"a ceiling fan turns slowly; each time a blade passes the lens, the outfit changes to the next one."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With three outfits, the blade swept past four or five times and the outfit changed on passes one and four. Passes two and three did nothing. The model understood "fan" and "outfit change" but had no idea those two things were supposed to happen at the same moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 2: be more precise
&lt;/h2&gt;

&lt;p&gt;I tried a slower fan, written-out pass times ("a blade passes at 2.5s and 6s"), and fewer words. Six runs, same problem. Sometimes the fan even changed direction halfway through. Text alone could not pin the rhythm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 3: show it the rhythm
&lt;/h2&gt;

&lt;p&gt;Seedance 2.0 Mini has a reference mode: besides reference images, you can pass a reference video, and it copies camera, motion and timing from it.&lt;/p&gt;

&lt;p&gt;So I made &lt;strong&gt;rhythm clips&lt;/strong&gt;: short cuts of one of our own earlier renders where the fan timing came out right.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2 outfits: a 6-second clip with one blade pass at 2.5s&lt;/li&gt;
&lt;li&gt;3 outfits: a 9-second clip with passes at 2.5s and 6s&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The request now sends the outfit stills as &lt;code&gt;reference_image_urls&lt;/code&gt; and the matching clip as &lt;code&gt;reference_video_urls&lt;/code&gt;. The prompt says to copy the camera, the fan and the timing from the video, take the room, the person and the outfits from the images, and treat the woman in the clip as a stand-in.&lt;/p&gt;

&lt;p&gt;Results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2 and 3 outfits: &lt;strong&gt;8 out of 8&lt;/strong&gt; correct (man, woman and a dog)&lt;/li&gt;
&lt;li&gt;The user's face was not pulled toward the stand-in in the clip&lt;/li&gt;
&lt;li&gt;The fan kept one direction in all 13 reference-mode runs&lt;/li&gt;
&lt;li&gt;4 outfits: only 2 out of 4 correct, so the effect stops at three&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reference mode also bills the reference video's seconds plus the output seconds, which works out to about $0.14 to $0.21 per video. That's roughly what the prompt-only version cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I took from it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Timing is a motion problem, not a language problem.&lt;/strong&gt; If the result depends on two events happening at the same moment, show the model a video where they do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use your own footage as the reference.&lt;/strong&gt; The rhythm clips are cut from our own render, not from the original TikTok.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cap the feature where it stops being reliable.&lt;/strong&gt; Three outfits that always work beat four that work half the time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few smaller lessons from the other effects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When composing two people into one scene, put the user photos first and the scene image last, and say "image 1 stands on the left, image 2 on the right". Otherwise left and right swap often.&lt;/li&gt;
&lt;li&gt;Check the photo before charging (is there a person or pet, is it too dark or blurry). If the check service is down, let the job through rather than block paying users.&lt;/li&gt;
&lt;li&gt;Refund credits automatically on any failed step.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can try the fan effect and the others at &lt;a href="https://blinkpop.video/?utm_source=devto&amp;amp;utm_medium=promo" rel="noopener noreferrer"&gt;blinkpop.video&lt;/a&gt;. New accounts get enough free credits for one video. I'd love to hear how others handle timing in AI video pipelines.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>7 cron expression gotchas that will silently break your scheduled jobs</title>
      <dc:creator>lumm</dc:creator>
      <pubDate>Thu, 21 May 2026 03:40:21 +0000</pubDate>
      <link>https://dev.to/lumm_7b4812001a80f4b531cf/7-cron-expression-gotchas-that-will-silently-break-your-scheduled-jobs-5f6a</link>
      <guid>https://dev.to/lumm_7b4812001a80f4b531cf/7-cron-expression-gotchas-that-will-silently-break-your-scheduled-jobs-5f6a</guid>
      <description>&lt;p&gt;I've been working with cron expressions across different platforms for a while now, and I keep running into the same traps — some of them cost me hours of debugging, one of them cost me a full day of missed backups.&lt;/p&gt;

&lt;p&gt;Here are 7 gotchas I've collected, with fixes for each.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. "Every 6 hours" vs "every minute of hour 6"
&lt;/h2&gt;

&lt;p&gt;This is the classic. You write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 6 * * *
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thinking it means "every 6 hours." It doesn't. It means "at 06:00 every day." What you actually want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 */6 * * *
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;*/6&lt;/code&gt; in the hour field means "every 6th hour." Without the slash, you're just picking hour 6.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. GitHub Actions is UTC-only and lies about timing
&lt;/h2&gt;

&lt;p&gt;Your workflow says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;9&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1-5'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You think it runs at 9am your time. It runs at 9am UTC. If you're in US Eastern, that's 5am. If you're in Beijing, that's 5pm.&lt;/p&gt;

&lt;p&gt;Worse: GitHub Actions can delay scheduled runs by 5-30 minutes under heavy load. A job scheduled for 9:00 UTC might actually fire at 9:22. This matters if you have downstream dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;code&gt;*/5&lt;/code&gt; doesn't work on AWS EventBridge
&lt;/h2&gt;

&lt;p&gt;You write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cron(*/5 * * * ? *)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;EventBridge rejects it. AWS uses &lt;code&gt;0/5&lt;/code&gt; instead of &lt;code&gt;*/5&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cron(0/5 * * * ? *)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No error message tells you this clearly. You just get a generic validation failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Day-of-month + day-of-week: OR vs AND
&lt;/h2&gt;

&lt;p&gt;This one is genuinely confusing. The expression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 8 15 * 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On &lt;strong&gt;Linux cron&lt;/strong&gt;: fires on the 15th of every month &lt;strong&gt;OR&lt;/strong&gt; every Monday. (OR semantics)&lt;/p&gt;

&lt;p&gt;On &lt;strong&gt;AWS EventBridge / Quartz&lt;/strong&gt;: you can't even set both — one field must be &lt;code&gt;?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want "the first Monday of every month" on Linux, you need a shell guard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;0 8 1-7 &lt;span class="k"&gt;*&lt;/span&gt; 1 &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="se"&gt;\%&lt;/span&gt;u&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 1 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; /your/command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Vercel Hobby plan: 1 cron job per day
&lt;/h2&gt;

&lt;p&gt;You deploy a Vercel cron that runs every hour:&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;"crons"&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;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/api/cleanup"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"schedule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0 * * * *"&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;On the Hobby plan, this silently gets throttled to once per day. No warning in the build output. You find out when your cleanup hasn't run for 23 hours.&lt;/p&gt;

&lt;p&gt;Pro plan minimum interval is 1 minute. Hobby is 1 per day. Period.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Kubernetes timeZone field needs v1.27+
&lt;/h2&gt;

&lt;p&gt;You add this to your CronJob spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;timeZone&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;America/New_York"&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;9&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On clusters older than 1.27, the &lt;code&gt;timeZone&lt;/code&gt; field is silently ignored. Your job runs in UTC. No error, no warning.&lt;/p&gt;

&lt;p&gt;Always check your cluster version before relying on this field.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Quartz uses different weekday numbers
&lt;/h2&gt;

&lt;p&gt;Linux cron: &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;7&lt;/code&gt; = Sunday, &lt;code&gt;1&lt;/code&gt; = Monday&lt;/p&gt;

&lt;p&gt;Quartz: &lt;code&gt;1&lt;/code&gt; = Sunday, &lt;code&gt;2&lt;/code&gt; = Monday&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;0 8 ? * 2&lt;/code&gt; means Monday on Quartz but Tuesday on Linux. Copy-paste between platforms and you've shifted your entire schedule by a day.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I built a tool for this
&lt;/h2&gt;

&lt;p&gt;After hitting most of these myself, I built &lt;a href="https://cronwiz.dev" rel="noopener noreferrer"&gt;cronwiz.dev&lt;/a&gt; — type a schedule in plain English, get the cron expression for 7 platforms (Linux, AWS, K8s, GitHub Actions, Vercel, Quartz, Cloudflare Workers) with platform-specific warnings baked in.&lt;/p&gt;

&lt;p&gt;It also works in reverse: paste a cron expression and get a human-readable explanation. Useful when you're debugging someone else's crontab at 3am.&lt;/p&gt;

&lt;p&gt;Free, no signup. The &lt;a href="https://github.com/lumm256/cronwiz" rel="noopener noreferrer"&gt;source is on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm also building a cron monitor (dead-man's-switch style — your job pings a URL on success, you get alerted if it doesn't fire on time). Waitlist is on the site if that's interesting.&lt;/p&gt;




&lt;p&gt;What cron gotchas have bitten you? I'm always looking for more edge cases to add to the tool.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>showdev</category>
      <category>saas</category>
      <category>monitoring</category>
    </item>
  </channel>
</rss>
