Definition
Working memory holds about 7±2 discrete items at once, and the number contracts under stress, fatigue, or context-switching. The number is not a design quota; it is a ceiling that drops fast in real-world conditions. Design for the lower bound, not the average.
Why it matters for ShurIQ reports
Stack-rank views, KPI strips, and filter rails should respect a working-memory budget. Five competitor cards on screen are easy to compare; eleven require the reader to scroll, lose context, and re-anchor. Where breadth is necessary, lean on chunking to compress many items into a small number of visual groups.
Takeaways
- Cap any "at-a-glance" surface at 5 to 7 elements; offload the rest to scroll or expansion.
- Where data must exceed the limit, group into 3–4 super-categories the reader can hold instead.
- Stress-test under client conditions — a CFO mid-meeting has a smaller working-memory budget than a designer at a desk.
- Do not invoke the number to justify removing things that should remain; the principle is about chunking, not censorship.
Visual motion language
Lists reveal in groups of 5–7 with a sequence-reveal cadence; additional items load on demand with a discrete group-form transition that signals a new chunk.
Origins
George A. Miller, 1956 — The Magical Number Seven, Plus or Minus Two.
Cavalry scene
The script below builds this concept's motion in Cavalry through the Stallion bridge. Pipe to cavalry_run_script via MCP, or paste into Cavalry's JavaScript Editor.
// Laws of UX · millers-law · Cavalry scene
// Motion family: grid-stagger (7±2 center-spread highlight)
// Palette: terracotta + cream
// To run: pipe to cavalry_run_script tool, or paste into Cavalry's JavaScript Editor
// Built 2026-04-30 by ShurAI
(function () {
var PREFIX = "claude_lawofux_millers-law_";
var existing = api.getAllSceneLayers();
for (var i = 0; i < existing.length; i++) {
try {
var nm = api.getNiceName(existing[i]);
if (nm && nm.indexOf("claude_lawofux_") === 0) api.deleteLayer(existing[i]);
} catch (e) {}
}
var BG = "#B8442E";
var DARK = "#8E3322";
var CREAM = "#D6CDB0";
var bg = api.primitive("rectangle", PREFIX + "bg");
api.set(bg, { "generator.dimensions": [1080, 1080] });
api.setFill(bg, true);
api.set(bg, { "material.materialColor": BG });
// 7x7 grid
var COLS = 7, ROWS = 7, SPACE = 65, R = 16;
var startX = -((COLS - 1) * SPACE) / 2;
var startY = ((ROWS - 1) * SPACE) / 2;
for (var r = 0; r < ROWS; r++) {
for (var c = 0; c < COLS; c++) {
var d = api.primitive("ellipse", PREFIX + "dot_" + r + "_" + c);
api.set(d, {
"generator.radius": [R, R],
"position.x": startX + c * SPACE,
"position.y": startY - r * SPACE,
"opacity": 0
});
api.setFill(d, true);
api.set(d, { "material.materialColor": DARK });
// Initial fade-in
var inF = (r * COLS + c);
api.keyframe(d, inF, { "opacity": 0 });
api.keyframe(d, inF + 8, { "opacity": 100 });
// Highlight middle row (r=3) — center brightest, edges dimmest
if (r === 3) {
var distFromCenter = Math.abs(c - 3);
var targetBrightness = [100, 80, 50, 25][distFromCenter] || 0;
var highlightFrame = 60 + distFromCenter * 4;
// Keep dark fill but add a cream overlay dot
var hl = api.primitive("ellipse", PREFIX + "hl_" + c);
api.set(hl, {
"generator.radius": [R, R],
"position.x": startX + c * SPACE,
"position.y": startY - 3 * SPACE,
"opacity": 0
});
api.setFill(hl, true);
api.set(hl, { "material.materialColor": CREAM });
api.keyframe(hl, highlightFrame, { "opacity": 0 });
api.keyframe(hl, highlightFrame + 10, { "opacity": targetBrightness });
}
}
}
var layerCount = api.getAllSceneLayers().length;
console.log("scene built: millers-law (" + layerCount + " layers)");
})();