LAWSOFUX · motion lab
Concept · serial-position-effect

Serial Position Effect

Sequential reveal then dim palette · magenta / cream takeaways · 2

Definition

Items at the start and end of a sequence are remembered better than items in the middle. The first items benefit from primacy (rehearsal into long-term memory), the last from recency (still active in working memory). The middle is where information goes to die.

Why it matters for ShurIQ reports

Stack-rank tables, navigation menus, and viewport tile orders all carry serial-position weight. The top row and the bottom row of a 21-company stack rank get re-read; rows 8–14 are the dropout zone. Action items at the top of a recommendation list and the closing line of a brief carry disproportionate memory weight.

Takeaways

Visual motion language

Sequence-reveal staggers entries with a slight color-emphasis on the first and last; the middle items fade in at lower contrast to acknowledge their lower memorability.

Cavalry recreation seed. 7 cream 30×30 squares arranged in a serpentine row: 4 in top row + 3 in bottom row right-offset. All start invisible. Fade in left-to-right with 150ms stagger over 1.5s. At t=1.7s scale up the first (top-left) and last (bottom-right) squares 1→1.4 with brightness boost. Hold static 2.5s. Loop.

Origins

Hermann Ebbinghaus, late 19th century — coined the serial position effect in foundational memory research.

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 · serial-position-effect · Cavalry scene
// Motion family: grid-stagger (book-end highlight)
// Palette: plum-purple + 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_serial-position-effect_";

  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    = "#4A2E5C";
  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 squares: 4 on top row, 3 on bottom row offset right
  var SIZE = 60;
  var GAP = 26;
  var topY = 50, botY = -50;
  var positions = [
    { x: -((4-1)/2) * (SIZE + GAP),                    y: topY }, // 0 top-left
    { x: -((4-1)/2) * (SIZE + GAP) + 1 * (SIZE + GAP), y: topY }, // 1
    { x: -((4-1)/2) * (SIZE + GAP) + 2 * (SIZE + GAP), y: topY }, // 2
    { x: -((4-1)/2) * (SIZE + GAP) + 3 * (SIZE + GAP), y: topY }, // 3
    { x: -((3-1)/2) * (SIZE + GAP) + 0 * (SIZE + GAP) + (SIZE/2 + GAP/2), y: botY },
    { x: -((3-1)/2) * (SIZE + GAP) + 1 * (SIZE + GAP) + (SIZE/2 + GAP/2), y: botY },
    { x: -((3-1)/2) * (SIZE + GAP) + 2 * (SIZE + GAP) + (SIZE/2 + GAP/2), y: botY }
  ];

  var bookendIdxs = [0, 6]; // primacy + recency

  for (var i = 0; i < positions.length; i++) {
    var p = positions[i];
    var sq = api.primitive("rectangle", PREFIX + "sq_" + i);
    api.set(sq, {
      "generator.dimensions": [SIZE, SIZE],
      "position.x": p.x, "position.y": p.y,
      "opacity": 0,
      "scale.x": 1.0, "scale.y": 1.0
    });
    api.setFill(sq, true);
    api.set(sq, { "material.materialColor": CREAM });

    var inF = i * 4;
    api.keyframe(sq, inF,      { "opacity": 0  });
    api.keyframe(sq, inF + 12, { "opacity": 70 });

    if (bookendIdxs.indexOf(i) >= 0) {
      // Boost
      api.keyframe(sq, 36, { "opacity": 70,  "scale.x": 1.0, "scale.y": 1.0 });
      api.keyframe(sq, 52, { "opacity": 100, "scale.x": 1.4, "scale.y": 1.4 });
    }
  }

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