Forty product cards, due Friday. The layout is built, the checkout flow works, the string validator has tests that all pass because there is nothing to validate yet. What does not exist is a single word of copy, a single product code, or a single input designed to make anything fail.
None of it has to be real. All of it has to be correct. Those are not the same requirement, and the gap between them is where an afternoon goes.
The three blanks, and the rule sitting behind each one
The card subtitle is capped at 90 characters by the design, the meta description at 160 by Google, and the button label at whatever fits without wrapping. Placeholder copy that ignores those numbers proves nothing, because the whole point of filling a mockup is to find out where text overflows.
The product codes have to scan. Not look like barcodes, scan. A barcode carries its own arithmetic, and a reader recalculates the last digit from the other twelve on every pass. Get it wrong and there is no beep, which in a demo is worse than no barcode at all.
The validator needs inputs that are interesting. A string checker written on Monday passes every test on Tuesday because the tests were written by the same person, in the same mood, with the same assumptions. What it needs is symmetric strings, strings with punctuation, strings that are digits, and one string that fails at a position you can name.
Three blanks. Three rules. Nothing in common except that the data is invented and the rule is not.
Step one: copy that has to fit a box
Start with the constraint, not the content. The card subtitle allows 90 characters, so the question is not how much lorem ipsum looks right, it is how many words fit in ninety characters. Measured over five hundred runs, the answer is about 12. A meta description at 160 characters holds about 22. A button label at 20 characters holds 2, which is a useful thing to learn before somebody writes a three word call to action.
| Ask for | Characters with spaces | Which slot that fills |
|---|---|---|
| 3 words | 21 | A button, and only just |
| 8 words | 56 | A product title |
| 13 words | 90 | The card subtitle, exactly at the cap |
| 23 words | 160 | A meta description at the limit |
| 50 words | 350 | A short description block |
The screenshot above is the 50 word setting: 348 characters with spaces, 299 without, average word length 6.0. Run it again and the character count moves, because only the word count is fixed. That is worth knowing before you build a budget around one run.
It is also worth knowing that this Latin runs long. The word list averages 5.95 characters against roughly 5 for running English, so a column that rags beautifully under placeholder copy will rag slightly differently under the real thing. Not enough to redesign around. Enough to check the tightest column twice.
Paragraph mode is the other half of the job, and it is not exact by construction: each paragraph is 3 to 6 sentences of 6 to 15 words, so one paragraph averages 47 words and 330 characters but can land anywhere from 18 to 90 words. That randomness is the feature. Generating one paragraph and pasting it five times hides exactly what a mockup exists to expose, which is uneven depth, a widow at the top of a column, a last line stranded on its own.
One setting stays on: the classic opening line. Nineteen words, 123 characters, and the only reliable way to stop somebody in the review meeting from treating the filler as a draft and correcting it.
Step two: codes a scanner will accept
Forty products need forty codes. The temptation is thirteen random digits, and it fails immediately, because the thirteenth digit is not free. It is computed from the other twelve by a weighted sum, and every reader in the world recomputes it.
Here is the arithmetic in full, for 4006381333931. Weights alternate three and one, counting backwards from the check digit: 4x1 + 0x3 + 0x1 + 6x3 + 3x1 + 8x3 + 1x1 + 3x3 + 3x1 + 3x3 + 9x1 + 3x3 = 89. Round 89 up to the next multiple of ten and you get 90. The difference, 1, is the check digit, and it is the digit the code actually ends in.
That direction of the weights is where home-made implementations go wrong. A twelve digit base starts on weight one; a seven digit base for EAN-8 and an eleven digit base for UPC-A both start on weight three. Write the loop from the left with a fixed starting weight and it is correct for EAN-13 and wrong for the other two, which is a pleasant kind of bug: it passes the first test and fails in production.
The prefix is the other thing the tool reports, and it is routinely misread. 400 here means the number was issued by GS1 Germany. It does not mean the product was made in Germany, and there is no way to find that out from a barcode at all. A company licenses a prefix from an office, and manufactures wherever it likes.
Two prefixes are worth knowing for a prototype. Anything starting 978 or 979 is a book, because an ISBN barcode is an EAN-13 with a publishing prefix on the front. Anything from 20 to 29 is restricted circulation, reserved for numbers that never leave the premises that issued them. For internal stock, that range is the honest choice, because it cannot collide with a real manufacturer anywhere in the world.
And a limit worth stating plainly, because it is the one thing a generator cannot give you: a code produced this way is structurally valid and completely unregistered. It scans, and it is not yours. For a mockup, a label template or a test fixture that is exactly right. For a product that will cross a till, the number comes from GS1 against a prefix you pay for.
Step three: inputs designed to break the validator
The string validator on this prototype does three things: strips punctuation, compares characters, reports a position. Testing it with words somebody typed by hand tests the same assumptions twice.
Take the sentence in the screenshot. Was it a car or a cat I saw is twenty-seven characters as typed, of which eight are spaces. Strip the spaces and the capital, and 19 characters remain, mirroring around a single o in the middle: 9 pairs match, and the odd one out is its own reflection. That is four separate behaviours tested in one input, and none of them is the obvious one.
The obvious one is racecar, and it tests almost nothing. Everything interesting lives in the awkward cases. Digits, for a start: 12321 is a palindrome under any definition anyone uses, and a checker that quietly deletes digits along with the punctuation will report it as too short instead. Mixed input next: A1 1A normalises to four characters and passes. And the failure path, which matters more than the success path, because a validator that says no without saying where is a validator nobody trusts.
The examples come from a pool of 66, split four ways so that a test set can be built by category rather than by hand: 24 single words from four to twelve letters, 14 names and places, 16 phrases running from eleven to fifty-one characters once stripped, and 12 numbers. Every entry was verified by running it back through the checker rather than by eye, which is not a formality: published palindrome lists routinely carry entries that fail once the punctuation comes off properly.
What the fixture set looked like when it was finished
| What the prototype needed | Where it came from | The rule it had to satisfy |
|---|---|---|
| 40 card subtitles | 13 words each | Under 90 characters, counted not estimated |
| 40 meta descriptions | 23 words each | Under 160 characters |
| 40 description blocks | 3 paragraphs each, all different | Uneven depth, so the ragging is honest |
| 40 product codes | EAN-13 from one prefix | A check digit a reader recomputes |
| A validator test set | 66 checked strings, 4 kinds | Symmetry, with the break position named |
Three rules, and what none of them can catch
Every rule here is a filter, and every filter has a shape. Knowing what each one lets through is more useful than knowing what it stops.
| Rule | What it catches | What it lets straight through |
|---|---|---|
| Character budget | Copy that overflows a fixed box | Copy that fits and says nothing |
| Symmetry | Any asymmetric string, at a named position | Anything about meaning, spelling or language |
| GS1 check digit | Every single mistyped digit, without exception | Two swapped neighbours differing by exactly 5 |
That last cell is the only genuine blind spot of the three, and it is narrow enough to describe exactly. Swapping two adjacent digits changes the weighted sum by twice their difference. Twice a difference of five is ten, and ten leaves the remainder untouched, so 27 written as 72 slips past. Every other adjacent swap is caught. So is every single wrong digit, all one hundred and eight of them on a twelve digit base.
Four things worth taking away
Exactness lives on one axis only. Word mode hits a number because it counts words. Paragraph and sentence mode cannot, because their length is part of what is randomised. If the requirement is a number, ask for the unit the number is in.
A checksum is the cheapest test you will ever write. Six lines of arithmetic catch every single-digit error in a dataset, permanently, without a test suite. It is worth asking, whenever a system has an identifier, whether the identifier is checking itself.
Placeholder text is a measuring instrument, not decoration. Used properly it tells you a subtitle holds twelve words and a meta description twenty-two. Used improperly it is grey paint that makes a design look finished before it is.
Fake data that obeys a rule is testable. Fake data that does not is scenery. The difference between thirteen random digits and a valid EAN-13 is one digit and the entire point.
Doing it again
The order would change. The afternoon started with the copy, because copy feels like the big job, and it turned out to be the smallest: three settings and a character count. The codes should have come first, because they were the only part with a rule that could reject the work outright, and rejecting late is what turns an afternoon into an evening.
Beyond that, the fixture set outlived the prototype, which was not the plan. The barcodes are still in the test database, the palindrome set still runs against the validator on every commit, and only the placeholder copy did what placeholder copy is supposed to do, which is to be deleted the moment somebody writes the real thing.
Tools discussed in this article
Lorem Ipsum Generator - placeholder copy by the paragraph, the sentence or an exact word count up to 500, with the classic opening line and a character count that tells you whether it fits. Ready-made pages: 25 words, 50 words, 100 words, 300 words, 3 paragraphs and 5 paragraphs.
Barcode Generator - builds and validates EAN-13, UPC-A and EAN-8 with the GS1 check digit worked out term by term, looks up which office issued the prefix, and draws the bars itself as an SVG rather than fetching them from anywhere.
Palindrome Generator - checks any word, phrase or number for symmetry and names the position where it breaks, or draws examples from 66 verified entries. By kind: words, names, phrases and numbers.
More text tools
Anagram Generator - rearranges the letters you supply and reports exactly how many distinct arrangements exist, which for MISSISSIPPI is 34,650 rather than the 39,916,800 that eleven letters suggest.
More code and random tools
Password Generator - for the staging login on the prototype, with a strength rating and a character mix you control.
WiFi Password Generator - passphrases for a WPA2 or WPA3 router, with entropy reported in bits instead of an invented crack time.
Random Number Generator - draws from a range you set, when the blank is a number and no rule governs it.
Color Generator - the palette half of a blank layout, in HEX, RGB and HSL.
Nickname Generator - usernames for the forty fake customer accounts nobody remembers to create until the demo.