---
format: 1
concept: "arrays"
kind: "figure"
title: "Insert and watch the shift"
labels: {"lang":"en","level":"beginner","approach":"visual"}
base: "29fad5e633ad83b7b46796d44f2968ec0a3c8ff05d6af1dba614b943bee97a54"
changes: ["Uses the ai.page figure kit: the shared design tokens for colour, light and dark, and the shared controls"]
by: "si"
declaration: {"company":"anthropic","model":"claude-opus","version":"5.5","thinking":"high","app":"claude-code","tools":[],"sources":[]}
---
A row of numbered boxes holding values, with spare boxes at the end. Choose an index and press **Insert**: every item from that index onwards moves one box right, from the last one backwards, and the new value goes in the freed box. A counter says how many items moved. **Read** picks an index and shows that reading it is one step, whatever its position. Inserting at index 0 moves every item; inserting at the end moves none. The arrow keys move the chosen index. With reduced motion, items move without animation.

```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
body{display:flex;flex-direction:column;gap:12px}
.row{display:grid;grid-template-columns:repeat(10,1fr);gap:4px}
.box{border:1px solid var(--aip-line);border-radius:6px;text-align:center;padding:8px 0;font-variant-numeric:tabular-nums;transition:background .3s ease-out,transform .3s ease-out}
.box .i{display:block;font-size:10px;color:var(--aip-ink-muted)}
.box.empty{border-style:dashed;color:var(--aip-ink-muted)}
.box.chosen{outline:3px solid var(--aip-accent);outline-offset:1px}
.box.moved{background:var(--aip-accent-soft)}
.box.new{background:var(--aip-accent);color:var(--aip-paper)}
.box.new .i{color:inherit}
.bar{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
#count{font-weight:700;color:var(--aip-warn)}
@media (prefers-reduced-motion:reduce){.box{transition:none}}
</style>
</head>
<body>
<div class="bar"><label>Index <input id="at" type="number" min="0" value="2" style="width:4em;font:inherit"></label><button class="go" id="ins">Insert 99</button><button id="read">Read it</button><button id="reset">Reset</button></div>
<div class="row" id="row" role="list" aria-label="The array"></div>
<p id="say" aria-live="polite">Choose an index, then insert or read.</p>
<p>Moves so far: <span id="count">0</span></p>
<script>
const CAP = 10;
let items, moves, busy = false;
const row = document.getElementById("row"), say = document.getElementById("say"), at = document.getElementById("at"), count = document.getElementById("count");
const reduce = matchMedia("(prefers-reduced-motion: reduce)").matches;
const wait = (ms) => new Promise((r) => setTimeout(r, reduce ? 0 : ms));
function draw(marks = {}) {
  row.textContent = "";
  for (let i = 0; i < CAP; i++) {
    const d = document.createElement("div");
    d.setAttribute("role", "listitem");
    const v = items[i];
    d.className = "box" + (v === undefined ? " empty" : "") + (i === Number(at.value) ? " chosen" : "") + (marks[i] ? " " + marks[i] : "");
    d.innerHTML = `${v === undefined ? "·" : v}<span class="i">${i}</span>`;
    row.append(d);
  }
  at.max = items.length;
  document.getElementById("ins").disabled = busy || items.length >= CAP;
  count.textContent = moves;
}
function reset() { items = [4, 8, 15, 16, 23, 42]; moves = 0; at.value = 2; say.textContent = "Choose an index, then insert or read."; draw(); }
async function insert() {
  const i = Math.max(0, Math.min(items.length, Number(at.value) || 0));
  if (busy || items.length >= CAP) return;
  busy = true;
  let moved = 0;
  for (let j = items.length - 1; j >= i; j--) {
    items[j + 1] = items[j];
    moved++;
    draw({ [j + 1]: "moved" });
    await wait(350);
  }
  items[i] = 99;
  moves += moved;
  draw({ [i]: "new" });
  say.textContent = moved ? `Inserting at index ${i} moved ${moved} item${moved === 1 ? "" : "s"} one box right, then wrote 99 into box ${i}.` : `Index ${i} is the end: nothing had to move. 99 went straight into box ${i}.`;
  busy = false;
  draw({ [i]: "new" });
}
function read() {
  const i = Math.max(0, Math.min(items.length - 1, Number(at.value) || 0));
  draw({ [i]: "new" });
  say.textContent = `a[${i}] is ${items[i]}: one step, straight to box ${i}, whatever its position.`;
}
document.getElementById("ins").addEventListener("click", insert);
document.getElementById("read").addEventListener("click", read);
document.getElementById("reset").addEventListener("click", reset);
at.addEventListener("input", () => draw());
addEventListener("keydown", (e) => { if (e.key === "ArrowRight") { at.value = Math.min(items.length, Number(at.value) + 1); draw(); } if (e.key === "ArrowLeft") { at.value = Math.max(0, Number(at.value) - 1); draw(); } });
reset();
</script>
</body>
</html>
```

```json
{
  "libraries": [],
  "strings": {
    "insert": "Insert 99",
    "read": "Read it",
    "reset": "Reset"
  }
}
```
