Six templates. Then the reason they broke.
The engagement started the way retail engagements usually start: design the product detail page, the listing page, the homepage, and the supporting templates around them. Comps. Redlines. Ship.
The pages were not the hard part. The hard part showed up the first time somebody asked a question the comps could not answer — what does the add-to-bag button say when no size is selected? There were four plausible answers and no rule, and the same shape of question was waiting behind every other component. A page is one answer to that question. A system is the answer to all of them.
So the scope moved. I kept delivering templates, and underneath them I defined the thing the templates were actually made of: a component library, a state taxonomy for each component, and a colour system where every value carried a job description instead of a mood.
The button that had to say four things.
This product page is long. Details, sizing, shipping, recommendations, paired products, ratings, a wall of customer photos, two more carousels. By the time a shopper has read enough to decide, the thing they decide with is a thousand pixels above them.
So the add-to-bag action detaches and follows — and once it follows, it has to carry the whole variant transaction with it, including the ways that transaction fails. The most common add-to-bag failure is not a server error. It is an unselected size. Which makes the error state the most important state on the most important control on the highest-value page on the site.
Sticky add-to-bag · state machine Recreation — interactive
Product name and prices are invented. The states, and the rule attached to each one, are the deliverable.
State 02 is the one worth arguing about. The obvious solution is a toast: leave the button saying Add to bag, and throw an error somewhere when it fails. We put the instruction in the button itself, because a toast is a message about a failure and a label is a description of what the control will do next. The shopper never gets told they did something wrong — the button simply tells them what it needs. Same information, no blame, nothing to dismiss, and it survives on a phone where a toast can land under a thumb.
A disabled button is a designer refusing to say why.Djoaniel Hernandez · System note № 05
I designed the listing page with every filter on.
Filter chips are the easiest component in retail to design and one of the easiest to ship broken, because the comp always shows two or three of them. Nobody selects three filters. People select a colour family, then a couple of sizes, then a sleeve length, then change their mind and leave the old ones on.
So the specimen I designed against was the maximum: every colour, every size, every sleeve length, all applied at once. Push the chips yourself and watch the readout — the number that matters is not the chip count, it is the height of the row, because that height is subtracted from the products.
Listing page · filter row at load Recreation — interactive
Result count and product names are placeholder values, exactly as they were in the spec. The row height is measured live in your browser.
Three rules came out of that specimen. Chips wrap rather than scroll horizontally, because a horizontal chip rail hides the filters a shopper most wants to remove. Clear all is pinned first and never wraps away from the row, so the escape hatch cannot leave the screen when the mess is at its worst. And the grid keeps a fixed minimum above the fold regardless of chip count — the filters are allowed to get ugly, the products are not allowed to disappear.
The version nobody frames is the real deliverable.
The homepage went out twice: once dressed in campaign imagery, and once as gray boxes. The second one is the one I actually designed.
Because the person who touches this page every week is not the shopper. It is a swapping a hero, three promo tiles, a five-product rail and a give-back banner on a campaign cadence, through a CMS, with no designer in the room. If the layout only holds when the photography is beautiful, it does not hold. Every slot has to declare its ratio, its safe area, its character budget and what it does when it is empty — or the page degrades a little every week until somebody calls it a redesign.
Homepage template Recreation — toggle the fill
Summer
and sweet
lifted
it all
accessories shop
Campaign photography belongs to the client and is not reproduced. In the populated state the palette itself stands in for the imagery — which is, conveniently, the point being made.
A palette is not a mood board. It is an assignment sheet.
The colour documentation does not describe how the colours feel. Each value carries the job it is allowed to do, so that a developer, a merchandiser or the next designer can resolve a question without a taste debate. Two of the entries are arguments rather than choices.
Hex values on this page are shifted from the source palette. The assignments are the subject; the exact values are the client's.
The palette also shipped with PMS numbers, because this brand exists in stores. A colour that only resolves on a screen is half a colour system — the same peacock has to survive a printed tag, a window graphic and an OLED phone, and the one that governs all three is the one worth writing down.
And every field has seven.
The same discipline, one level down. A text input is not a rectangle; it is seven rectangles a developer has to be told about before they guess.
Buttons carried the same treatment — four hierarchies, desktop and mobile, redlined to a 47px target.
The honest edges of this one.
The reason this project sits in a portfolio next to a banking data standard and a chatbot architecture is that it is the same job. Find the moment the system is asked a question it has no answer for, and answer it once, in a place where the answer survives the next person. In banking that moment was a missing valuation. Here it was a shopper who had not picked a size.