LAWSOFUX · motion lab
Concept · law-of-similarity

Law of Similarity

Grid stagger reveal palette · magenta / cream takeaways · 3

Definition

Visually similar elements are perceived as members of the same group — even when separated by space, content, or time. Color, shape, weight, and motion behavior all serve as group signals. Similarity is the second-strongest grouping force after proximity.

Why it matters for ShurIQ reports

Stack-rank rows, brand-power-score axes, and viewport-tile types each need a consistent visual identity that the reader can re-acquire on every scroll. If two unrelated UI elements share styling, the reader will spend cognitive effort wondering whether they are linked. The discipline is to keep similar things similar and different things visibly different.

Takeaways

Visual motion language

Items of the same class animate in parallel-rays — same easing, same delay offset — to reinforce membership. Color-emphasis sweeps share timing across grouped elements.

Cavalry recreation seed. 5×5 grid of 97px circles (radius 48.5, spacing ~117px) inside a 566×565 panel. Fill cream (#f4f1d0) for the scattered group; fill darker (#000 at 0.2 opacity over bg) for the rest. Cream coordinates: (1,1), (1,3), (2,4), (3,3), (4,1), (4,5), (5,2). Animate each row fading in together, top-to-bottom, ~140ms stagger between rows, ~700ms total. No connecting lines. Hold static 2.5s; loop. Background: pink/maroon #8C3A4F.

Origins

Gestalt psychology — early 20th century perceptual organization 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 · law-of-similarity · Cavalry scene
// CORRECTED 2026-04-30 · verified from production page
// Motion family: grid-stagger (5x5 identical circles, 7 cream scattered, similarity by color only)
// No connecting lines. Row-by-row top-to-bottom reveal.
// Palette: pink/maroon + 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_law-of-similarity_";

  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    = "#8C3A4F";
  var CREAM = "#D6CDB0";
  var DARK  = "#4A1F2A";

  var bg = api.primitive("rectangle", PREFIX + "bg");
  api.set(bg, { "generator.dimensions": [1080, 1080] });
  api.setFill(bg, true);
  api.set(bg, { "material.materialColor": BG });

  // 5x5 grid. Cream coords (1-indexed row,col): (1,1)(1,3)(2,4)(3,3)(4,1)(4,5)(5,2)
  var creamMap = {
    "1,1": true, "1,3": true,
    "2,4": true,
    "3,3": true,
    "4,1": true, "4,5": true,
    "5,2": true
  };

  var R       = 48;  // radius
  var SPACING = 130; // center-to-center
  var GRID    = 5;
  var origin  = -((GRID - 1) * SPACING) / 2; // -260 -> first col

  for (var r = 1; r <= GRID; r++) {
    for (var c = 1; c <= GRID; c++) {
      var key = r + "," + c;
      var isCream = !!creamMap[key];
      var dot = api.primitive("ellipse", PREFIX + "r" + r + "c" + c);
      api.set(dot, {
        "generator.radius": [R, R],
        "position.x": origin + (c - 1) * SPACING,
        "position.y": -(origin + (r - 1) * SPACING), // flip: row 1 at top (+Y)
        "opacity": 0
      });
      api.setFill(dot, true);
      api.set(dot, { "material.materialColor": isCream ? CREAM : DARK });

      // Row-by-row stagger: ~140ms per row (~4 frames at 30fps)
      var t0 = (r - 1) * 4;
      var t1 = t0 + 10;
      api.keyframe(dot, t0, { "opacity": 0 });
      api.keyframe(dot, t1, { "opacity": isCream ? 100 : 45 });
      api.magicEasing(dot, "opacity", t1, "EaseOut", "");
    }
  }

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