LAWSOFUX · motion lab
Concept · hicks-law

Hick's Law

Grid stagger reveal palette · cobalt / cream takeaways · 5

Definition

The time required to make a decision grows logarithmically with the number of options. Add complexity to each option and the curve steepens further. The takeaway is not "fewer choices always" — the takeaway is that decision time is a designable quantity.

Why it matters for ShurIQ reports

Viewport selectors, filter rails, and stack-rank toggles are decision surfaces; every additional option pays a measurable cost in time-to-insight. A viz hub that surfaces 18 filters at once buries the executive; a hub that surfaces 4 with a "more" expansion respects the law. The framing carries forward to gap card design — never ask the reader to choose among undifferentiated cards.

Takeaways

Visual motion language

Non-default options collapse to a compact secondary tier on first paint, expanding only on user request. The default option zoom-focuses with a 1.05× scale to signal the recommended path.

Cavalry recreation seed. 7×6 grid of 28px dark dots (40px spacing). Centered chip = 100×100 cream square outline 8px stroke with 4 small cream rectangles protruding from each side and inner 40×40 outlined square. Animate dots fading in row-by-row 0→0.7 over 1.2s, then chip scales 0.4→1 in 500ms with mild overshoot. Loop the chip with a subtle 2s breathing scale 1→1.05.

Origins

William Edmund Hick and Ray Hyman, 1952 — formalized reaction time as a function of number of stimuli.

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 · hicks-law · Cavalry scene
// Motion family: grid-stagger
// Palette: cobalt + 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_hicks-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    = "#1E5C8C";
  var DARK  = "#163E5C";
  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 });

  // 7 cols x 6 rows of small dark dots
  var COLS = 7, ROWS = 6, SPACE = 70, R = 14;
  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 });
      api.keyframe(d, r * 4,      { "opacity": 0  });
      api.keyframe(d, r * 4 + 12, { "opacity": 70 });
    }
  }

  // CPU-chip motif at center: outer square outline + inner square + 4 stub legs
  var chipOuter = api.primitive("rectangle", PREFIX + "chip_outer");
  api.set(chipOuter, {
    "generator.dimensions": [140, 140],
    "position.x": 0, "position.y": 0,
    "opacity": 0,
    "scale.x": 0.4, "scale.y": 0.4
  });
  api.setFill(chipOuter, false);
  api.setStroke(chipOuter, true);
  api.set(chipOuter, { "stroke.strokeColor": CREAM, "stroke.width": 8 });

  var chipInner = api.primitive("rectangle", PREFIX + "chip_inner");
  api.set(chipInner, {
    "generator.dimensions": [60, 60],
    "position.x": 0, "position.y": 0,
    "opacity": 0,
    "scale.x": 0.4, "scale.y": 0.4
  });
  api.setFill(chipInner, false);
  api.setStroke(chipInner, true);
  api.set(chipInner, { "stroke.strokeColor": CREAM, "stroke.width": 6 });

  // 4 stub legs
  var legs = [
    { x:    0, y:  90, w: 16, h: 30 },
    { x:    0, y: -90, w: 16, h: 30 },
    { x:   90, y:   0, w: 30, h: 16 },
    { x:  -90, y:   0, w: 30, h: 16 }
  ];
  var legIds = [];
  for (var li = 0; li < legs.length; li++) {
    var lg = legs[li];
    var L = api.primitive("rectangle", PREFIX + "leg_" + li);
    api.set(L, {
      "generator.dimensions": [lg.w, lg.h],
      "position.x": lg.x, "position.y": lg.y,
      "opacity": 0,
      "scale.x": 0.4, "scale.y": 0.4
    });
    api.setFill(L, true);
    api.set(L, { "material.materialColor": CREAM });
    legIds.push(L);
  }

  var chipParts = [chipOuter, chipInner].concat(legIds);
  for (var ci = 0; ci < chipParts.length; ci++) {
    var p = chipParts[ci];
    api.keyframe(p, 30, { "opacity": 0,   "scale.x": 0.4, "scale.y": 0.4 });
    api.keyframe(p, 48, { "opacity": 100, "scale.x": 1.0, "scale.y": 1.0 });
    api.magicEasing(p, "scale.x", 48, "EaseOut", "");
    api.magicEasing(p, "scale.y", 48, "EaseOut", "");
    // Breathing
    api.keyframe(p, 90,  { "scale.x": 1.0,  "scale.y": 1.0  });
    api.keyframe(p, 120, { "scale.x": 1.05, "scale.y": 1.05 });
    api.keyframe(p, 150, { "scale.x": 1.0,  "scale.y": 1.0  });
  }

  var layerCount = api.getAllSceneLayers().length;
  console.log("scene built: hicks-law (" + layerCount + " layers)");
})();