Fresh supermarket marketing planner - weekly ad circular layout tool: traffic, margin and image items each in their slot, discount total offset on the spot
Build me a single-file HTML circular (weekly ad) layout tool
for the marketing planner of a fresh-food supermarket. It
must open by double-click and work fully offline.
Context: we publish a circular every [cycle] and pick 12-16
items from dozens of candidates. Today it is buyers and the
store manager picking by gut - the page ends up all eggs and
bananas, nobody champions the margin items, and nobody has
ever totaled the discounts. I want selection + layout +
arithmetic finished in one page.
Data entry (support both):
- Paste CSV: item name, baseline weekly units, margin rate,
supply stability (steady | tight | out), whether it ran a
special in the last 30 days, manual flags (image-item
candidate, meal-scenario note)
- Or add rows through a form
Role assignment (every rule visible and editable in
settings - no black box):
- Traffic-item candidate: baseline weekly units in the top
[sales rank cutoff], AND margin rate >= [traffic-item
margin floor] - an item already paper-thin on margin has
no room to cut price and cannot lead traffic
- Margin-item candidate: margin rate >= [margin-item
threshold] AND supply steady - "tight" and "out" are
auto-excluded; a manual override stays in with a
stockout-risk flag on it
- Image item: manual flag only (seasonal, high-ticket,
makes the store look good). The tool never auto-assigns
this role - it cannot judge what makes a store look good
- Any item that ran a special in the last 30 days is
demoted by default (two specials in a row trains
customers to wait for the special); manual exemption
allowed, with the exemption recorded
Layout and arithmetic:
- Fixed format: 1 front-page item, 1 back-page item, the
rest inside - traffic items default onto front and back,
drag to swap
- Suggested promo price: traffic item = cost x [traffic
markup]. Editing a price updates that item's discount
(regular price - promo price) and the whole-ad discount
total live
- One balance-check line: whole-ad discount total vs
margin items' projected gain, where gain = margin items'
baseline margin x [uplift multiple]. I supply the
multiple; the tool only multiplies. If the multiple is
blank, the line does not render - better absent than
fabricated
Output:
- Layout table: slot / item / role / promo price /
discount - printable for the graphic designer
- Data in localStorage, JSON export/import; handovers
leave no paper behind
Hard requirements:
- Single file, no build step, no external CDN or fonts
- No sales forecasting, no "smart selection" - projected
volume is always baseline weekly units x my multiple.
The tool invents no numbers
- Thresholds start empty in settings - no preloaded
"typical industry values." Every store's customers have
different price sensitivity, and a copied threshold gets
executed as truth
- No composite scores ("item score," "hit index") -
sorting only by explainable fields (units, margin rate,
discount dollars); whatever rules cannot decide goes
back to a human
Why it is written this way
Laying out a circular is not "pick what sells" - it is role composition. One ad has to do three jobs at once: pull people in (traffic items), earn the margin back (margin items), and make the store look worth the trip (image items). Sort purely by volume and the page is all eggs and bananas - and the people who came only buy eggs. Sort purely by margin and nobody walks in. The tool's core value is making the three roles' thresholds explicit, which turns the layout argument from "I think this item will pop" into "who set this threshold?" - whoever sets a threshold answers for it, and that is far more reliable than an arguer answering for a hunch.
No sales forecasting is the tool's floor. The moment a forecast number appears it becomes a budget commitment, and by month-end nobody remembers it was a guess. The tool only multiplies baseline units by a human-supplied factor; the factor is the planner's judgment, and when it is wrong, at least it is wrong traceably. Same logic for the balance line: when the uplift factor is blank, the line simply does not render - one missing line beats one fabricated number dressed up as arithmetic.
"Ran a special in the last 30 days" demoting an item is the most common self-inflicted wound in grocery promotion: the same soy sauce at special price three circulars in a row, and by the fourth nobody ever pays full price again. That rule lives in settings rather than buried in code precisely so the planner can see it and argue with it - a good rule should survive being challenged; a black-box rule only gets worked around.
Empty default thresholds and the ban on "typical industry values" follow the same logic as the forecasting ban. A model would happily supply "below 15% margin, unsuitable as a traffic item" - professional-sounding, but a neighborhood store and an upscale store face completely different price sensitivities. The tool enforces structure; humans supply numbers. That line is what makes this a tool instead of an opinion.
Variables
| Variable | Notes |
|---|---|
| Circular cycle | Weekly / biweekly; widens or narrows the special-demotion window |
| Three thresholds | Sales rank cutoff, traffic-item margin floor, margin-item threshold - set from the store's own data |
| Traffic markup / uplift multiple | The arithmetic basis for discounting and offsetting; blank multiple hides the balance line |