Scramble

Details

Characters from Open Peeps.

I'm using bitty for the event to element wiring. The rest of the code is below. The [! include ... !] calls are what's loading the SVG images inline.

The HTML

<div hidden>
  [! include "_wrappers/svgs-body.html" !]
  [! include "_wrappers/svgs-head.html" !]
  [! include "_wrappers/svgs-face.html" !]
</div>

<bitty-2-0 data-connect="ThePeeps" data-send="peeps">
  <div data-receive="peeps"></div>
  <button data-send="scrambleBody|peep">Scramble Bodies</button>
  <button data-send="scrambleHead|peep">Scramble Heads</button>
</bitty-2-0>

The JavaScript

class State2 {
  scrambleBody() {
    shuffleArray(this.bodies);
  }

  scrambleHead() {
    shuffleArray(this.heads);
  }
}

function shuffleArray(array) {
  let currentIndex = array.length;
  let randomIndex;
  while (currentIndex != 0) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex--;
    [array[currentIndex], array[randomIndex]] = [
      array[randomIndex],
      array[currentIndex],
    ];
  }
}

const s2 = new State2();

window.ThePeeps = class {
  bittyInit() {
    s2.bodies = [...document.querySelectorAll("[data-part=body]")].toSpliced(
      12,
    );
    s2.faces = [...document.querySelectorAll("[data-part=face]")].toSpliced(
      12,
    );
    s2.heads = [...document.querySelectorAll("[data-part=head]")].toSpliced(
      12,
    );
  }

  peep(_event, el) {
    el.replaceChildren(s2.bodies[el.dataset.num]);
    el.appendChild(s2.heads[el.dataset.num]);
    el.appendChild(s2.faces[el.dataset.num]);
  }

  async peeps(_event, el) {
    for (let num = 0; num < 12; num += 1) {
      let peep = document.createElement("div");
      peep.dataset.num = num;
      peep.dataset.receive = "peep";
      await el.appendChild(peep);
    }
    this.api.forward(null, "peep");
  }

  scrambleBody(_event, _el) {
    s2.scrambleBody();
  }

  scrambleHead(_event, _el) {
    s2.scrambleHead();
  }
}

The CSS

[data-part=body] {
  position: absolute;
  top: 36px;
  left: 10px;
  width: 70px;
  height: 70px;
}

[data-part=face] {
  position: absolute;
  top: 13px;
  left: 42px;
  width: 30px;
  height: 30px;
}


[data-receive=peeps] {
  display: flex;
  flex-wrap: wrap;
}


[data-receive=peep] {
  margin: var(--default-margin);
  position: relative;
  width: 100px;
  height: 100px;
}

[data-part=head] {
  position: absolute;
  top: 0px;
  left: 28px;
  width: 50px;
  height: 50px;
}