<?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: 尚毅段</title>
    <description>The latest articles on DEV Community by 尚毅段 (@succday).</description>
    <link>https://dev.to/succday</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%2F4203752%2F546e0e9c-7bef-4b5f-87cf-f5a5d8eee8d1.png</url>
      <title>DEV Community: 尚毅段</title>
      <link>https://dev.to/succday</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/succday"/>
    <language>en</language>
    <item>
      <title>A same-word game that runs in the browser: state, scoring, and the tie problem</title>
      <dc:creator>尚毅段</dc:creator>
      <pubDate>Sat, 14 Nov 2026 01:32:53 +0000</pubDate>
      <link>https://dev.to/succday/a-same-word-game-that-runs-in-the-browser-state-scoring-and-the-tie-problem-39cl</link>
      <guid>https://dev.to/succday/a-same-word-game-that-runs-in-the-browser-state-scoring-and-the-tie-problem-39cl</guid>
      <description>&lt;p&gt;Two players join a room, get the seed word "moon", and type a word each in secret. If both write "night", they score. If one writes "night" and the other writes "star", the round ends with nothing, even though both answers are perfectly good associations.&lt;/p&gt;

&lt;p&gt;That gap is the whole game. I built SameWord, a word-association game for two to four players that runs in a browser tab with no account and no install. The interesting part was never comparing two strings. It was deciding what a round is, how a round is won, and what happens when the room does not agree.&lt;/p&gt;

&lt;p&gt;Here are the three parts that took the most thought.&lt;/p&gt;

&lt;h2&gt;
  
  
  A round has one state, and everyone shares it
&lt;/h2&gt;

&lt;p&gt;A game is five rounds. Each round has the same shape: the server picks a seed word, every player submits exactly one word, then everything is revealed at once.&lt;/p&gt;

&lt;p&gt;The reveal is the only moment anything is shared. Before that, the room shows a counter like "2 of 3" and nothing else. Nobody can see which words are in, so nobody can copy an answer. When the last player submits, or the clock hits zero, the words appear together with the name attached to each.&lt;/p&gt;

&lt;p&gt;Two timers have to agree for that to work: the round clock (30 or 60 seconds, chosen when the room is created) and the reveal. The round clock is the authoritative one. If it hits zero with someone still typing, the round is scored on the words that arrived; an empty slot is skipped rather than filled with a placeholder. That rule matters in practice, because a four-player room with a 60-second clock will almost never have everyone submit early.&lt;/p&gt;

&lt;p&gt;The host presses Start on each round, which creates an obvious failure mode: a distracted host freezes the room. The reveal advances on its own 20 seconds after it appears, so the game keeps moving even if nobody clicks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two ways to win, and no partial credit
&lt;/h2&gt;

&lt;p&gt;A round scores when one of two things is true.&lt;/p&gt;

&lt;p&gt;A match: every submitted word is the same word. The comparison trims spaces and ignores capital letters, so "MOON" and "  moon " are the same. Plurals are not. "rabbit" and "rabbits" are different answers, and so are "ocean" and "sea", because the game cannot score a synonym as a match on its own.&lt;/p&gt;

&lt;p&gt;The second path is the same-meaning confirm. The words differ, but every online player taps a button saying they treat the words as one answer. Then the round counts.&lt;/p&gt;

&lt;p&gt;That button exists because word matching fails exactly where language is interesting. Plural forms, synonyms, and typos are all things a room can agree on and a string comparison cannot. But a confirm that any one player could trigger would be a free point, so it needs unanimity.&lt;/p&gt;

&lt;p&gt;There is no partial credit. A round is a win or it is not, and the result screen counts wins out of five. Players who want a finer signal have asked for per-round closeness scores; I left them out because "you were sort of close" turns a five-round game into a spreadsheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tie problem is the default, not the edge case
&lt;/h2&gt;

&lt;p&gt;The seed for round two comes from round one. After a win, the next seed is the word the room agreed on. After a no-match round, the next seed is the word that appeared most often.&lt;/p&gt;

&lt;p&gt;That rule has a hole, and the hole is the normal path whenever two people play.&lt;/p&gt;

&lt;p&gt;In a two-player room with no match, the two words appear once each. The frequency is 1 to 1 every single time, so "most frequent" never picks a winner. Three players can produce a three-way tie; four players tie two and two quite often. A tie-breaker is not a rare branch in this game, it is the road most rounds take.&lt;/p&gt;

&lt;p&gt;The rule I settled on: when words are tied on frequency, the word that was submitted first becomes the seed. It is deterministic, it needs no extra round, and every client can compute it from the same reveal data.&lt;/p&gt;

&lt;p&gt;The cost is real. Submission order is a function of typing speed and network latency, so in a two-player game the next seed is often decided by who was faster rather than by anything about the words. A player who types immediately after the seed appears gets to steer the following round. I considered three alternatives. A random pick from the tied words is fairer but makes the game feel arbitrary. Replaying the round punishes everyone for a tie. Carrying the previous seed forward breaks the chain that gives round two its context.&lt;/p&gt;

&lt;p&gt;None of those were clearly better, so the fast-finger rule stays. If I were starting over, I would show the tie resolution on screen instead of resolving it silently. Players already suspect the seed is not random; telling them the rule is cheaper than letting them guess.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unanimity breaks before anything else does
&lt;/h2&gt;

&lt;p&gt;The same-meaning confirm asks every online player. With two people that is two taps and a small cost. With four it is the most fragile part of the game, because one player who does not tap turns a round everyone else agreed on into a no-match.&lt;/p&gt;

&lt;p&gt;"Online player" is doing quiet work in that sentence. Someone who closed the tab cannot confirm, so they cannot block a round either. Someone who is still connected but walking away can. The rules put no timer on the confirm, so a four-player room can stall on a decision that three people already made.&lt;/p&gt;

&lt;p&gt;I have not solved that one. A majority rule would make the four-player mode feel fairer, but it would also let two players outvote the third, and the entire game is built on the idea that the room is the unit, not the individual.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a browser-only room actually costs
&lt;/h2&gt;

&lt;p&gt;No accounts means the room code is the only shared object: six characters generated when the room is created, copied into whatever chat the group already uses. There is nothing to install and nothing to sign up for, and the host's player list is the only social proof that anyone is there.&lt;/p&gt;

&lt;p&gt;The constraint shows up in small places. Words are capped at 24 characters and limited to letters, spaces, hyphens and apostrophes, which keeps the comparison simple and stops the input from becoming a message box. The one-phone mode exists for the same reason: two people, one device, hand it over between turns, words stay hidden until the reveal.&lt;/p&gt;

&lt;p&gt;None of this is exotic. A five-round game with a room code and a countdown is about as small as a multiplayer browser game gets. The state machine, the unanimity rule, and the tie-breaker are where the game actually lives, and all three are decisions about what the room is allowed to disagree on.&lt;/p&gt;

&lt;p&gt;SameWord is free at &lt;a href="https://playsameword.com" rel="noopener noreferrer"&gt;playsameword.com&lt;/a&gt;, and the rules are written up at &lt;a href="https://playsameword.com/how-to-play/" rel="noopener noreferrer"&gt;playsameword.com/how-to-play&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>gamedev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Book cover sizes that actually break at upload</title>
      <dc:creator>尚毅段</dc:creator>
      <pubDate>Fri, 13 Nov 2026 01:26:29 +0000</pubDate>
      <link>https://dev.to/succday/book-cover-sizes-that-actually-break-at-upload-1n99</link>
      <guid>https://dev.to/succday/book-cover-sizes-that-actually-break-at-upload-1n99</guid>
      <description>&lt;p&gt;A cover that looks finished can still fail at the KDP upload step. When it does, the error is usually not about the artwork. It is a number that came from a different version of the book.&lt;/p&gt;

&lt;p&gt;I maintain the sizing calculator at BookCoverGen, and the same handful of mismatches show up in support mail. Here they are in the order they cost people the most time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The only arithmetic that matters
&lt;/h2&gt;

&lt;p&gt;A print cover is one flat file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;width = panel + panel + spine + 0.25 in&lt;/li&gt;
&lt;li&gt;height = trim height + 0.25 in&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 0.25 in is 0.125 in of bleed on each outside edge. The panels come from the trim size. The spine comes from page count times paper thickness.&lt;/p&gt;

&lt;p&gt;For 6 x 9 in at 300 pages on black-and-white white paper, KDP's per-page figure is 0.002252 in, so the spine is 0.676 in and the full wrap is 12.93 x 9.25 in. Every case below is that calculation going wrong in a different place.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Your page count changed after the cover was built
&lt;/h2&gt;

&lt;p&gt;This one gets caught in the previewer, not at your desk.&lt;/p&gt;

&lt;p&gt;Re-paginate a manuscript and the spine moves. 6 x 9 at 250 pages on white paper is 0.563 in. At 300 pages it is 0.676 in. That is 0.113 in, close enough to an eighth of an inch, and it lands exactly where the author name sits on the spine. On a fold, an eighth of an inch is the difference between centered and cut.&lt;/p&gt;

&lt;p&gt;Build the cover after the final proof, not after the first draft. If the interior changes, re-run the calculation before the next upload.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The paper changed, the cover did not
&lt;/h2&gt;

&lt;p&gt;KDP's spine math is per paper type:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;black-and-white white paper: 0.002252 in per page&lt;/li&gt;
&lt;li&gt;black-and-white cream paper: 0.002500 in per page&lt;/li&gt;
&lt;li&gt;premium color white paper: 0.002347 in per page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At 300 pages the white-paper spine is 0.676 in. The same 300 pages on cream is 0.750 in. The file has to grow by 0.074 in, and the front and back panels shift outward with it. Switch paper at the pricing step and keep the old cover, and the spine type is off the fold.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The file has no bleed, or bleed on two edges
&lt;/h2&gt;

&lt;p&gt;A print file is trimmed after it is printed. The artwork has to run past the trim line on the top, bottom and outside edges, which adds 0.25 in to both dimensions.&lt;/p&gt;

&lt;p&gt;Two common versions of this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the file is built at trim size (12 x 9 in for 6 x 9 at 300 pages, not 12.93 x 9.25 in);&lt;/li&gt;
&lt;li&gt;the designer adds bleed at the outer edges of the front and back panels but not across the spine wrap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both look fine on screen, because the missing strip is white and the background is white. The previewer is the first place the trim sliver shows up, and a background that stops at trim size will show a hairline at the cut.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The ebook cover was exported from the print panel
&lt;/h2&gt;

&lt;p&gt;Ebooks have no spine, no bleed and no back cover. KDP asks for a front cover of 1,600 x 2,560 px at a 1.6 aspect ratio, JPEG or TIFF, under 50 MB.&lt;/p&gt;

&lt;p&gt;The print panel for 6 x 9 in at 300 DPI is 1,800 x 2,700 px. The ratio is 1.5, not 1.6, so it does not simply scale down. What happens next depends on the store: the image gets cropped, padded, or rendered smaller in the thumbnail grid than a properly sized file. Export the ebook cover at the pixel size, separately from the print export.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Spine text on a book that will not print it
&lt;/h2&gt;

&lt;p&gt;KDP prints spine text only above 79 pages. Below that the spine stays blank, so artwork should run through it and type should not be there at all. Type placed on a 40-page file does not appear in print; if the page count later grows past 79, the old file still has type set for a spine width it no longer has.&lt;/p&gt;

&lt;p&gt;When there is spine text, it needs 0.0625 in clear on each side of the fold. Thin books have thin margins. Check the template before the title goes on the spine.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. More than one page, fonts not embedded, images below 300 DPI
&lt;/h2&gt;

&lt;p&gt;These are the boring checks that produce failed preflight:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the wrap is one page: back cover, spine, front cover, never three separate files;&lt;/li&gt;
&lt;li&gt;fonts embedded, not linked;&lt;/li&gt;
&lt;li&gt;images at 300 DPI at final size;&lt;/li&gt;
&lt;li&gt;one flattened layer, no live transparency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The barcode area on the back cover has to stay clear. The template marks where it goes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before you upload, check these six
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Final page count, after the last proof.&lt;/li&gt;
&lt;li&gt;The paper type you will actually print on.&lt;/li&gt;
&lt;li&gt;Full wrap = panels + spine + 0.25 in.&lt;/li&gt;
&lt;li&gt;Bleed 0.125 in on the top, bottom and outside edges.&lt;/li&gt;
&lt;li&gt;Spine text only over 79 pages, 0.0625 in clear on each side.&lt;/li&gt;
&lt;li&gt;Ebook cover exported at 1,600 x 2,560 px, separate from the print wrap.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;KDP publishes the current figures and changes them. The calculator on our site runs the same arithmetic with your page count and exports a layout guide at 1 unit = 1 inch, but the printer's template is the final word. When a file fails at upload, the error text is usually accurate about which of these six it is.&lt;/p&gt;

</description>
      <category>books</category>
      <category>design</category>
      <category>selfpublishing</category>
      <category>print</category>
    </item>
    <item>
      <title>Modeling 33 weapons 9 classes as data (not screenshots)</title>
      <dc:creator>尚毅段</dc:creator>
      <pubDate>Thu, 12 Nov 2026 01:24:40 +0000</pubDate>
      <link>https://dev.to/succday/modeling-33-weapons-x-9-classes-as-data-not-screenshots-1c8j</link>
      <guid>https://dev.to/succday/modeling-33-weapons-x-9-classes-as-data-not-screenshots-1c8j</guid>
      <description>&lt;h1&gt;
  
  
  Modeling 33 weapons × 9 classes as data (not screenshots)
&lt;/h1&gt;

&lt;p&gt;Most camo trackers are a grid of screenshots. You scroll, you find your weapon, you count boxes with your eyes, and when the game patches something the images are wrong until someone re-uploads them.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://mw4camotracker.com/" rel="noopener noreferrer"&gt;MW4 Camo Tracker&lt;/a&gt; the other way: the whole grind is one JSON dataset, and every screen renders from it. Here is the shape of that data and the parts worth reusing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data is a tree with three levels
&lt;/h2&gt;

&lt;p&gt;The top level is class: assault rifles (8), submachine guns (5), shotguns, light machine guns (3), marksman rifles (3), sniper rifles (3), pistols (4), launchers (4), melee. That is 33 weapons.&lt;/p&gt;

&lt;p&gt;Each weapon owns an ordered list of camo rows. Order matters, because the game unlocks in a fixed sequence: military camos first, then the 99 special camo challenges, then gold, platinum, harmonic break, divergence, and the mastery set on top. The site exposes 473 checkable rows in total, and every row has a stable id built from weapon + camo, not an array index.&lt;/p&gt;

&lt;p&gt;That last decision saves a lot of pain. Array indexes shift the moment a patch adds or removes a camo, and any saved progress then lands on the wrong row. A synthetic key like &lt;code&gt;m4-gold&lt;/code&gt; survives reordering.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// rows are generated at build time from the dataset, ids are derived, never positional&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;rowId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weapon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="sb"&gt;`${weapon.slug}-${camo.slug}`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same reason the dataset keeps the class list as a separate table. Nine classes is small enough to inline, but the sidebar, the filters and the sitemap all read from one array instead of repeating the list three times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not screenshots
&lt;/h2&gt;

&lt;p&gt;Screenshots are easy to produce and cheap to look at once, but they carry cost that grows quietly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A 1400px webp per weapon is fine for one page and painful when every weapon page needs its own hero image.&lt;/li&gt;
&lt;li&gt;You cannot compute anything from an image: no percentage, no "next unfinished row", no sort by challenge type.&lt;/li&gt;
&lt;li&gt;Screen readers get nothing. Text rows can be tabbed, labelled and announced.&lt;/li&gt;
&lt;li&gt;After a patch, every changed row means an image edit. Text means one JSON diff.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The counterargument is that screenshots show the actual game UI and users trust that. That is fair — but the trust comes from the weapon names and camo names matching the game, not from the image format. A text row that says "Gold — 0/1" carries the same fact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Progress state lives in the browser
&lt;/h2&gt;

&lt;p&gt;Every tick is stored locally and the page renders from that store. The schema is one object: dataset version plus a map of row id to timestamp.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"2026-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"m4-gold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1762361000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"ak74-platinum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1762361402000&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;Two details that matter more than they look:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dataset version is stored with progress.&lt;/strong&gt; When the dataset changes, the app can tell whether a missing row was completed or removed. Without it, a patch silently resets partial progress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writes are debounced and total count is rendered from the map.&lt;/strong&gt; No separate counter to get out of sync. The header says 0 / 473 because it counted the map on render, and the map is the only source of truth.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The tradeoff is device-local state: clear your browser data and the grind is gone. That is why the site also offers a Google sign-in to sync, and an export the user can keep. Local-first with an explicit sync opt-in beats an account wall in front of a checklist, and it keeps the first visit fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "next challenge" suggestion is rule-based, on purpose
&lt;/h2&gt;

&lt;p&gt;The site suggests an unlock order. It is generated from the published camo order plus the rows you already ticked. It does not claim to know which challenge is easiest for you, because that depends on how you play. The copy on the page says so.&lt;/p&gt;

&lt;p&gt;That distinction is worth writing down in the product, not just in a code comment. A tool that says "easiest" and gets it wrong loses trust on the second weapon.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do differently
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I started with a flat array per weapon and had to migrate. The synthetic id should have been there from day one.&lt;/li&gt;
&lt;li&gt;I kept the class order in the component. It belongs in the dataset next to the weapons.&lt;/li&gt;
&lt;li&gt;I underestimated how much of the UI is just "does this row have a timestamp". A single derived selector would have replaced three separate conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is novel architecture. It is the same argument as any catalog app: store facts, render views, keep ids stable, and let the data survive the next patch. The camo grid just makes the argument easy to see, because the whole product is one long checklist.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>datamodel</category>
      <category>gaming</category>
    </item>
    <item>
      <title>Cache-read prices are where LLM bills quietly diverge: 50 models compared</title>
      <dc:creator>尚毅段</dc:creator>
      <pubDate>Wed, 11 Nov 2026 04:35:29 +0000</pubDate>
      <link>https://dev.to/succday/cache-read-prices-are-where-llm-bills-quietly-diverge-50-models-compared-2mak</link>
      <guid>https://dev.to/succday/cache-read-prices-are-where-llm-bills-quietly-diverge-50-models-compared-2mak</guid>
      <description>&lt;p&gt;Most LLM price pages lead with input and output cost per million tokens. That number is easy to compare and easy to misread. Cache reads change the bill by a factor of 20 to 50, and the discount is not uniform across vendors, so two models with the same input price can end up far apart once prompts get reused.&lt;/p&gt;

&lt;p&gt;We keep a price table of 55 models across OpenAI, Anthropic, Google, DeepSeek, xAI and others, checked on 2026-11-11 against each vendor's pricing page. This post pulls out one column that rarely gets compared: what a cached input token costs relative to a fresh one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The spread
&lt;/h2&gt;

&lt;p&gt;Fifty of the 55 tracked models publish a cache-read price. The ratio to standard input ranges from 2% to 5%.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Input $/1M&lt;/th&gt;
&lt;th&gt;Cached $/1M&lt;/th&gt;
&lt;th&gt;Cached share of input&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek Flash (V4.1)&lt;/td&gt;
&lt;td&gt;0.30&lt;/td&gt;
&lt;td&gt;0.006&lt;/td&gt;
&lt;td&gt;2.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Fable 5.2&lt;/td&gt;
&lt;td&gt;8.00&lt;/td&gt;
&lt;td&gt;0.20&lt;/td&gt;
&lt;td&gt;2.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Fable 5.1&lt;/td&gt;
&lt;td&gt;10.00&lt;/td&gt;
&lt;td&gt;0.25&lt;/td&gt;
&lt;td&gt;2.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepSeek V4 Pro&lt;/td&gt;
&lt;td&gt;1.32&lt;/td&gt;
&lt;td&gt;0.044&lt;/td&gt;
&lt;td&gt;3.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-6.1 Terra&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;td&gt;0.05&lt;/td&gt;
&lt;td&gt;5.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-6.1 Sol&lt;/td&gt;
&lt;td&gt;2.00&lt;/td&gt;
&lt;td&gt;0.10&lt;/td&gt;
&lt;td&gt;5.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 5.5&lt;/td&gt;
&lt;td&gt;2.00&lt;/td&gt;
&lt;td&gt;0.10&lt;/td&gt;
&lt;td&gt;5.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 4 Carbon&lt;/td&gt;
&lt;td&gt;2.00&lt;/td&gt;
&lt;td&gt;0.10&lt;/td&gt;
&lt;td&gt;5.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Opus 5.5&lt;/td&gt;
&lt;td&gt;4.00&lt;/td&gt;
&lt;td&gt;0.20&lt;/td&gt;
&lt;td&gt;5.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 2% tier is not the same product as the 5% tier. A 2% cache read means a repeated 100K-token prompt costs 2% of what the first pass cost; at 5% it costs 5%. Over a long agent run that difference is the difference between a workflow that pays for itself and one that does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five models publish no cache price
&lt;/h2&gt;

&lt;p&gt;Mistral Small 4, Codestral 25.08, and the Ministral 3 family (14B, 8B, 3B) list no cache-read rate. That does not mean they are expensive. It means you cannot model a cached workload from the public price page alone, and any comparison that assumes one is guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this changes in practice
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Compare cache ratios before you compare headline prices. A model at $1 input with a 5% cache read can cost more than a $2 model at 2% once the same context is reused a few times.&lt;/li&gt;
&lt;li&gt;Watch the long-context surcharge. GPT-6 Astra is $10/$50 per million up to 272K input and $20/$75 beyond it, which moves more than the cache discount saves.&lt;/li&gt;
&lt;li&gt;Re-check monthly. This table moved on every check we ran between 2026-11-04 and 2026-11-11.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The full table, with per-model sources and checked dates, is at &lt;a href="https://aiapicostcalc.com/" rel="noopener noreferrer"&gt;AI API Cost Calc&lt;/a&gt;. If you spot a price that has drifted, the site links every vendor page it was taken from.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>api</category>
      <category>cost</category>
    </item>
    <item>
      <title>How to Play the Same Word Game: Rules for 2–4 Players, Scoring, and the Part the TikToks Skip</title>
      <dc:creator>尚毅段</dc:creator>
      <pubDate>Mon, 09 Nov 2026 10:09:15 +0000</pubDate>
      <link>https://dev.to/succday/how-to-play-the-same-word-game-rules-for-2-4-players-scoring-and-the-part-the-tiktoks-skip-ced</link>
      <guid>https://dev.to/succday/how-to-play-the-same-word-game-rules-for-2-4-players-scoring-and-the-part-the-tiktoks-skip-ced</guid>
      <description>&lt;p&gt;The same word game is the two-player word game that spread through Douyin and TikTok in early November: every player gets one seed word, each player secretly writes a single word they associate with it, then the words are revealed. If two people wrote the same word, they score the round.&lt;/p&gt;

&lt;p&gt;Most clips online show the fun part and skip the rules. These are the exact rules we built into a free browser version at &lt;a href="https://playsameword.com/" rel="noopener noreferrer"&gt;playsameword.com&lt;/a&gt;, plus the house variants we ended up using.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need before you start
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;2 to 4 players&lt;/strong&gt;, each with their own phone or laptop. Words are submitted secretly, so one shared screen does not work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A room code.&lt;/strong&gt; The host creates a room and gets a 6-character code; everyone else joins with the code or a share link.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;30 or 60 seconds per round.&lt;/strong&gt; 60 seconds is the better setting for kids and for anyone playing in a second language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A game lasts 5 rounds.&lt;/strong&gt; That is about 5 to 8 minutes with the reveal pauses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How one round works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The game shows everyone the same seed word. The built-in list includes words like moon, ocean, fire, rabbit and winter.&lt;/li&gt;
&lt;li&gt;Each player types one associated word, 1 to 24 characters. Letters, spaces, hyphens and apostrophes are allowed; anything else is rejected before it reaches the server.&lt;/li&gt;
&lt;li&gt;When every player has submitted, or the timer hits zero, all words are revealed at once.&lt;/li&gt;
&lt;li&gt;The round is scored as an exact match, a synonym, or nothing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Players who do not submit in time simply sit the round out. The game does not fill in a word for them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scoring, including the part the TikToks skip
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Exact match.&lt;/strong&gt; Both words are normalized (lowercased, spaces trimmed) and compared. &lt;code&gt;Moon&lt;/code&gt; and &lt;code&gt;moon&lt;/code&gt; count as the same word. This is the main way to score.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Synonym.&lt;/strong&gt; If the words are different, every online player can click "these mean the same thing." If everyone agrees, the round counts as a success. This exists because two people can hold the same idea and still type ocean and sea. Without the vote, those rounds would be scored as misses, which feels wrong and makes groups stop playing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The next seed word.&lt;/strong&gt; After a successful round, the winning word becomes the seed for the next round, so the chain drifts toward whatever the group agreed on. After a failed round, the most-submitted word becomes the next seed. With 2 players and a tie, the word submitted first wins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The result page&lt;/strong&gt; lists matches out of 5, the words from every round, and the full seed chain. If you want to compare games later, the chain is the interesting part: it shows how far the group travelled from the first word.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four things that decide whether you score
&lt;/h2&gt;

&lt;p&gt;Round one is harder than it looks because the obvious answer feels too obvious to write.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Write the most obvious word, not the cleverest one.&lt;/strong&gt; Obvious words are shared words. A clever association is almost always personal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick your first association, not your third.&lt;/strong&gt; Most players scan the seed, reject the first word as too easy, and land on something only they would say.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concrete beats abstract.&lt;/strong&gt; Pizza is a shared word. Hunger is not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In 3–4 player games, use the synonym vote early.&lt;/strong&gt; One player writing a slightly different word should not kill a round that everyone can see was the same idea.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  House variants worth trying
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;60-second rounds&lt;/strong&gt; when the group includes younger players or people playing in a second language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme rounds.&lt;/strong&gt; Agree before the game that every association has to be food, a city, or a movie title.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best of three.&lt;/strong&gt; Five rounds is short; three games takes about 15 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-word strictness.&lt;/strong&gt; Enforce it strictly if you want faster rounds; allowing two-word phrases makes matching much easier.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where to play
&lt;/h2&gt;

&lt;p&gt;The free version is at &lt;a href="https://playsameword.com/" rel="noopener noreferrer"&gt;playsameword.com&lt;/a&gt;. No account, no install, runs in the browser on phones and desktops. There is a Chinese version at &lt;a href="https://playsameword.com/zh/" rel="noopener noreferrer"&gt;playsameword.com/zh/&lt;/a&gt; if your group mixes languages, and the two pages link to each other.&lt;/p&gt;

&lt;p&gt;Full disclosure: we built the site. The rules above are free to copy into your own group chat, and the scoring detail is here because most clips leave it out.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>webdev</category>
      <category>showdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>What makes a photo usable for a tattoo stencil (and what doesn't)</title>
      <dc:creator>尚毅段</dc:creator>
      <pubDate>Sat, 24 Oct 2026 03:13:36 +0000</pubDate>
      <link>https://dev.to/succday/what-makes-a-photo-usable-for-a-tattoo-stencil-and-what-doesnt-4j2p</link>
      <guid>https://dev.to/succday/what-makes-a-photo-usable-for-a-tattoo-stencil-and-what-doesnt-4j2p</guid>
      <description>&lt;p&gt;Most "photo to tattoo" attempts fail for a reason that has nothing to do with the model: &lt;strong&gt;the photo was never going to survive the conversion&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A tattoo stencil is not a filtered photo. It is a line drawing at a fixed physical size, printed at 300 DPI, that an artist will transfer onto skin and cut into. Every decision before that point either supports the drawing or destroys it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a stencil actually needs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Closed, continuous outlines.&lt;/strong&gt; A stencil is transferred through the outline. Gaps mean the artist improvises.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified interior detail.&lt;/strong&gt; Shading in the reference becomes either solid black or nothing — a stencil cannot hold a gradient.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Known physical size.&lt;/strong&gt; 300 DPI at 10 cm is a different drawing from 300 DPI at 20 cm. Line weight has to scale with it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No background.&lt;/strong&gt; The photo's room, floor and furniture are not part of the tattoo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the pipeline is roughly: remove the background, find the subject's silhouette, simplify interior edges to a consistent line weight, and export at print resolution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why fur and foliage break it
&lt;/h2&gt;

&lt;p&gt;Edges that are &lt;em&gt;textured&lt;/em&gt; are the hard case. Fur, hair, leaves, lace — each strand is a real edge, and a naive edge detector turns them into thousands of tiny closed shapes. The result looks like static, and no artist will tattoo it.&lt;/p&gt;

&lt;p&gt;What works instead: treat the silhouette as the outline, treat interior detail as a handful of shapes, and let the artist decide the rest. A dog portrait stencil is not every hair; it is the ear shape, the eye, the muzzle line and the collar.&lt;/p&gt;

&lt;h2&gt;
  
  
  The photo checklist
&lt;/h2&gt;

&lt;p&gt;Before uploading anything:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One subject&lt;/strong&gt;, filling most of the frame&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Even light&lt;/strong&gt; — a hard shadow across the face becomes a hard line in the stencil&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plain-ish background&lt;/strong&gt; — it gets removed, but busy backgrounds confuse the mask&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sharp focus&lt;/strong&gt;, especially at the edges you care about (eyes, ears, letters)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No filter.&lt;/strong&gt; Contrast that looks good on a phone screen turns into a mess of black shapes at print resolution.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What people actually ask for
&lt;/h2&gt;

&lt;p&gt;The three requests that come up constantly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;a pet&lt;/strong&gt; — usually a memorial piece. Emotional, and the photo is often the only one they have.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;a face&lt;/strong&gt; — portraits are the hardest, because a small error in the eyes reads instantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;handwriting or a keepsake&lt;/strong&gt; — the easiest, if the source is a clean scan or a sharp photo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are building something in this space, the useful product decision is not "more styles". It is &lt;strong&gt;letting people preview before paying&lt;/strong&gt;, and being honest about which photos will not work. A free preview that says "this one is too dark, try another" saves both sides a refund.&lt;/p&gt;

&lt;h2&gt;
  
  
  The print side
&lt;/h2&gt;

&lt;p&gt;A stencil that looks fine on screen and prints at the wrong size is worse than no stencil. Fixed 300 DPI, A4 by default, and the subject scaled to a stated physical size — those three constraints remove most of the support tickets.&lt;/p&gt;

&lt;p&gt;That is the whole product at &lt;a href="https://tattoostencil.ink" rel="noopener noreferrer"&gt;the Tattoo Stencil tool&lt;/a&gt;: upload a photo, get clean lines, download a print-ready PDF. Free preview, pay only for the high-resolution file.&lt;/p&gt;

&lt;p&gt;The related one, &lt;a href="https://tattoofromphoto.ink" rel="noopener noreferrer"&gt;the photo-to-line-art tool&lt;/a&gt;, skips the stencil and just produces line art you can take to an artist as a reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  The general lesson
&lt;/h2&gt;

&lt;p&gt;Every "photo to X" tool is really a &lt;strong&gt;constraint problem&lt;/strong&gt;. For video it is timing and motion. For a stencil it is line weight and DPI. The model is the easy part; knowing what the output must satisfy is the product.&lt;/p&gt;

</description>
      <category>design</category>
      <category>tutorial</category>
      <category>ai</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Turning an old photo into a moving clip: the model side nobody explains</title>
      <dc:creator>尚毅段</dc:creator>
      <pubDate>Sat, 24 Oct 2026 03:13:27 +0000</pubDate>
      <link>https://dev.to/succday/turning-an-old-photo-into-a-moving-clip-the-model-side-nobody-explains-1d3j</link>
      <guid>https://dev.to/succday/turning-an-old-photo-into-a-moving-clip-the-model-side-nobody-explains-1d3j</guid>
      <description>&lt;p&gt;The "sorry I lied" format is not a video trend. It is a &lt;em&gt;confession&lt;/em&gt; format that happens to move.&lt;/p&gt;

&lt;p&gt;It goes like this: a childhood photo, then a few lines that take the flattering memory apart — &lt;em&gt;I lied, my hair was down. I lied, the dress was not that cute. I lied, that was actually my little brother&lt;/em&gt; — and the last slide gives the real photo back. The joke is that the memory was never the version you told.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a near-static clip is the right template
&lt;/h2&gt;

&lt;p&gt;Most AI video work is about motion: dance, sport, action. This one is the opposite. The emotional register is slow. A camera push-in, a bit of grain, and the photo holding still is &lt;em&gt;more&lt;/em&gt; correct than movement.&lt;/p&gt;

&lt;p&gt;So the reference clip is not a dance routine — it is a slow zoom on a single face. That makes it the easiest trend of the three to serve, and the easiest to get wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Too much motion&lt;/strong&gt; and it reads as a jump-scare, not nostalgia.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A cropped face&lt;/strong&gt; loses the costume, which is the entire joke.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sharp modern lighting&lt;/strong&gt; kills the film look the format depends on.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The audio decision nobody wants to make
&lt;/h2&gt;

&lt;p&gt;Every trend has a sound, and the sound is half the post. Two options:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ship the clip with music baked in.&lt;/strong&gt; Feels generous. Gets you: a fixed track that is stale in two weeks, a takedown risk, and posts muted by the platform for reusing audio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ship a silent MP4 and tell people to attach the trend sound on TikTok.&lt;/strong&gt; Feels cheap. Gets you: a clip that rides the current sound, no licensing exposure, and the same workflow every editor already uses.&lt;/p&gt;

&lt;p&gt;I picked silent, and made it the answer to the FAQ's first question ("Why is the clip silent?") so it reads as a feature, not a limitation. The clip is a clean canvas; the sound is the user's choice and the platform's distribution mechanism.&lt;/p&gt;

&lt;p&gt;If you do ship audio: &lt;strong&gt;never&lt;/strong&gt; ship a track you did not license. A muted post is the best case.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the model does to an old photo
&lt;/h2&gt;

&lt;p&gt;Two things worth knowing before you promise anything:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It re-renders the scene.&lt;/strong&gt; Grandma's living room will come back as a plausible living room, not the actual one. This is usually good — the alternative is a blurry crop of the original background — but it is not a restoration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low-resolution sources are fine, up to a point.&lt;/strong&gt; A phone photo of a printed photo works, because the model is generating the detail, not enlarging it. What it cannot fix is a face that is 30 pixels wide.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Practical input rules: single subject, face clearly visible, even light, no glare off the print.&lt;/p&gt;

&lt;h2&gt;
  
  
  The product bit
&lt;/h2&gt;

&lt;p&gt;For a format this emotional, the failure mode is not "ugly output", it is "output that feels wrong". So the settings are deliberately limited: a length, and that is it. No motion strength slider, no style picker. Fewer choices, fewer ways to make something that misses the mood.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tattoostencil.ink" rel="noopener noreferrer"&gt;The Tattoo Stencil tool&lt;/a&gt; is a different kind of product entirely — same lesson though: &lt;strong&gt;the constraint is the product&lt;/strong&gt;. There, the constraint is 300 DPI and lines that survive being tattooed.&lt;/p&gt;

&lt;p&gt;The reference: &lt;a href="https://imsorryilied.ink" rel="noopener noreferrer"&gt;the old-photo clip tool&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>video</category>
      <category>machinelearning</category>
      <category>design</category>
    </item>
    <item>
      <title>What I learned rebuilding a TikTok dance trend as a one-photo tool</title>
      <dc:creator>尚毅段</dc:creator>
      <pubDate>Sat, 24 Oct 2026 03:08:11 +0000</pubDate>
      <link>https://dev.to/succday/what-i-learned-rebuilding-a-tiktok-dance-trend-as-a-one-photo-tool-59n2</link>
      <guid>https://dev.to/succday/what-i-learned-rebuilding-a-tiktok-dance-trend-as-a-one-photo-tool-59n2</guid>
      <description>&lt;p&gt;Dance trends are the worst thing to copy by hand.&lt;/p&gt;

&lt;p&gt;You need the counts, the framing, the lighting and someone willing to hold a phone for twenty takes. So the ecosystem solved it the way it always does: templates. The tutorial that goes around for every dance trend is basically identical —&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;copy the link to the original video&lt;/li&gt;
&lt;li&gt;open the creator's profile&lt;/li&gt;
&lt;li&gt;pick their template&lt;/li&gt;
&lt;li&gt;import your photo&lt;/li&gt;
&lt;li&gt;post&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That workflow is what a "one photo" tool is actually competing with. Not the model, not the quality — &lt;strong&gt;the number of steps&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I rebuilt it as a single upload
&lt;/h2&gt;

&lt;p&gt;A template still asks you to: find the trend, find the creator, find the template, install the app, grant permissions, import a photo, wait for the template to load. Seven steps and two apps.&lt;/p&gt;

&lt;p&gt;The one-photo version is: upload, pick a length, wait two minutes. Three steps, one tab.&lt;/p&gt;

&lt;p&gt;Whether that wins depends entirely on one thing: &lt;strong&gt;does the output look close enough to the trend that people believe it&lt;/strong&gt;. If the model hallucinated a different room, you lost. If it looks like a plausible performance of the same routine, you won.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reference clip decides everything
&lt;/h2&gt;

&lt;p&gt;For dance specifically, the reference video has to satisfy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one person, full body, camera static&lt;/li&gt;
&lt;li&gt;the whole routine inside the clip&lt;/li&gt;
&lt;li&gt;no burned-in captions or app UI&lt;/li&gt;
&lt;li&gt;no watermark in the frame&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is why most "download a TikTok and use it as a template" attempts fail. &lt;strong&gt;The watermark doesn't disappear in the output&lt;/strong&gt; — it gets re-rendered into your user's video. I learned this the expensive way: my first pass at a dance template produced clips with a phone-screen recording and a creator's handle baked into the middle of them.&lt;/p&gt;

&lt;p&gt;The fix is boring: source clean footage, crop to 9:16, and check the frames before you ship. A 30-second review would have saved a full afternoon.&lt;/p&gt;

&lt;h2&gt;
  
  
  The domain name problem
&lt;/h2&gt;

&lt;p&gt;One of these sites is called &lt;code&gt;talkdirty.ink&lt;/code&gt;. That name gets you flagged by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;payment providers (adult-content policy)&lt;/li&gt;
&lt;li&gt;ad networks&lt;/li&gt;
&lt;li&gt;the occasional user who assumes it is a different kind of product&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fix is not clever copy, it is &lt;strong&gt;being explicit on the page&lt;/strong&gt;: the FAQ's first question is "Is this an adult site?" and the answer is "No. This is a dance-video tool." Content moderation, no explicit uploads, accounts closed if they try.&lt;/p&gt;

&lt;p&gt;If you pick a spicy domain for a trend, write that answer before you write anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually breaks
&lt;/h2&gt;

&lt;p&gt;Not the model. These:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Queue backlog.&lt;/strong&gt; Everyone tries the trend in the same 48 hours. A single worker draining jobs is not enough; you need a dead-letter queue and a cron that fails stuck jobs &lt;em&gt;and refunds them&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refunds.&lt;/strong&gt; A failed render must return credits automatically, and the refund must be idempotent. Otherwise a retry refunds twice and you are paying users to use your product.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expectations.&lt;/strong&gt; The clip takes two to nine minutes depending on the model. Say so before they upload. Users forgive waiting; they do not forgive surprises.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Numbers from real runs
&lt;/h2&gt;

&lt;p&gt;Six-second vertical clip, same photo, four models:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;model&lt;/th&gt;
&lt;th&gt;time&lt;/th&gt;
&lt;th&gt;note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;fastest&lt;/td&gt;
&lt;td&gt;2m 24s&lt;/td&gt;
&lt;td&gt;motion tracks well, face softens on fast turns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mid&lt;/td&gt;
&lt;td&gt;4m 20s&lt;/td&gt;
&lt;td&gt;sharper, stable edges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pro&lt;/td&gt;
&lt;td&gt;8m 48s&lt;/td&gt;
&lt;td&gt;best fidelity, too slow for a default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;slowest&lt;/td&gt;
&lt;td&gt;9m 47s&lt;/td&gt;
&lt;td&gt;motion fine, patience gone&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The fastest one is the correct default. Quality that nobody waits for is not quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://talkdirty.ink" rel="noopener noreferrer"&gt;Talk Dirty&lt;/a&gt; if you want the dance one. &lt;a href="https://ozilai.ink" rel="noopener noreferrer"&gt;Ozilai&lt;/a&gt; for the football variant, &lt;a href="https://imsorryilied.ink" rel="noopener noreferrer"&gt;I'm Sorry I Lied&lt;/a&gt; for the nostalgic one.&lt;/p&gt;

&lt;p&gt;The media pipeline I use to turn a clip into a poster + manifest (and to check the frames before shipping) is here: &lt;a href="https://github.com/duanhesen/hot-word-site-pipeline" rel="noopener noreferrer"&gt;hot-word-site-pipeline&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>showdev</category>
      <category>video</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to put yourself into a viral trend clip with one photo (no editing)</title>
      <dc:creator>尚毅段</dc:creator>
      <pubDate>Sat, 24 Oct 2026 03:07:49 +0000</pubDate>
      <link>https://dev.to/succday/how-to-put-yourself-into-a-viral-trend-clip-with-one-photo-no-editing-2lac</link>
      <guid>https://dev.to/succday/how-to-put-yourself-into-a-viral-trend-clip-with-one-photo-no-editing-2lac</guid>
      <description>&lt;p&gt;Every few weeks a new 20-second clip takes over TikTok, and the comments are always the same: &lt;em&gt;how do I put myself in this?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The honest answer used to be "learn After Effects", or more recently "hunt down a CapCut template and copy a link". Both are friction. This post is about removing it — and about the parts of that product that are not the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually happens under the hood
&lt;/h2&gt;

&lt;p&gt;Motion transfer models take two inputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;reference video&lt;/strong&gt; (the trend clip)&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;source image&lt;/strong&gt; (your face)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and produce a new video where your identity drives the motion of the original. Timing, camera movement and choreography come from the reference; who you are comes from the photo.&lt;/p&gt;

&lt;p&gt;The part people underestimate: &lt;strong&gt;the model re-renders the background&lt;/strong&gt;. That is why the output looks like "you were there" instead of a cut-out pasted on top — and it is also why it will never be a 1:1 copy of the original scene. If you expect the exact stadium, exact lighting and exact crowd, you will be disappointed. If you expect "me, doing that move, in a scene that plausibly belongs to it", it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The photo is 80% of the result
&lt;/h2&gt;

&lt;p&gt;People blame the model for bad output. Most of the time it is the input. What works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one person, facing the camera&lt;/li&gt;
&lt;li&gt;even light, no hard shadow across half the face&lt;/li&gt;
&lt;li&gt;head and shoulders in frame, not a full-body shot from across the room&lt;/li&gt;
&lt;li&gt;no sunglasses, no mask, no beauty filter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What technically renders and looks wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;group photos (the model has to pick a face)&lt;/li&gt;
&lt;li&gt;mirror selfies (the camera angle fights the reference)&lt;/li&gt;
&lt;li&gt;low-light phone shots (the encoder has already destroyed the detail)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A cheap trick: take the selfie in the same lighting you would use for a passport photo, then stop. Fancy lighting makes it worse, because the model has to reconcile your light with the reference scene's light.&lt;/p&gt;

&lt;h2&gt;
  
  
  The parts that are not the model
&lt;/h2&gt;

&lt;p&gt;The model call is five minutes of work. The rest is what makes it a product:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Credits are a ledger, not a counter.&lt;/strong&gt; Every movement is a row with an idempotency key derived from the business object — &lt;code&gt;order:&amp;lt;id&amp;gt;&lt;/code&gt;, &lt;code&gt;generation:&amp;lt;id&amp;gt;&lt;/code&gt;, &lt;code&gt;generation_refund:&amp;lt;id&amp;gt;&lt;/code&gt;. Payment webhooks retry. Users double-click. Without the keys you get double-charging and double-refunding, and you find out from an angry email.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A failed render must refund automatically.&lt;/strong&gt; Not "contact support". The refund is derived from the same generation row, so it is a no-op if it runs twice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The job is a queue, not a request.&lt;/strong&gt; Submit to the provider, store the request id, poll, and let a cron reconcile anything stuck past the deadline. A HTTP request that waits for a video will time out long before the video exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content is data.&lt;/strong&gt; Copy lives in per-locale modules that take the site config as an argument. Change the keyword or the price and every page updates — including the structured data and &lt;code&gt;/llms.txt&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The boring numbers
&lt;/h2&gt;

&lt;p&gt;On a real photo, a 6-second vertical clip:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fast model: ~2.5 minutes&lt;/li&gt;
&lt;li&gt;mid model: ~4.5 minutes&lt;/li&gt;
&lt;li&gt;slow model: ~9 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anything above five minutes loses a meaningful share of users before they see a result. That is a product constraint, not a model benchmark.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ozilai.ink" rel="noopener noreferrer"&gt;Ozilai&lt;/a&gt; — the football goal variant&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://talkdirty.ink" rel="noopener noreferrer"&gt;Talk Dirty&lt;/a&gt; — the dance variant&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://imsorryilied.ink" rel="noopener noreferrer"&gt;I'm Sorry I Lied&lt;/a&gt; — an old photo, gently moving&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same engine, different reference clips. One photo in, one vertical MP4 out.&lt;/p&gt;

&lt;p&gt;If you are building something similar, the two tools I keep reaching for are in this repo: a media pipeline that turns clips into posters and manifests, and a checker that tells you whether AI crawlers can actually read your site.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tutorial</category>
      <category>video</category>
    </item>
  </channel>
</rss>
