not sure how to explain that to you. need to add some "snapage" functionality to vertices and edges, to be able to attach and detach lines from wireframe model. output some code, without any frameworks or libraries used.: <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Visual Matrix Constructor</title>
  <style>
    body {
      margin: 0;
      overflow: hidden;
    }
    canvas {
      display: block;
    }
    .vmc-menu {
      display: none;
      position: absolute;
      background-color: rgba(0,0,0,0.1);
      border-radius: 5px;
      padding: 10px;
      box-shadow: 0 2px 5px rgba(0,0,0,0.1);
      z-index:1;
    }
    .vmc-menu label {
      display: block;
      margin-bottom: 10px;
    }
    .red-dot {
      position: absolute;
      width: 5px;
      height: 5px;
      background-color: red;
      border-radius: 50%;
      pointer-events: none;
      color:red;
      z-index:0;

    }
  </style>
</head>
<body>
  <div class="vmc-menu" id="vmc-menu">
    <label>Vertex X: <input type="number" id="vmc-vertex-x" step="0.1"></label>
    <label>Vertex Y: <input type="number" id="vmc-vertex-y" step="0.1"></label>
    <label>Vertex Z: <input type="number" id="vmc-vertex-z" step="0.1"></label>
    <button id="add-edge">Add Edge</button>
    <button id="remove-edge">Remove Edge</button>
  </div>
  <div class="red-dot" id="red-dot"></div>
  <script>
  const canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);

const ctx = canvas.getContext('2d');
const vmcMenu = document.getElementById('vmc-menu');

const vertices = [
  [0, 0, 0],
  [0, 1, 0],
  [1, 1, 0],
  [1, 0, 0],
  [0, 0, 1],
  [0, 1, 1],
  [1, 1, 1],
  [1, 0, 1],
];

const edges = [
  [0, 1],
  [1, 2],
  [2, 3],
  [3, 0],
  [0, 4],
  [1, 5],
  [2, 6],
  [3, 7],
  [4, 5],
  [5, 6],
  [6, 7],
  [7, 4],
];

const scale = 0.025;
const zoom = 1;
const offsetX = 0.5;
const offsetY = 0.5;

let angleX = 0;
let angleY = 0;
let angleZ = 0;
  let bestIndex = -1;
  let bestDistance = Infinity;
let startNewEdgeIndex = -1;
let isMouseDown = false;
let prevMousePos = null;

// Red Dot
const redDot = document.getElementById('red-dot');

// Add Edge
document.getElementById('add-edge').addEventListener('click', () => {
  if (bestIndex === -1) return;
  if (startNewEdgeIndex === -1) {
    startNewEdgeIndex = bestIndex;
  } else {
    edges.push([startNewEdgeIndex, bestIndex]);
    startNewEdgeIndex = -1;
  }
});

// Remove Edge
document.getElementById('remove-edge').addEventListener('click', () => {
  if (bestIndex === -1) return;
  edges.forEach((edge, index) => {
    if (edge.includes(bestIndex)) {
      edges.splice(index, 1);
    }
  });
});

function rotateX(angle) {
  const c = Math.cos(angle);
  const s = Math.sin(angle);
  return [
    [1, 0, 0],
    [0, c, -s],
    [0, s, c],
  ];
}

function rotateY(angle) {
  const c = Math.cos(angle);
  const s = Math.sin(angle);
  return [
    [c, 0, s],
    [0, 1, 0],
    [-s, 0, c],
  ];
}

function rotateZ(angle) {
  const c = Math.cos(angle);
  const s = Math.sin(angle);
  return [
    [c, -s, 0],
    [s, c, 0],
    [0, 0, 1],
  ];
}

function project(vertex, scale, offsetX, offsetY, zoom) {
  const [x, y, z] = vertex;
  const posX = (x - offsetX) * scale;
  const posY = (y - offsetY) * scale;
  const posZ = z * scale;

  return [
    (posX * (zoom + posZ) + canvas.width / 2),
    (posY * (zoom + posZ) + canvas.height / 2),
  ];
}

function transform(vertex, rotationMatrix) {
  const [x, y, z] = vertex;
  const [rowX, rowY, rowZ] = rotationMatrix;
  return [
    x * rowX[0] + y * rowX[1] + z * rowX[2],
    x * rowY[0] + y * rowY[1] + z * rowY[2],
    x * rowZ[0] + y * rowZ[1] + z * rowZ[2],
  ];
}

function extraterrestrialTransformation(vertex, frequency, amplitude) {
  const [x, y, z] = vertex;
  const cosX = (Math.cos(x * frequency) * amplitude);
  const cosY = (Math.cos(y * frequency) * amplitude);
  const cosZ = (Math.cos(z * frequency) * amplitude);

  return [x + cosX, y + cosY, z + cosZ];
}

function getDeviation(maxDeviation) {
const t = Date.now() / 1000;
const frequency = 100 / 50;
const amplitude = maxDeviation / 10;
const deviation = Math.sin(t * frequency) * amplitude;
return deviation.toFixed(3);
}

function render() {
  ctx.fillStyle = '#FFF';
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  const rotX = rotateX(angleX);
  const rotY = rotateY(angleY);
  const rotZ = rotateZ(angleZ);

  // Extraterrestrial transformation parameters
  const frequency = 1;
  const amplitude = 0.8;

  const transformedVertices = vertices.map(vertex => {
    const extraterrestrialVertex = extraterrestrialTransformation(vertex, frequency, amplitude);
    const cx = extraterrestrialVertex[0] - offsetX;
    const cy = extraterrestrialVertex[1] - offsetY;
    const cz = extraterrestrialVertex[2] - offsetY;

    const rotated = transform(transform(transform([cx, cy, cz], rotX), rotY), rotZ);

    return [
      rotated[0] + offsetX,
      rotated[1] + offsetY,
      rotated[2] + offsetY,
    ];
  });

  const projectedVertices = transformedVertices.map(vertex => project(vertex, canvas.height * scale, offsetX, offsetY, zoom));

ctx.lineWidth = 2;
ctx.strokeStyle = 'hsla(' + (angleX + offsetX + angleY + offsetY) * 55 + ', 100%, 30%, 0.8)';
ctx.beginPath();

for (let edge of edges) {
const [a, b] = edge;
const [x1, y1] = projectedVertices[a];
const [x2, y2] = projectedVertices[b];

const dist = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2 + (y2 - x1) ** 2 + (x2 - y1));
const angle = Math.atan2(y2 - y1, x2 - x1, x2 - y1, y2 - x1);

// Calculate control point for curved edge
const cpDist = 0.005 * dist;
const cpX = (x1 + x2) / 2 + cpDist * Math.cos(angle - Math.PI / 2) * getDeviation(0.2);
const cpY = (y1 + y2) / 2 + cpDist * Math.sin(angle - Math.PI / 2) * getDeviation(0.2);

ctx.moveTo(x1, y1, x2, y2);
ctx.quadraticCurveTo(cpX, cpY, x2, y2, x1, y1);
}

ctx.stroke();

canvas.addEventListener('mousedown', (event) => {
  isMouseDown = true;
  prevMousePos = { x: event.clientX, y: event.clientY };
});

canvas.addEventListener('mouseup', () => {
  isMouseDown = false;
  prevMousePos = null;
});

canvas.addEventListener('mousemove', (event) => {
  const mousePos = {
    x: event.clientX - canvas.getBoundingClientRect().left,
    y: event.clientY - canvas.getBoundingClientRect().top
  };
  
  bestIndex = -1;
  bestDistance = Infinity;

  projectedVertices.forEach((currVertex, index) => {
    const distance = Math.hypot(
      currVertex[0] - mousePos.x,
      currVertex[1] - mousePos.y
    );
    if (distance < bestDistance) {
      bestIndex = index;
      bestDistance = distance;
    }
  });
  
  if (bestDistance < 10 && bestIndex !== -1) {
    vmcMenu.style.display = 'block';
    vmcMenu.style.left = mousePos.x + 'px';
    vmcMenu.style.top = mousePos.y + 'px';

    document.getElementById('vmc-vertex-x').value = vertices[bestIndex][0];
    document.getElementById('vmc-vertex-y').value = vertices[bestIndex][1];
    document.getElementById('vmc-vertex-z').value = vertices[bestIndex][2];

    document.getElementById('vmc-vertex-x').dataset.vertexIndex = bestIndex;
    document.getElementById('vmc-vertex-y').dataset.vertexIndex = bestIndex;
    document.getElementById('vmc-vertex-z').dataset.vertexIndex = bestIndex;

    redDot.style.display = 'block';
    redDot.style.left = projectedVertices[bestIndex][0] - 3 + 'px';
    redDot.style.top = projectedVertices[bestIndex][1] - 3 + 'px';
  } else {
    vmcMenu.style.display = 'none';
    redDot.style.display = 'none';
  }

  if (isMouseDown && prevMousePos) {
    const deltaX = event.clientX - prevMousePos.x;
    const deltaY = event.clientY - prevMousePos.y;

    angleY += deltaX * 0.01;
    angleX += deltaY * 0.01;

    prevMousePos = { x: event.clientX, y: event.clientY };
  }
});

function updateVertexValue(event, indexToUpdate) {
  const newValue = parseFloat(event.target.value);
  const vertexIndex = parseInt(event.target.dataset.vertexIndex);

  if (!isNaN(newValue) && vertexIndex >= 0) {
    vertices[vertexIndex][indexToUpdate] = newValue;
  }
}

document.getElementById('vmc-vertex-x').addEventListener('input', (event) => {
  updateVertexValue(event, 0);
});
document.getElementById('vmc-vertex-y').addEventListener('input', (event) => {
  updateVertexValue(event, 1);
});
document.getElementById('vmc-vertex-z').addEventListener('input', (event) => {
  updateVertexValue(event, 2);
});

angleX += +getDeviation(0.0005);
angleY += +getDeviation(0.0005);
angleZ += +getDeviation(0.0005);

  requestAnimationFrame(render);
}

requestAnimationFrame(render);
window.addEventListener("resize", () => {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
});
  </script>
</body>
</html>