<?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: Jim L</title>
    <description>The latest articles on DEV Community by Jim L (@jim_l_efc70c3a738e9f4baa7).</description>
    <link>https://dev.to/jim_l_efc70c3a738e9f4baa7</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%2F3766233%2F709db6b4-8669-45ab-9e00-5fd8f0a97aba.png</url>
      <title>DEV Community: Jim L</title>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jim_l_efc70c3a738e9f4baa7"/>
    <language>en</language>
    <item>
      <title>Why one long AI ad costs more than ten short ones</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Sat, 05 Sep 2026 02:14:20 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/why-one-long-ai-ad-costs-more-than-ten-short-ones-5eji</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/why-one-long-ai-ad-costs-more-than-ten-short-ones-5eji</guid>
      <description>&lt;p&gt;I generated one five minute clip last week and it burned more credits than every short ad I had made in the days before it. The clip was not even usable. I assumed I had been billed for quality, or for resolution, or for some queue priority I had accidentally opted into. It was none of those.&lt;/p&gt;

&lt;p&gt;Lip-sync compute scales with duration, not with whether the result was any good. A single long take has to re-solve mouth shapes across every frame it contains, so a five minute take is not five times the work of a one minute take in the way a longer render usually is. And if the take comes back unusable, which long takes often do, you paid for all of it before you found out.&lt;/p&gt;

&lt;p&gt;The fix is boring and it works: generate in five to eight second beats and stitch them. Sync comes out cleaner because each beat is solved over a short window, and a bad beat costs you one beat instead of the whole ad. This is also how the short ads had stayed cheap without me noticing why.&lt;/p&gt;

&lt;p&gt;The other half of it is picking the model for the job rather than for the spec sheet. &lt;a href="https://casttake.com/models" rel="noopener noreferrer"&gt;CastTake's model and pricing page&lt;/a&gt; lists every model it can run with the rate per second, and the spread is wider than I expected: Grok Imagine 1.5 at 480p is 4 credits a second, MiniMax H3 is 14 at 720p and 22.4 at 1080p, one credit being one US cent. A five second clip is 20 credits, 70, or 112 depending purely on that choice.&lt;/p&gt;

&lt;p&gt;Stitching has a cost I should name, because it is the part nobody mentions when they recommend it. You own continuity yourself now, and keeping a presenter recognisable from one beat to the next needs a reference image rather than luck.&lt;/p&gt;

&lt;p&gt;So the order matters more than the choice. Generate ten hooks on the cheap model to find the one that works, since 480p is already past the resolution most of a phone feed is watched at, then finish the single winner on the expensive one. Running the whole batch at 1080p costs five and a half times as much and does not make a weak script work.&lt;/p&gt;

</description>
      <category>aivideostartushowdevp</category>
    </item>
    <item>
      <title>The six ways an HTML file breaks the moment it leaves your machine</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Fri, 04 Sep 2026 10:13:07 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/the-six-ways-an-html-file-breaks-the-moment-it-leaves-your-machine-1o49</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/the-six-ways-an-html-file-breaks-the-moment-it-leaves-your-machine-1o49</guid>
      <description>&lt;p&gt;I wrote a single-file HTML demo, tested it in my browser, it worked perfectly, then I sent the file to a client and got a screenshot of a blank white page. This has happened to me enough times now that I finally sat down and catalogued what actually goes wrong, because it works on my machine stops being funny after the third time.&lt;/p&gt;

&lt;p&gt;The most common one is a missing charset declaration. Your editor and browser both default to UTF-8 silently, so a page full of curly quotes or an em dash renders fine locally and turns into garbled boxes the second it's opened somewhere with a different default encoding. Second, absolute file:// paths for images or scripts, which point at your hard drive and simply don't exist on anyone else's. Third, blocked mixed content: an HTTPS page trying to load an HTTP resource gets silently blocked by the browser with zero visible error, so the page just looks broken with no clue why.&lt;/p&gt;

&lt;p&gt;Fourth is a missing viewport meta tag, which looks fine on your desktop monitor and turns into a tiny unreadable page the moment someone opens the link on a phone. Fifth, unresolved script references, a relative path to a JS file that lived in the same folder on your machine but doesn't exist wherever the HTML ends up. Sixth, inline event handlers that some hosts and mail clients strip out for security reasons, silently killing any interactivity the page had.&lt;/p&gt;

&lt;p&gt;Every one of these passes a local test because your machine already has the missing context: the right encoding default, the file sitting next to its scripts, no mixed-content policy tripping. The bug only exists once the file is somewhere else, which is exactly when you're least able to debug it.&lt;/p&gt;

&lt;p&gt;After cataloguing the list I started running new files through &lt;a href="https://htmlhosting.org/html-file-to-url" rel="noopener noreferrer"&gt;htmlhosting's publish flow&lt;/a&gt;, which checks for all six of these before the page goes live and offers a one-click fix where a safe default exists, charset gets added, a relative path gets flagged, that kind of thing. It caught the missing viewport tag on a page I was sure was fine, purely because I'd built it and tested it on a monitor, never a phone.&lt;/p&gt;

&lt;p&gt;It's not a replacement for actually testing your own work. But it catches the specific class of bug that's invisible until the file leaves the room you wrote it in, and that's the exact moment you have the least ability to fix it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>html</category>
      <category>showdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Every image-to-3D tool I tried gave me a mesh I couldn't actually use</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Fri, 04 Sep 2026 10:12:14 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/every-image-to-3d-tool-i-tried-gave-me-a-mesh-i-couldnt-actually-use-5348</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/every-image-to-3d-tool-i-tried-gave-me-a-mesh-i-couldnt-actually-use-5348</guid>
      <description>&lt;p&gt;I needed a rough 3D prop for a game prototype, one photo of a wooden crate, turned into something I could drop into an engine that same afternoon. Sounds like exactly the thing AI 3D generation should be good at in 2026. In practice I burned an evening on three different tools before I got anything usable.&lt;/p&gt;

&lt;p&gt;The first tool exported a GLB that looked fine in its own preview window and then imported into my engine with inverted normals, half the crate rendering inside-out. The second one only offered a proprietary viewer format, no OBJ or STL export at all unless I paid for a tier I didn't need for a prototype. The third gave me a real mesh but it was a single fused blob, no separation between the crate's slats and its frame, so I couldn't texture or rig anything on it.&lt;/p&gt;

&lt;p&gt;What actually got me a usable file was &lt;a href="https://sculptly3d.com/" rel="noopener noreferrer"&gt;Sculptly's photo-to-mesh generator&lt;/a&gt;, mostly because it exports what I actually needed instead of what was easiest for them to render: a real GLB, OBJ, and STL from the same generation, not a locked-in viewer format. First model is free with no account and no card, which meant I could just test the crate photo before deciding if the tool was worth using at all instead of registering first and finding out the export was broken after the fact.&lt;/p&gt;

&lt;p&gt;The part I didn't expect to care about: it also produces a Gaussian splat as a .ply file from the same single image, something none of the other three tools even attempted. I didn't need the splat for the game prototype, but I generated one anyway out of curiosity and it held detail on the crate's wood grain that the mesh version simply couldn't represent, since a mesh has to commit to hard edges and a splat doesn't.&lt;/p&gt;

&lt;p&gt;It's still not magic. A single photo of a crate at one angle means the generator has to guess at what the back and underside look like, and on more complex objects that guess shows. It's a starting mesh for a prototype, not a final asset for a shipped product. But for what I needed that afternoon, a mesh with correct normals, in a format my engine could actually import, was the entire ask, and it's the only one of the four tools that cleared that bar on the first try.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>3d</category>
      <category>showdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>Two store APIs, eight ZENONIA games, and no publisher key</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Wed, 02 Sep 2026 07:45:55 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/two-store-apis-eight-zenonia-games-and-no-publisher-key-3dk3</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/two-store-apis-eight-zenonia-games-and-no-publisher-key-3dk3</guid>
      <description>&lt;p&gt;I wanted to know which ZENONIA games a person can actually buy in 2026. There is no endpoint that answers that question. So I asked two endpoints that answer something next to it, and then spent most of the afternoon working out what their answers do not mean.&lt;/p&gt;

&lt;p&gt;Here is the whole method, because it is small enough to fit in a paragraph:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;store.steampowered.com/api/storesearch&lt;/code&gt; once per title.&lt;/li&gt;
&lt;li&gt;One &lt;code&gt;GET play.google.com/store/apps/details?id=&amp;lt;package&amp;gt;&lt;/code&gt; per Google Play package name.&lt;/li&gt;
&lt;li&gt;HTTP 200 means there is a live listing at that identifier. 404 means there is not.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eight titles went in on 2026-08-31. ZENONIA 1 came back on Steam as appid 4538960 with a separate demo at 4733680, priced at $8.99. Inotia 4 came back on Steam too, appid 3956320. ZENONIA 4 and 5 came back on Google Play at &lt;code&gt;com.gamevil.zenonia4.global&lt;/code&gt; and &lt;code&gt;com.gamevil.zenonia5.global&lt;/code&gt;. ZENONIA 2 and 3 returned 404 at the equivalent package names. Six of the eight did not come back from at least one of the two queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that is easy to get wrong
&lt;/h2&gt;

&lt;p&gt;A 404 from Google Play does not mean the app is gone. It means nothing is published at the string you asked for. Those two statements look similar and are not.&lt;/p&gt;

&lt;p&gt;ZENONIA 6 and ZENONIA S were where this bit. I had guessed &lt;code&gt;com.gamevil.zenonia6.global&lt;/code&gt; and &lt;code&gt;com.gamevil.zenoniaS.global&lt;/code&gt;, got 404 on both, and could have written "delisted" next to each of them. A single guessed package name cannot support that word, because a wrong guess produces the same 404 that a removed app produces.&lt;/p&gt;

&lt;p&gt;So the next day I widened it. Starting from the naming pattern that demonstrably works, since ZENONIA 4 and 5 both return 200, I hand-picked 15 variants: both publisher prefixes those two use (Gamevil and Com2uS), the suffix structures that turn up in this naming family, and the case variants of that trailing S. Not a full grid of every prefix crossed with every suffix. A specific list, written down, so anyone can rerun it.&lt;/p&gt;

&lt;p&gt;All 15 returned 404. Zero hit 200. The two known-good packages were sent in the same batch as controls and both returned 200, which is the only reason I trust the 404s at all.&lt;/p&gt;

&lt;p&gt;That still does not prove either title was never on Google Play. The package-name space is unbounded and I cannot try every string in it. So both stay recorded as &lt;strong&gt;Unverified&lt;/strong&gt;, not as delisted, and the candidate list sits next to the result so that someone who knows a package name that returns 200 can close it in one message.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 200 is not a green light either
&lt;/h2&gt;

&lt;p&gt;One of the listings that answers 200 also says, in its own store copy, that it is only available up to Android 4.4 KitKat. The page is live. The install button is there. The ceiling is from 2013.&lt;/p&gt;

&lt;p&gt;I have not tried to install it on a device, so I record that as the listing's own restriction rather than a prediction about anyone's phone. But it is the reason the table has two separate columns instead of one: "has a live store page" and "you can play this tonight" are different facts, and collapsing them into a single green tick would have been the most useful-looking mistake available.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would tell anyone probing a store catalogue
&lt;/h2&gt;

&lt;p&gt;Send known-good controls in the same batch, every time. Two of my requests existed purely to prove the pipeline could still see a 200, and they are the difference between a result and a rumour.&lt;/p&gt;

&lt;p&gt;Write down the exact strings you tried. "We searched and found nothing" is unfalsifiable. A list of 15 candidates with 15 status codes is something a stranger can attack.&lt;/p&gt;

&lt;p&gt;And date-stamp the row, not the page. Store listings change without telling anyone, so every status I have is a claim about one moment.&lt;/p&gt;

&lt;p&gt;Every request behind this, the raw responses and the two controls, is in &lt;a href="https://zenonia.wiki/where-to-play/" rel="noopener noreferrer"&gt;the full ZENONIA store-status table, with every request logged&lt;/a&gt;. If you have a package name that returns 200 for ZENONIA 6 or S, that page is where it belongs.&lt;/p&gt;

</description>
      <category>api</category>
      <category>gamedev</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Code Interpreter is infrastructure, not a prompt</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Tue, 11 Aug 2026 12:33:52 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/code-interpreter-is-infrastructure-not-a-prompt-18hm</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/code-interpreter-is-infrastructure-not-a-prompt-18hm</guid>
      <description>&lt;p&gt;I spent a weekend trying to move a custom GPT onto local weights and got the model part done in about an hour. The rest of the weekend went to one feature I had never once thought about: Code Interpreter.&lt;/p&gt;

&lt;p&gt;My assumption going in was that writing Python was the hard part, so a model that writes decent Python covers it. That assumption is wrong in a specific way, and it is worth naming because the same mistake shows up in every "local model vs ChatGPT" comparison I have read.&lt;/p&gt;

&lt;p&gt;Writing Python is the easy half. The hard half is &lt;strong&gt;running&lt;/strong&gt; it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you are actually replacing
&lt;/h2&gt;

&lt;p&gt;When a user uploads a CSV to a custom GPT and asks it to plot something, here is the shape of what happens on OpenAI's side:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a container spins up&lt;/li&gt;
&lt;li&gt;the file lands in it&lt;/li&gt;
&lt;li&gt;generated code executes against that file&lt;/li&gt;
&lt;li&gt;the container has no network&lt;/li&gt;
&lt;li&gt;it dies on a timeout&lt;/li&gt;
&lt;li&gt;nothing it did can touch anything else&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every one of those is a decision someone made and then operated. None of them is a prompt. You do not get any of them by downloading weights, no matter how good the weights are at writing pandas.&lt;/p&gt;

&lt;p&gt;So when you move off a custom GPT, this is not a capability that ports and it is not a capability that disappears. It is a capability that becomes yours to host. That distinction turns out to matter a lot for planning, because the three categories behave completely differently:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;What it costs you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ports as-is&lt;/td&gt;
&lt;td&gt;Your Actions endpoint&lt;/td&gt;
&lt;td&gt;Nothing, it was already your HTTP API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You rebuild&lt;/td&gt;
&lt;td&gt;Code Interpreter&lt;/td&gt;
&lt;td&gt;Evenings, plus something you now operate forever&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does not port&lt;/td&gt;
&lt;td&gt;Image generation&lt;/td&gt;
&lt;td&gt;A second model, or a no&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I had been treating all three as one bucket labelled "stuff I lose", which made the whole decision look scarier than it was, while simultaneously filing "I'll just add a sandbox" under Saturday afternoon, which made the actual work look easier than it was.&lt;/p&gt;

&lt;h2&gt;
  
  
  The naive version and why it is not fine
&lt;/h2&gt;

&lt;p&gt;The first thing anyone writes 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="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generated_code&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;__builtins__&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 is not a sandbox. Stripping builtins is a speed bump for anything that can reach a class hierarchy, and a generated script does not have to be malicious to hurt you here. A model that writes an accidental infinite loop, or an accidental &lt;code&gt;while True&lt;/code&gt; that appends to a list, does the same damage as one that was trying to.&lt;/p&gt;

&lt;p&gt;The actual requirements, once I wrote them down honestly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Filesystem isolation, because the user's uploaded file should be the only file the code can see&lt;/li&gt;
&lt;li&gt;No network, because a model that decides to &lt;code&gt;pip install&lt;/code&gt; something is a model that just gave a package registry your execution context&lt;/li&gt;
&lt;li&gt;A wall clock timeout that kills the process, not one that asks it nicely&lt;/li&gt;
&lt;li&gt;A memory ceiling, for the same reason as the timeout&lt;/li&gt;
&lt;li&gt;Some way to get the plot back out, which sounds trivial until the container is correctly isolated and now you need a channel&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of this is available. gVisor, Firecracker, a locked-down Docker container with &lt;code&gt;--network none&lt;/code&gt; and a cgroup limit, or one of the hosted sandbox APIs if you would rather rent it than run it. None of it is exotic. What I keep coming back to is that on the ChatGPT side, items 1 through 5 were a checkbox in a form.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it changed about my decision
&lt;/h2&gt;

&lt;p&gt;I ended up not moving the assistant that used Code Interpreter, and moving two others that did not. That sounds like a compromise but it was actually the useful outcome, because it forced the question to be asked per capability instead of per assistant.&lt;/p&gt;

&lt;p&gt;The move is worth it when the reason is that data cannot leave your machines, or when you want the model to still behave the same in five years regardless of what a pricing page says by then. It is not worth it when your real bill is engineering time. Two evenings rebuilding retrieval costs more than a year of Plus, and I say that as someone who spent the two evenings.&lt;/p&gt;

&lt;p&gt;If you want to run the same audit against your own build rather than mine, the &lt;a href="https://www.openaitoolshub.org/en/tools/muse-glimmer-vs-gpts?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=oath-devto-20260811-muse-glimmer" rel="noopener noreferrer"&gt;Muse Glimmer vs GPTs capability checker&lt;/a&gt; does exactly this: you tick which features your GPT actually uses, and it splits them into ports, rebuild, and blocked, with the reasoning shown for each. It also asks how much VRAM you have before it tells you anything encouraging, which I appreciated after being told by three separate blog posts that the model needs anywhere from 17 GB to 64 GB.&lt;/p&gt;

&lt;p&gt;If I were starting the weekend again, I would skip the benchmarking entirely on day one and just list what my assistant uses, marking each feature as code or as operations. The model comparison I spent most of Saturday on turned out not to be the comparison that decided anything.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>python</category>
      <category>devops</category>
    </item>
    <item>
      <title>Every Pokopia guide names the habitat. None of them prices it</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Tue, 11 Aug 2026 05:27:50 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/every-pokopia-guide-names-the-habitat-none-of-them-prices-it-150b</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/every-pokopia-guide-names-the-habitat-none-of-them-prices-it-150b</guid>
      <description>&lt;p&gt;Shellder lives in two Bubbly Basin habitats. One of them costs 2 material units to build. The other costs 6. Serebii, Nintendo Life and game8 all tell you where Shellder spawns, and I read all three on 11 August 2026 without finding a single unit cost between them.&lt;/p&gt;

&lt;p&gt;That is the gap. Location data is everywhere. What you actually spend to reach that location is nowhere, and it is the number that decides your build order.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers that fall out once you price everything
&lt;/h2&gt;

&lt;p&gt;There are 50 Pokemon in Bubbly Basin. Phione and Manaphy do not come from a habitat at all, which leaves 48 that do.&lt;/p&gt;

&lt;p&gt;29 of those 48 come from exactly one habitat. For most of the Basin there is no route to compare, no saving to hunt, and nothing to optimise. The advice "pick the cheaper habitat" is unactionable for 60% of the roster, which is worth saying plainly rather than burying under a comparison table that mostly has one row.&lt;/p&gt;

&lt;p&gt;The choices that do exist are small and clustered. Shellder has the biggest spread at 4 units between its cheapest and dearest source. Corphish and Corsola are next at 3. After that the gaps stop mattering.&lt;/p&gt;

&lt;p&gt;Four species tie for cheapest at 2 units: Corphish, Crawdaunt, Shellder and Totodile. The dearest is Starmie at 13, via Mermaid's Gym, and nothing else spawns it. If Starmie is on your list, that 13 is not negotiable, and it is better to plan around it than to discover it halfway through a build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the value ratio and the unit count disagree
&lt;/h2&gt;

&lt;p&gt;The habitat table on the same site ranks habitats by Pokemon per distinct material type, and it is explicit that four units of one material cost it nothing. That is the correct measure when you have a full inventory and you are deciding what to spend it on.&lt;/p&gt;

&lt;p&gt;It is the wrong measure when you are the one out gathering, because what you collect is units, not categories.&lt;/p&gt;

&lt;p&gt;The two rankings pull apart at both ends. Bubbly bathtub asks for the fewest units in the Basin, 2, and comes 20th of 36 on the value ratio. Basin tall grass tops the ratio at 4.00 and sits 16th on units. Neither ranking is broken. They answer different questions, and which one you want depends entirely on whether your bottleneck is inventory or gathering time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing neither measure can see
&lt;/h2&gt;

&lt;p&gt;None of this knows where the materials are found. The dataset has habitat costs and no gathering locations in it.&lt;/p&gt;

&lt;p&gt;That matters more than the unit gaps do. A 2-unit habitat whose one material only appears in a far corner of the map can easily take longer than a 5-unit habitat built from things lying around your base. Until someone maps material spawn points, unit cost is a proxy for effort rather than a measure of it, and anyone telling you otherwise has not gone and collected them.&lt;/p&gt;

&lt;p&gt;I would rather say that out loud than let a tidy sorted table imply a precision it does not have.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use it anyway
&lt;/h2&gt;

&lt;p&gt;Work backwards from the species you actually want. Look up each one, note whether it has a choice at all, and only spend thinking time on the handful with a real spread. Then total the materials for every habitat on your list at once rather than building them one at a time, because the overlaps are where the genuine savings are, not in swapping a 3-unit habitat for a 2-unit one.&lt;/p&gt;

&lt;p&gt;The full table, all 50 species with their source habitats priced in total material units and sortable by cheapest source or biggest saving, is at &lt;a href="https://pokopiabubblybasin.wiki/pokemon-locations?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=pokopia-devto-20260811-locations" rel="noopener noreferrer"&gt;Pokemon locations in Bubbly Basin&lt;/a&gt;. It also flags which species have no alternative, so you can stop looking for a cheaper route that does not exist.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>data</category>
      <category>showdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Palworld's Cake recipe lists 5 Flour, and Flour is not something you can pick up</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Tue, 11 Aug 2026 05:24:38 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/palworlds-cake-recipe-lists-5-flour-and-flour-is-not-something-you-can-pick-up-1475</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/palworlds-cake-recipe-lists-5-flour-and-flour-is-not-something-you-can-pick-up-1475</guid>
      <description>&lt;p&gt;The Cake recipe looks like five ingredients. Four of them are, in the sense that you can go out and end up holding one. Flour is not. Flour comes out of a Mill at 3 Wheat to 1, so the line that reads "Flour x5" is really "Wheat x15", and that single indirection is most of the reason Cake feels more expensive than the recipe card suggests.&lt;/p&gt;

&lt;p&gt;Here is the whole bill for one Cake:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ingredient&lt;/th&gt;
&lt;th&gt;Per cake&lt;/th&gt;
&lt;th&gt;Where it comes from&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Flour&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Milled from 15 Wheat, 3 to 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Red Berries&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Berry Plantation, or gathered wild&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Milk&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Mozzarina on a Ranch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Egg&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Chikipi on a Ranch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Honey&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Beegarde on a Ranch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Total raw Wheat: 15. Mill conversions: 5.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part nobody puts in the recipe box
&lt;/h2&gt;

&lt;p&gt;Three of those five lines are Ranch output. Milk, Egg and Honey cost you no materials at all, which is why they look free in a recipe listing. What they actually cost is three Ranch slots and the Pals to fill them, and they arrive on their own schedule rather than when you want them. If you are short on Cake it is usually not because you ran out of Wheat, it is because one of the three Ranch lines is not running.&lt;/p&gt;

&lt;p&gt;The Wheat itself has an escape hatch worth knowing about. You can grow it on a plantation, or you can buy it from a Wandering Merchant and skip the plantation entirely. Either way it is the only ingredient that still needs processing after you have it, at 10 workload per Mill conversion.&lt;/p&gt;

&lt;p&gt;Cooking is a Cooking Pot or Electric Kitchen at 2000 workload with a Kindling Pal assigned.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need unlocked before any of this matters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cake recipe&lt;/strong&gt;: Technology level 17.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Breeding Farm&lt;/strong&gt;: Technology tier 19, plus 2 Ancient Technology points. Build cost is 10 Wooden Board, 20 Stone, 50 Fiber.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mill&lt;/strong&gt;: needed for the Flour step, 3 Wheat to 1 Flour.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One honest gap in that list. The Breeding Farm workload figure reads as 15000 to me, and an independent check of the same page read it as 150. Two orders of magnitude apart on a number I only have one page for, so I left it out rather than pick a side.&lt;/p&gt;

&lt;h2&gt;
  
  
  How many cakes does a mutation hunt cost
&lt;/h2&gt;

&lt;p&gt;This is the question everyone actually arrives with, and it is not answerable. Not because the arithmetic is hard, but because half of it has never been published.&lt;/p&gt;

&lt;p&gt;One breeding cycle consumes one Cake, so cakes are roughly equal to cycles. That figure is single-sourced, and both Game8 and the Cake and Breeding Farm pages on palworld.wiki.gg omit it entirely, so it is not a settled number either.&lt;/p&gt;

&lt;p&gt;What nobody publishes is how many cycles a mutation takes. The rates I found range from 1% to somewhere in the 5 to 10% band per egg. That is a five to tenfold spread, and multiplying an unknown by a lightly-sourced known does not produce an answer, it produces a number that looks like one.&lt;/p&gt;

&lt;p&gt;Cycle length has the same problem. One source puts a cycle at "roughly two to four hours of in-game time depending on the parent Pals rank". That is single-sourced and wide enough that cake-per-real-hour is not worth computing. The Breeding Farm page omits duration altogether.&lt;/p&gt;

&lt;p&gt;So the useful version of the question is not "how much will my mutation hunt cost", it is "how much Wheat do I need for the next 25 cakes", which is 375, plus 200 Red Berries and three Ranch lines that have been running long enough to bank 175 Milk, 200 Egg and 50 Honey.&lt;/p&gt;

&lt;p&gt;If you want the multiplication done for a batch size you pick, with every quantity attributed to the page that stated it, the &lt;a href="https://palworldgames.wiki/cake-cost?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=palworld-devto-20260811-cake-cost" rel="noopener noreferrer"&gt;Palworld cake cost calculator&lt;/a&gt; runs the whole chain including the Mill conversions. Nothing on it is estimated, and the figures that are single-sourced are labelled as such rather than presented alongside the corroborated ones.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>data</category>
      <category>showdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>A 60-inch round table seats 8. It also seats 10. Both numbers are correct</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Tue, 11 Aug 2026 05:21:24 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/a-60-inch-round-table-seats-8-it-also-seats-10-both-numbers-are-correct-55dk</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/a-60-inch-round-table-seats-8-it-also-seats-10-both-numbers-are-correct-55dk</guid>
      <description>&lt;p&gt;Book 13 tables for 100 wedding guests and you finish with four spare seats. Book 10 and you finish with a room where nobody can slide a chair under the table. Both counts describe the same table, the 60-inch round, and both come from companies that rent it out for a living.&lt;/p&gt;

&lt;p&gt;I went looking for the discrepancy expecting to find one supplier being sloppy. That is not what is going on. The suppliers are answering different questions and none of them says which question they answered.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four questions hiding inside one number
&lt;/h2&gt;

&lt;p&gt;How the table is laid. Ten covers fit on a 60-inch tabletop. Ten &lt;em&gt;full&lt;/em&gt; covers, meaning charger, side plate and three glasses, do not. One rental firm states this outright: with formal place settings you cannot fit more than eight. If your caterer is doing a charger and a wine flight, your table is an eight whatever the capacity chart says.&lt;/p&gt;

&lt;p&gt;Whether the chairs tuck in. At ten, chairs stop sliding under the table. This is the detail that decides whether a table feels crowded, and it happens long before anyone counts the plates. Nobody at the wedding will say "this table is over capacity". They will say they had to shuffle sideways to let someone past.&lt;/p&gt;

&lt;p&gt;How the food arrives. A plated dinner is costed at roughly 24 inches of table edge per guest. Family-style service, where platters live on the table, is quoted nearer 18. Same supplier, same table, different answer, because the platters need the middle and the plates need the edge.&lt;/p&gt;

&lt;p&gt;Who is answering. One of the sources I checked was a furniture retailer describing home dining. It starts a 48-inch round at four people. Event rental firms put the same table at six to eight. Neither is wrong. A dining room is not a marquee, and the retailer never claimed otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  The page that could not agree with itself
&lt;/h2&gt;

&lt;p&gt;The clearest illustration was a single rental listing that manages three different numbers on one page. The heading says "Seats up to 10 adults". The body says it "will seat up to 8 adult guests comfortably". A photo caption underneath says "up to 10 chairs".&lt;/p&gt;

&lt;p&gt;That is not sloppiness worth mocking. It is what happens when comfortable capacity and physical capacity get written by different people for the same product. It does mean that any single number you are quoted should be treated as the opening of a conversation with your venue rather than a specification.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does to your 100-guest count
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Table&lt;/th&gt;
&lt;th&gt;Comfortable&lt;/th&gt;
&lt;th&gt;Maximum&lt;/th&gt;
&lt;th&gt;Tables for 100&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;60 inch round (5 ft)&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;13 to 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;72 inch round (6 ft)&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;10 to 9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;48 inch round (4 ft)&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;25 to 13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8 ft banquet&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;13 to 10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6 ft banquet&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;17 to 13&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One note on the banquet rows. A 6 ft table gets quoted as "6-8", and the one source that spells out the arrangement puts three chairs down each side plus one at each end. If you are not seating the ends, and plenty of couples do not, it is a six.&lt;/p&gt;

&lt;p&gt;The 66-inch round is missing from that table on purpose. Suppliers disagreed on it without a majority, and averaging numbers nobody stated felt worse than leaving a gap.&lt;/p&gt;

&lt;p&gt;Room size is worth a sanity check rather than a decision: 100 guests with a dance floor lands somewhere around 1,300 to 1,850 sq ft. Venues quote their own capacity, so use this to notice a room that is obviously too small, not to overrule the venue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Round up, on purpose
&lt;/h2&gt;

&lt;p&gt;Whichever number you land on, take the comfortable one rather than the maximum. Guest counts move in the last fortnight and they mostly move up. A layout with zero slack turns one late acceptance into a new table, new linen, and a chart that has to be redrawn after it went to the printer.&lt;/p&gt;

&lt;p&gt;The count is also the easy half. Knowing you need ten tables tells you what to book. It does not tell you who sits where, and that is the part that keeps changing after the stationery is ordered. In r/weddingplanning threads about presenting a seating plan, one recurring argument for individual escort cards over a single printed chart is that a card can be quietly pulled when somebody cancels, while a chart has to be redone. That is one commenter in one thread rather than a survey, but the underlying worry is real: the question is rarely "can I edit the plan", it is "does this edit force a reprint".&lt;/p&gt;

&lt;p&gt;If you want to run your own guest count and table size rather than borrow mine, the &lt;a href="https://weddingseatchart.com/how-many-tables-for-100-guests?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=wsc-devto-20260811-tables-100" rel="noopener noreferrer"&gt;tables for 100 guests calculator&lt;/a&gt; does the arithmetic and shows how many spare seats each layout leaves you, with every capacity figure attributed to the supplier who published it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I Kept Missing a Game Event by 40 Minutes, So I Built a Timezone-Aware Countdown For It</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Thu, 06 Aug 2026 04:59:08 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-kept-missing-a-game-event-by-40-minutes-so-i-built-a-timezone-aware-countdown-for-it-4gef</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-kept-missing-a-game-event-by-40-minutes-so-i-built-a-timezone-aware-countdown-for-it-4gef</guid>
      <description>&lt;p&gt;Forza Horizon 6 has a weekly event called the Treasure Hunt: photo clues drop you into a hidden car reward, and the whole thing resets every Thursday at 14:30 UTC. Simple enough, except I'm in Australia, the reset time is written in UTC everywhere the game and its community talk about it, and daylight saving shifts my offset from UTC twice a year. I missed the reset window three weeks running, not because the game is hard, but because I did timezone arithmetic badly at 11pm.&lt;/p&gt;

&lt;p&gt;The usual fix people post in the FH6 subreddit is "just remember it's Thursday afternoon UTC." That works until DST flips in either your hemisphere or the UK's (the game's scheduling appears to follow UK server time, which itself observes BST/GMT), and now your mental math is off by an hour and you don't find out until the treasure hunt map is already blank.&lt;/p&gt;

&lt;p&gt;So I built a small countdown page: &lt;a href="https://fh6treasurehunt.com/tools/reset-timer?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=fh6treasurehunt-devto-20260806-reset-timer" rel="noopener noreferrer"&gt;fh6treasurehunt.com/tools/reset-timer&lt;/a&gt;. It does three things I couldn't find bundled anywhere else:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Converts 14:30 UTC to your local time automatically&lt;/strong&gt;, using &lt;code&gt;Intl.DateTimeFormat&lt;/code&gt; with the browser's detected timezone rather than a hardcoded offset table, so it doesn't quietly break twice a year when DST changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shows a live countdown&lt;/strong&gt;, not just a static "resets Thursday" label, so you can tell at a glance whether you have 6 hours or 6 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;States where the season rotation currently sits&lt;/strong&gt;, since the treasure hunt content itself changes with the season and a bare countdown without that context is only half the answer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The annoying part wasn't the countdown math, that part is a solved problem. It was building an archive to go with it. Once I had the timer, the obvious next question was "okay, but what about the hunt I missed two weeks ago." Most guide sites only ever show the current week, so I ended up building a searchable archive of past hunts alongside the timer, which turned out to be more work than the timer itself.&lt;/p&gt;

&lt;p&gt;Small site, narrow job, but it's the kind of "I got annoyed enough to fix it myself" project that's more fun to build than anything I get paid for. If you've built something similarly single-purpose to fix your own recurring annoyance, I'd like to hear about it in the comments.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Ran the Numbers on HKMC's 3% Annuity Discount Before Booking the Sales Appointment</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Wed, 05 Aug 2026 03:31:07 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-ran-the-numbers-on-hkmcs-3-annuity-discount-before-booking-the-sales-appointment-4ofh</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-ran-the-numbers-on-hkmcs-3-annuity-discount-before-booking-the-sales-appointment-4ofh</guid>
      <description>&lt;p&gt;HKMCA is dangling a 3% premium discount if you book a sales appointment by August 31 and get your application in by September 30. Sounds like a nice little bonus until you sit down and work out what 3% actually means in dollars, because on the kind of premium people actually put into these annuity plans, it's not pocket change either direction.&lt;/p&gt;

&lt;p&gt;I've been tracking Hong Kong's HKMC Annuity Plan on and off for about two years, mostly because my parents keep asking whether it's worth converting part of their MPF payout into one. The 3% discount promo is the first time HKMC has run a time-limited incentive like this on the plan, and it's pulling in a lot of "should I rush this" energy from people who otherwise weren't planning to touch the product this year.&lt;/p&gt;

&lt;p&gt;Here's the math nobody spells out at the sales appointment. On a HK$500,000 premium, 3% is HK$15,000. On HK$2,000,000, it's HK$60,000. That's real money, but it's a one-time discount on an irreversible decision that locks your capital into a fixed monthly payout for the rest of your life, with no lump-sum exit once you're in. The annuity's actual value depends far more on your age, sex (payout rates differ), and how long you expect to live than on whether you caught a 3% early-bird window.&lt;/p&gt;

&lt;p&gt;I built a small calculator that takes your age, sex, and intended premium and shows the exact discount amount alongside the plan's standard internal rate of return at different life expectancies, so you can see whether the 3% actually moves the needle versus just waiting for the next promo cycle (HKMC has run smaller ones before). &lt;a href="https://www.lowrisktradesmart.org/en/tools/hkmc-annuity-discount-worth-it" rel="noopener noreferrer"&gt;https://www.lowrisktradesmart.org/en/tools/hkmc-annuity-discount-worth-it&lt;/a&gt;. Enter your numbers and it spits out both figures side by side.&lt;/p&gt;

&lt;p&gt;A few things I noticed while building it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The discount rate scales with premium size but the underlying monthly payout formula doesn't get any more generous. You're not getting a better annuity, just a cheaper entry ticket into the same one.&lt;/li&gt;
&lt;li&gt;Deadlines matter more than the discount itself for some people. If you were already going to apply this year, the 3% is free money. If you weren't, don't let a promo talk you into an irreversible 15-20 year commitment you weren't ready for.&lt;/li&gt;
&lt;li&gt;The break-even point (age at which the annuity starts winning over just keeping the cash in a term deposit or the Silver Bond) doesn't move much with a 3% discount. It shifts the number by maybe 1-2 years, not the 5+ years some sales pitches implied when I asked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're on the fence, run your actual premium through the tool before the appointment. It takes less time than the meeting itself, and at least you'll walk in knowing whether you're chasing HK$15,000 or HK$150,000, and whether either number changes your answer.&lt;/p&gt;

</description>
      <category>personalfinance</category>
      <category>hongkong</category>
      <category>money</category>
      <category>finance</category>
    </item>
    <item>
      <title>I Killed My Subscription Price Because Nobody Buys a Monthly Plan for an Anniversary Gift</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Mon, 03 Aug 2026 21:36:29 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-killed-my-subscription-price-because-nobody-buys-a-monthly-plan-for-an-anniversary-gift-1c9e</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-killed-my-subscription-price-because-nobody-buys-a-monthly-plan-for-an-anniversary-gift-1c9e</guid>
      <description>&lt;p&gt;I launched &lt;a href="https://songmemento.com" rel="noopener noreferrer"&gt;songmemento.com&lt;/a&gt; with a $19.99/month subscription as the only way to pay, and it took less time than I'd like to admit to realize that was the wrong model for what the product actually is.&lt;/p&gt;

&lt;p&gt;The tool turns one specific memory into a custom AI-generated song: you answer three short questions (who it's for, the memory, the occasion), get a free ~15-second preview generated from your actual answers, then pay for the full track. The occasions people were describing in testing were things like a proposal, an anniversary, a specific birthday. Those are events that happen once or twice a year for any given person, sometimes once ever. Asking someone to commit to a recurring monthly charge for a gift they need exactly one time is a mismatch between the pricing model and the actual use case, and I built that mismatch myself by defaulting to "SaaS pricing" without checking whether this was actually a SaaS.&lt;/p&gt;

&lt;p&gt;I switched to a one-off price of $1.80 per song, with a $13 bundle (about $1.30/song) for anyone making more than one, wedding favors or a batch of birthday gifts across a year. The subscription still exists but it's no longer the lead offer; one-off is what the checkout flow pushes toward now.&lt;/p&gt;

&lt;p&gt;The engineering side of that pivot was smaller than the business-reasoning side, which is worth saying plainly: dropping a subscription-gate check and adding a single-purchase Stripe flow is a day of work, not a rebuild. The actual full track renders in roughly 60 seconds after purchase using the ACE-Step model on Replicate, and that part of the stack didn't change at all. What changed was entirely upstream: I'd built pricing around what's easy to bill (recurring revenue is nice on paper) instead of around when the customer actually has money-in-hand intent, which for a gift product is right at the moment of the occasion, not on a monthly cycle.&lt;/p&gt;

&lt;p&gt;I'll be honest about where this still sits: real user numbers are near zero, this is a few-days-old build-in-public project, and I'm not going to pretend otherwise with fake testimonials or usage stats. The free preview is a real render of your own answers, not a stock demo, and that part I'll stand behind regardless of pricing. If you're building a gift or occasion-based product and defaulting to subscription pricing because that's what every SaaS starter template ships with, it's worth asking whether your actual purchase moment repeats monthly or not before you commit to that model.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Skipped the YouTube Scraper and Made You Paste the Transcript Instead</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Mon, 03 Aug 2026 21:26:55 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-skipped-the-youtube-scraper-and-made-you-paste-the-transcript-instead-58g5</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-skipped-the-youtube-scraper-and-made-you-paste-the-transcript-instead-58g5</guid>
      <description>&lt;p&gt;A friend sent me a 40-minute lecture recording two nights before her exam and asked if my quiz tool could just "pull the transcript" from the video URL. The honest answer was no, and after building the alternative, I don't think I want it to.&lt;/p&gt;

&lt;p&gt;My first instinct when I started &lt;a href="https://quizpaste.com" rel="noopener noreferrer"&gt;quizpaste.com&lt;/a&gt; was to build a YouTube scraper: paste a URL, hit the captions endpoint, extract the transcript, generate a quiz. I got as far as a working prototype using &lt;code&gt;youtube-transcript-api&lt;/code&gt; before I stopped and thought about what happens six months from now when YouTube changes how captions are served, or rate-limits the endpoint, or the video is age-restricted, or the uploader disabled captions entirely. Every one of those breaks silently, and I'd be the one finding out from a support email instead of a test.&lt;/p&gt;

&lt;p&gt;So I ripped it out. Instead, quizpaste just takes text. If you want a quiz from a YouTube video, you open the transcript panel under the video, click "Copy transcript," and paste the raw text into the same box you'd use for lecture notes. No API key, no scraping, no maintenance burden tied to a UI I don't control. It is a worse demo (you can't just drop a URL) and a more durable product.&lt;/p&gt;

&lt;p&gt;The harder engineering problem turned out to be downstream of that decision, not upstream of it: making sure every question the model generates can actually be traced back to a sentence in whatever text you pasted, transcript or notes. The generation step asks the model for candidate question/answer pairs, but before anything reaches your screen, a second pass checks whether the answer text has a real match against the source: not a fuzzy vibe-check, an actual substring/near-match search against the original paragraph. If a candidate question doesn't clear that bar, it's discarded and never shown to you, quietly, no retry loop that eventually gives up and shows you something ungrounded anyway. That constraint is what makes the transcript-paste approach work at all: a hallucinated answer sourced from "general knowledge about the video" would be useless once you're staring at a flashcard with no way to check it.&lt;/p&gt;

&lt;p&gt;The tradeoffs I made are honest ones. There's no account sync between devices right now, so if you generate a quiz on your laptop it doesn't follow you to your phone, and the free tier caps out at two generations per IP per day (that cap exists to keep the AI bill sane, not to push an upgrade, because there currently isn't a paid tier to push you to). Export is .tsv and CSV, Anki-importable, but there's no packaged .apkg file yet.&lt;/p&gt;

&lt;p&gt;If you're building anything that ingests third-party platform content, I'd genuinely rather maintain a slightly worse first-run experience than own a scraper that breaks the moment someone else's frontend changes. Happy to talk through the citation-matching logic in more detail if anyone's solving a similar problem.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
