<?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>How Volumetric Multi-Color 3MF Segmentation Solves the Bambu Lab AMS Layer-Bleed Problem</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Thu, 01 Oct 2026 01:32:38 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/how-volumetric-multi-color-3mf-segmentation-solves-the-bambu-lab-ams-layer-bleed-problem-j6g</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/how-volumetric-multi-color-3mf-segmentation-solves-the-bambu-lab-ams-layer-bleed-problem-j6g</guid>
      <description>&lt;p&gt;Multi-material 3D printing has transitioned from an experimental dual-extrusion hack into an everyday consumer standard, largely driven by automated filament changers like the Bambu Lab AMS, Anycubic ACE, and Prusa MMU3. Today, printing a functional prototype, decorative emblem, or tabletop miniature across four distinct filament spools requires zero physical intervention mid-print.&lt;/p&gt;

&lt;p&gt;However, anyone who has attempted to take a raw 3D mesh—especially one generated from an illustration or reconstructed via neural surfaces—into a slicer knows the agonizing bottleneck of mesh preparation.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Triangle Paintbrush Trap
&lt;/h3&gt;

&lt;p&gt;When you import an unsegmented mesh (such as a monolithic STL or OBJ) into Bambu Studio or OrcaSlicer, your only native option for multi-color assignment is the surface paintbrush tool.&lt;/p&gt;

&lt;p&gt;While the paintbrush works adequately on flat geometric test cubes, it quickly falls apart on complex organic topology:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Facet Bleedthrough&lt;/strong&gt;: On thin walls (like character ears, armor collars, or structural fins), clicking a face on the front of the model frequently paints through to the back because the brush projection treats the geometry as a 2D surface raster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concave Shadow Seams&lt;/strong&gt;: Crevices, undercut joints, and narrow interior pockets are physically unreachable by raycast cursor selection, leaving uncolored voids where the nozzle fails to switch materials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shell-Depth Inconsistency&lt;/strong&gt;: Slicer color painting applies color to a superficial layer depth (typically 2 to 3 perimeter walls). If the model undergoes mechanical post-processing, light sanding, or has slight underextrusion, the underlying primary body color immediately shows through.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a detailed figurine, manual facet painting routinely takes between 90 minutes and 3 hours per model before you can even click slice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transitioning from Surface Painting to Volumetric Segregation
&lt;/h3&gt;

&lt;p&gt;The fundamental issue is treating multi-color printing as a 2D painting problem rather than a 3D CAD assembly problem. A multi-toolhead or AMS-driven printer does not need painted surfaces; it requires discrete, manifold solid volumes that intersect seamlessly at boundary walls.&lt;/p&gt;

&lt;p&gt;The modern solution lies in automated volumetric segmentation at the file container level—specifically within the 3MF (3D Manufacturing Format) specification.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Monolithic STL Pipeline (Painful):
[2D Art / Mesh] -&amp;gt; [Single Monolithic STL] -&amp;gt; [Manual Slicer Triangle Painting (2 hrs)] -&amp;gt; [Unpredictable Purge / Bleed]

Volumetric 3MF Pipeline (Automated):
[2D Art / Mesh] -&amp;gt; [Volumetric Color Clustering] -&amp;gt; [Multi-Body Assembly in 3MF] -&amp;gt; [Instant 1-Click AMS Slot Assignment]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In an automated volumetric pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Color Quantization and Clustering&lt;/strong&gt;: Continuous tonal gradients are simplified into a discrete palette (typically 2 to 8 target filaments) based on dominant semantic features (skin, primary body, trim, accent).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Volumetric Island Extraction&lt;/strong&gt;: Instead of coloring boundary triangles, the algorithm calculates depth normals and partitions the geometry into distinct solid sub-meshes, each with water-tight boundary closure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assembly 3MF Packaging&lt;/strong&gt;: The separate bodies are exported as a unified 3MF production file where relative coordinate transforms and origin anchors are preserved identically across all sub-components.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Platforms specifically engineered for desktop manufacturing, such as Sculptly3D, have adopted this volumetric segmentation architecture. When loading a model generated through Sculptly3D into Bambu Studio, the slicer does not encounter an unpainted mesh; it opens a structured multi-part assembly. Assigning AMS slots becomes a matter of right-clicking sub-assemblies and choosing filament slots in under twenty seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Calibrating Slicer Parameters for Multi-Body 3MFs
&lt;/h3&gt;

&lt;p&gt;Once you have a true multi-body 3MF file loaded into your slicer, achieving clean print finishes comes down to tuning three mechanical parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flushing Volume Multipliers&lt;/strong&gt;: When transitioning from saturated or dark pigments (like carbon black or royal blue) to light pigments (like alpine white or pastel yellow), standard slicer defaults often under-purge. Setting your dark-to-light flushing multiplier to 1.3 or 1.5 prevents dingy gray banding on white shells.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wipe Tower Density and Placement&lt;/strong&gt;: Keep the purge tower oriented toward the rear center of your build plate to minimize toolhead travel distances. Setting wipe tower brim width to at least 5mm prevents tall purge towers from detaching during high-speed travel moves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interlocking Interface Clearances&lt;/strong&gt;: If the sub-bodies are designed to fit together post-printing rather than fusing during a single print run, ensure a radial tolerance gap of 0.15mm to 0.20mm for standard 0.4mm brass or hardened steel nozzles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By replacing tedious manual surface painting with true volumetric 3MF body partitioning, creators can shift their time away from vertex micro-management and focus on high-velocity rapid prototyping.&lt;/p&gt;

</description>
      <category>design</category>
      <category>hardware</category>
      <category>tools</category>
    </item>
    <item>
      <title>One Photo, Three Formats: How an AI Ad Maker Classifies Products Before Rendering</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Mon, 28 Sep 2026 08:19:25 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/one-photo-three-formats-how-an-ai-ad-maker-classifies-products-before-rendering-538n</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/one-photo-three-formats-how-an-ai-ad-maker-classifies-products-before-rendering-538n</guid>
      <description>&lt;p&gt;Every e-commerce seller has an asset folder packed with plain Amazon or Shopify listing shots: white backgrounds, flat studio lighting, and zero personality. When you look at high-performing TikTok feeds, none of the converting ads look like catalog shots. They look like dynamic vertical videos showing the product unboxed, held, or demonstrated in action.&lt;/p&gt;

&lt;p&gt;Bridging that gap usually meant hiring a video editor or booking an expensive creator shoot. When you test an automated tool like casttake to turn a static product photo into a video ad, the real bottleneck is deciding which format matches the physical nature of your item before you waste compute credits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why generic video prompts fail on product shots
&lt;/h3&gt;

&lt;p&gt;If you type a vague prompt like "make a viral video ad for this water bottle" into a generic diffusion model, the result is almost always unusable. The AI invents non-existent features, warps the brand logo, or morphs the screw cap into an unrecognizable blob.&lt;/p&gt;

&lt;p&gt;A practical workflow begins by parsing constraints from the image itself. The classifier on casttake reads whether the product is worn on the body, held in a hand, or set on a tabletop, and whether a real human face is already present.&lt;/p&gt;

&lt;p&gt;These constraints prevent ridiculous pairings. A thermal kettle cannot be a try-on haul, and an oversized knit sweater does not need an unboxing teardown. By combining the category scan with two user choices (what the campaign objective is and who appears on camera), the system outputs three targeted formats rather than asking you to write prompt engineering paragraphs from scratch.&lt;/p&gt;

&lt;h3&gt;
  
  
  The three deliverables from a single upload
&lt;/h3&gt;

&lt;p&gt;Depending on where you are in your ad testing cycle, a single photo can generate three distinct outputs with transparent upfront pricing:&lt;/p&gt;

&lt;p&gt;First, a static product scene image ad. The tool extracts your clean product outline and situates it into an authentic environment (like a sunlit kitchen counter or a gym locker bench). At 13 credits (about thirteen cents), this is the fastest way to test product readability in 9:16 or 4:5 aspect ratios.&lt;/p&gt;

&lt;p&gt;Second, a five to fifteen second vertical video ad. The model animates a product demonstration, unboxing beat, or problem-solution hook tailored to the item. This ranges from 70 to 210 credits (seventy cents to two dollars and ten cents).&lt;/p&gt;

&lt;p&gt;Third, a trending template remake, where an established top-performing video script is re-rendered around your product for 210 credits.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When converting a single listing photo into an actionable ad, I used casttake to classify the product constraints and generate a fifteen-second vertical video format for two dollars, keeping in mind that you must always compare the first and last frames against your original photo because generative video models can occasionally alter cap shapes or label text.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The pre-flight check before spending ad budget
&lt;/h3&gt;

&lt;p&gt;Before you push any AI-rendered creative to Meta Ads Manager or TikTok Shop, run two quick quality checks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Check physical packaging consistency. TikTok Shop in particular strictly flags ads where the delivered product looks noticeably different from the video. If the cap color shifted from navy to black, reject the take and re-roll.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verify aspect ratio and disclosure tags. Vertical placements require 9:16 framing with safe zones at the top and bottom. Always mark the content as AI-generated if the target platform mandates synthetic disclosures.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Treating AI ad makers as fast concept filters rather than final magic wands gives e-commerce operators an unfair speed advantage while keeping production budgets under control.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Checked Whether a No-Upload Face Shape App Really Doesn't Upload Your Photo</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Tue, 22 Sep 2026 10:05:06 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-checked-whether-a-no-upload-face-shape-app-really-doesnt-upload-your-photo-32l3</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-checked-whether-a-no-upload-face-shape-app-really-doesnt-upload-your-photo-32l3</guid>
      <description>&lt;p&gt;I stopped using one of those face analysis apps mid-upload once I noticed the network tab in dev tools showing my photo heading to a server I'd never heard of, for an app that had zero explanation of what happened to it after. That's a normal thing to check if you build software for a living, and a genuinely unsettling thing to find.&lt;/p&gt;

&lt;p&gt;After that I only wanted tools where the photo never leaves my device, full stop, not "we delete it after processing" or "encrypted in transit," just nothing sent anywhere. That's a smaller category than you'd think, because running face landmark detection well usually means someone's server doing the heavy lifting.&lt;/p&gt;

&lt;p&gt;measureface is the one I found that actually does this for its free analysis. It runs Google's MediaPipe Face Landmarker as WebAssembly inside the browser tab itself, returning 478 points on your face without any of it touching a server. You can watch the network tab yourself while it runs, which I did, out of habit, and there's nothing to see because there's nothing to send.&lt;/p&gt;

&lt;p&gt;Worth being precise here because "no upload" gets used loosely by a lot of sites. The free analysis, the actual face measurement, genuinely never leaves your browser. There's a separate optional paid feature, a hairstyle visual, and that one does get sent out, to an image generation service, but only after you explicitly agree to it as a distinct step. It's not hidden in fine print, it's a different action you have to opt into on purpose.&lt;/p&gt;

&lt;p&gt;The other thing that made me trust the numbers it gives back, once I'd confirmed the privacy claim, is that whoever built it is upfront about not being a medical or anatomy expert. The about page is signed by one person, a developer in Sydney, who says plainly that every anatomical statement on the site is attributed to a source rather than claimed as his own expertise. That's a strange thing to want from a face measurement tool, but after finding a few citation errors on other face shape sites, an author who says "I checked the paper this number is supposedly from, and it's not actually in there" earned more trust from me than a polished "our team of experts" page would have.&lt;/p&gt;

&lt;p&gt;If you're looking for a face tool that genuinely doesn't upload your photo, check for yourself rather than taking a privacy claim on faith, open dev tools, watch the network tab while it runs, and see if a request with your image actually goes out. That's the only way to know for sure, and it's a two-minute check before you hand any site your face. It's also what made me stick with measureface after the first run, not the claim itself, the fact that checking it was this easy.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The pixel size of a stamp in a document, and the one check before you send it</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Thu, 17 Sep 2026 15:23:38 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/the-pixel-size-of-a-stamp-in-a-document-and-the-one-check-before-you-send-it-53fh</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/the-pixel-size-of-a-stamp-in-a-document-and-the-one-check-before-you-send-it-53fh</guid>
      <description>&lt;p&gt;Someone asks for "a stamp for our invoices", you make one, you send the PNG, and it comes back looking soft and slightly too big. You export it again, larger. Now it is sharp and &lt;em&gt;much&lt;/em&gt; too big. Somewhere in there is a number nobody tells you.&lt;/p&gt;

&lt;p&gt;The number is not a stamp thing. It is the same arithmetic behind every image that has to land at a known physical size in a document.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pixels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millimetres&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;25.4&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dpi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An inch is defined as exactly 25.4 mm, so this is not an estimate. A 35 mm round stamp at 220 dpi is &lt;code&gt;35 / 25.4 * 220&lt;/code&gt; = 303 px. At 96 dpi the same stamp is 132 px. Same stamp, same document, two files that differ by a factor of 2.3 — and the only thing that changed was where it was going.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the dpi number comes from, and where it does not
&lt;/h2&gt;

&lt;p&gt;This is the part I got wrong for a while, so it is worth being precise about what is documented and what is convention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documented:&lt;/strong&gt; Microsoft Office has a default-resolution setting for pictures you insert, with options at 96, 150, 220 and 330 ppi plus "High fidelity". Those numbers are real and they are Microsoft's. What they are &lt;em&gt;for&lt;/em&gt; is compression of images you paste in — they are not a statement about what your artwork must be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Convention, not spec:&lt;/strong&gt; 300 ppi for anything going to a printer. Widely recommended, including by commercial printers, but it is a convention rather than a format requirement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Neither:&lt;/strong&gt; any per-destination table you find that says "Google Docs needs exactly X". I have not found a source for that, and I would treat one with suspicion. What you can say honestly is that a document read on screen needs far fewer pixels than the same document printed, and picking a number in the 150 region for screen-first and 300 for print-first will not embarrass you.&lt;/p&gt;

&lt;p&gt;So: treat the presets as reasonable starting points with an honest provenance, not as requirements. The arithmetic is exact. The dpi you feed it is a judgement call.&lt;/p&gt;

&lt;h2&gt;
  
  
  The failure that actually costs you the job
&lt;/h2&gt;

&lt;p&gt;Not size. Background.&lt;/p&gt;

&lt;p&gt;A stamp is supposed to sit &lt;em&gt;over&lt;/em&gt; text. If the file has an opaque white rectangle behind the ink, it covers whatever it lands on, and the person who receives it will describe this as "it looks wrong" rather than "your alpha channel is missing". Two ways this happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The export never had transparency — a JPEG, for instance, which has no alpha channel at all. There is no fixing this after the fact; it has to be re-exported.&lt;/li&gt;
&lt;li&gt;The export has an alpha channel, but the artwork was drawn on a white fill. Technically transparent, visually a white box.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A cheap check: look at the pixels around the border of the image. If they are fully transparent, the edge is clean. If they are opaque white, you have a box. This does not prove anything about the middle of the image — a white rectangle with a one-pixel transparent border will pass an edge check and still be a white rectangle — so treat it as a fast negative test, not a certificate.&lt;/p&gt;

&lt;p&gt;Worth knowing: partially transparent is its own trap. Alpha 249 out of 255 is 98% opaque, and it will look like a faint white box rather than no box. "Has some transparency" and "has a transparent background" are different claims.&lt;/p&gt;

&lt;h2&gt;
  
  
  PNG or SVG
&lt;/h2&gt;

&lt;p&gt;If the destination will only accept a raster image, PNG, sized with the line above. If it will take vector, SVG, and then the whole question disappears — the renderer resolves it at whatever the output device needs.&lt;/p&gt;

&lt;p&gt;The reason to keep an SVG even when you deliver a PNG is that it stays editable. A year later, when the company name changes, you can fix the file instead of rebuilding it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools
&lt;/h2&gt;

&lt;p&gt;I maintain a couple of browser-side tools for this, both free and neither needing an account:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://stampmakertool.com/digital-stamp-maker" rel="noopener noreferrer"&gt;a stamp maker that sizes the export for its destination&lt;/a&gt; — draw it, enter the physical size and the target, and the PNG downloads at the computed width rather than at some fixed default. It also does the edge check described above.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stampmakertool.com/date-stamp-generator" rel="noopener noreferrer"&gt;a date stamp generator&lt;/a&gt;, if what you need is a dater face. That one has a different trap in it: &lt;code&gt;03/04/2026&lt;/code&gt; is two different days depending on who picks up the paper, which is 132 ambiguous days a year.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything runs in the page; no upload is involved either way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;Compute the pixels instead of guessing, be honest that the dpi figure is a judgement rather than a spec, and check the border pixels before you send the file. That is most of it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I wanted to know my actual canthal tilt, not just "fox eye or not"</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Thu, 17 Sep 2026 02:45:01 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-wanted-to-know-my-actual-canthal-tilt-not-just-fox-eye-or-not-37bk</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-wanted-to-know-my-actual-canthal-tilt-not-just-fox-eye-or-not-37bk</guid>
      <description>&lt;p&gt;Canthal tilt shows up constantly in the fox-eye / hunter-eye makeup trend, always as a vibe rather than a number: "positive tilt" or "negative tilt," decided by eyeballing (no pun intended) a photo. I wanted the actual angle, in degrees, because "positive" covers everything from barely-there to pretty dramatic and I had no idea which end of that range I was on.&lt;/p&gt;

&lt;p&gt;The annoying part of measuring it yourself: you need the two eye corners in a photo where your head isn't tilted, and any head tilt gets read as eye tilt if you don't correct for it. I tried eyeballing it on a screenshot with a protractor app and gave up. That's not a measurement, that's a guess with extra steps.&lt;/p&gt;

&lt;p&gt;I used &lt;a href="https://measureface.com/canthal-tilt-test" rel="noopener noreferrer"&gt;measureface.com's canthal tilt test&lt;/a&gt;, which runs face landmark detection in the browser, finds the actual eye-corner points (inner and outer corner, each eye separately), and corrects for head rotation before giving you the angle. It gives each eye its own number instead of averaging them, which turned out to matter. Mine came back +3° and +6°, close enough to each other that I wouldn't have noticed the difference by eye, but genuinely two different numbers.&lt;/p&gt;

&lt;p&gt;Worth saying plainly: neither of those numbers is "good" or "bad." The tool doesn't score it that way, which I appreciated, because the fox-eye trend treats a bigger positive number as better, and that's a style preference, not a fact about a face. What I actually wanted was just to know the number instead of guessing at a label.&lt;/p&gt;

&lt;p&gt;One accuracy note the tool itself flags: it tells you how precisely it could resolve the angle before giving you the number, so a blurry or off-angle photo gets a wider margin instead of a falsely confident figure. Worth using a straight-on, evenly lit photo if you want the tightest reading.&lt;/p&gt;

&lt;p&gt;If you've seen "canthal tilt" thrown around online and never had an actual measurement to attach to it, this is a five-minute way to get one.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I filmed the clip in my bedroom, not in front of a green screen. Here's what actually worked.</title>
      <dc:creator>Jim L</dc:creator>
      <pubDate>Thu, 17 Sep 2026 01:14:35 +0000</pubDate>
      <link>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-filmed-the-clip-in-my-bedroom-not-in-front-of-a-green-screen-heres-what-actually-worked-1m9p</link>
      <guid>https://dev.to/jim_l_efc70c3a738e9f4baa7/i-filmed-the-clip-in-my-bedroom-not-in-front-of-a-green-screen-heres-what-actually-worked-1m9p</guid>
      <description>&lt;p&gt;I filmed the clip in my bedroom, not in front of a green screen. Here's what actually worked.&lt;/p&gt;

&lt;p&gt;Most "remove video background" tutorials assume you set the shot up first: a green cyclorama, two softboxes, maybe a C-stand. I didn't. I had a talking-head clip shot against a beige wall with a lamp in the corner, and I needed the background gone for a slide deck.&lt;/p&gt;

&lt;p&gt;Traditional chroma key can't help here. There's no green to key out. What you actually need is a model that finds the subject on every frame instead of subtracting a color. That's the difference between "green screen removal" (subtracting a known color) and "background removal" (segmenting a person frame by frame, regardless of what's behind them).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I tried first&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I tried cutting a still frame in Photoshop and reusing the mask across the timeline. Doesn't work once the subject moves even slightly, edges drift. I tried a rotoscoping plugin in my NLE next. Technically possible, but it took over an hour for a 20-second clip, and the hair edges looked like they'd been through a paper shredder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What worked&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I ended up using &lt;a href="https://removebackgroundfromvideo.com/remove-background-from-video-without-green-screen" rel="noopener noreferrer"&gt;removebackgroundfromvideo.com's no-green-screen tool&lt;/a&gt;. You upload the clip as shot (MP4/MOV/WebM, up to 30s and 100MB on the free tier) and it segments the subject per frame instead of keying a color. A 30-second clip took about 5 minutes. I could tab away and come back.&lt;/p&gt;

&lt;p&gt;The honest caveat: hair and fine detail still aren't perfect. My curls kept a faint halo from the room light, and a plant leaf behind my head left a slight green smear on one frame. If you need broadcast-grade edges on flyaway hair, you're still better off with a proper green screen. For a slide-deck talking head or a product demo where "good enough at normal viewing distance" is the bar, it held up fine.&lt;/p&gt;

&lt;p&gt;One thing I'd flag before you commit: check what file format you actually need before you spend credits. I wasted my first attempt exporting a green-screen MP4 when I actually needed a transparent WebM for a web page, and the tool offers four output types (transparent WebM, ProRes 4444 MOV, green-screen MP4, alpha mask) and picking the wrong one means redoing it.&lt;/p&gt;

&lt;p&gt;If your footage was shot in an ordinary room and you don't want to reshoot, this is the category of tool to look at. The constraint isn't your studio setup anymore. It's how well the segmentation model handles your specific edges.&lt;/p&gt;

</description>
    </item>
    <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>
  </channel>
</rss>
