JSFiddle - React, Tailwind, and code Playground

by Graham Dixon

HTML

<svg class="hidden">
  <defs>
    <g id="cube" class="cube-unit">
      <rect width="21" height="24" fill="var(--lightColor)" stroke="var(--strokeColor)" transform="skewY(30)" />
      <rect width="21" height="24" fill="var(--darkColor)" stroke="var(--strokeColor)" transform="skewY(-30) translate(21 24.3)" />
      <rect width="21" height="21" fill="var(--mainColor)" stroke="var(--strokeColor)" transform="scale(1.41,.81) rotate(45) translate(0 -21)" />
    </g>
  </defs>
</svg>

    <svg class="blue-cube" viewBox="0 -64 300 230">
 [{x: 0, y: 2}, {x: 0, y:1}, {x: 1, y: 2}, {x: 0, y: 0}, {x: 1, y:0}, {x: 2, y: 0}, {x: 0, y: 1}, {x: 2, y:1}, {x: 2, y: 2}]
      <!--  1, 3
      79, (79 + (3 * 21)) = 79 + 63 = 142
      79, (79 + (2 * 21)) = 79 + 42 = 121 -->
      // 0, 2
      // middle 3
      <use xlink:href="#cube" x="121" y="48"></use>
      <use xlink:href="#cube" x="121" y="24"></use>
      <use xlink:href="#cube" x="121" y="0"></use>
      // 0, 1
      // left 3
      100 - 79 = 21
      0, 1 + depth 1
      <use xlink:href="#cube" x="100" y="60"></use>
      <use class="m-left" xlink:href="#cube" x="100" y="36"></use>
      <use class="m-left" xlink:href="#cube" x="100" y="12"></use>
      // 1, 2
      // 1, 2
      // 142 - 79 = 63 = 3
      // right 3
      <use xlink:href="#cube" x="142" y="60"></use>
      <use xlink:href="#cube" x="142" y="36"></use>
      <use xlink:href="#cube" x="142" y="12"></use>
    123   3
    456   5 6
    789  
 // 0, 0
      // left 1
      <g class="m-left">
        <use xlink:href="#cube" x="79" y="72"></use>
        <use xlink:href="#cube" x="79" y="48"></use>
        <use xlink:href="#cube" x="79" y="24"></use>
      </g>
      // 1, 0
      // middle 2
      <use xlink:href="#cube" x="121" y="72"></use>
      <use xlink:href="#cube" x="121" y="48"></use>
      <use xlink:href="#cube" x="121" y="24"></use>
      // 2, 0
      // right 1
      <g class="m-right">
        <use xlink:href="#cube" x="163" y="72"></use>
    ...

CSS

body {
  font-family: "Roboto", sans-serif;
  margin: 0 auto;
  text-align: center;
}

.hidden {
  display: none;
}

.cube-unit {
  fill-opacity: 0.9;
  stroke-miterlimit: 0;
}

.blue-cube {
  --mainColor: #009cde;
  --strokeColor: #0079ad;
  --lightColor: #00affa;
  --darkColor: #008bc7;
}

JavaScript

document.addEventListener('DOMContentLoaded', function() {
    const cubeSize = 3; // Example for a 3x3x3 Rubik's Cube
    generateRubiksCube(cubeSize);
});

function generateRubiksCube(n) {
    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    
    svg.setAttribute("viewBox", "0 0 300 230");
    svg.classList.add("blue-cube");
        
        
    // Adjust these values based on the exact layout and perspective desired
    const baseX = 79; // Starting x-coordinate for the first cube at the leftmost position
    const baseY = 12; // Starting y-coordinate for the lowest cube in the front row
    const xIncrement = 21; // Horizontal increment for moving right in the SVG
    const yIncrement = 12; // Vertical increment for moving up in the SVG
    const depthXOffset = 21; // Additional x offset for each layer deeper into the cube
    const depthYOffset = -12; // Y offset for each layer deeper, giving the 3D effect

    const cubePositions = generateCubePos(n);
    
    //console.log(cubePositions);
    
    cubePositions.forEach((cube) => {
      const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
      use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#cube');
      use.setAttribute('x', cube.x);
      use.setAttribute('y', cube.y);
      svg.appendChild(use);
    });

    document.body.appendChild(svg);
}

const cubeSize = 3; // Example for a 4x4x4 cube

function generateSquareMatrix(n) {
  let matrix = [];
  let num = 1;
  for (let row = 0; row < n; row++) {
      let newRow = [];
      for (let col = 0; col < n; col++) {
          newRow.push(num++);
      }
      matrix.push(newRow);
  }
  return matrix;
}

function generateCubePos(n) {
    let positions = [];
    const baseX = 79, baseY = 48; // Adjust these based on the first cube position
    const xIncrement = 21, yIncrement = 24; // Horizontal and vertical increments
    const depthX = 21, depthY = 12; // Adjustments for depth to create the 3D...