A 3D Video Player

<m-group sx="0.4" sy="0.4" y="2">
  <m-video
    z="3"
    y="7"
    width="25"
    rx="0"
    ry="0"
    start-time="0"
    loop="true"
    src="https://public.mml.io/charge.mp4"
  >
    <m-label
      onclick="restart(event.currentTarget.parentNode)"
      content="restart"
      x="10"
      y="-6"
      font-size="100"
      width="4.5"
      alignment="center"
      height="1.5"
      color="#cccccc"
    ></m-label>
    <m-label
      onclick="pause(event.currentTarget.parentNode)"
      content="pause"
      x="-10"
      y="-6"
      font-size="100"
      width="4.5"
      alignment="center"
      height="1.5"
      color="#cccccc"
    ></m-label>
    <m-label
      onclick="unpause(event.currentTarget.parentNode)"
      content="unpause"
      x="-5"
      y="-6"
      font-size="100"
      width="4.5"
      alignment="center"
      height="1.5"
      color="#cccccc"
    ></m-label>
    <m-label
      onclick="resume(event.currentTarget.parentNode)"
      content="resume"
      x="5"
      y="-6"
      font-size="100"
      width="4.5"
      alignment="center"
      height="1.5"
      color="#cccccc"
    ></m-label>
    <m-label
      onclick="toggleEnabled(event.currentTarget.parentNode)"
      content="enable"
      x="0"
      y="-6"
      font-size="100"
      width="4.5"
      alignment="center"
      height="1.5"
      color="#cccccc"
    ></m-label>
    <m-label
      class="attributes-label"
      content="attrs:"
      x="0"
      y="6.5"
      padding="20"
      font-size="50"
      width="25"
      alignment="center"
      height="2"
      color="green"
      font-color="white"
    ></m-label>
  </m-video>
</m-group>
<script>
  function updateAttributesLabel(videoTag) {
    const attributes = [];
    for (const attr of videoTag.getAttributeNames()) {
      const val = videoTag.getAttribute(attr);
      attributes.push(`${attr}="${val}"`);
    }
    const attributesLabel = videoTag.querySelector(".attributes-label");
    if (attributesLabel) {
      attributesLabel.setAttribute("content", `<m-video ${attributes.join(" ")}></m-video>`);
    }
  }

  function restart(videoTag) {
    videoTag.setAttribute("pause-time", document.timeline.currentTime);
    videoTag.setAttribute("start-time", document.timeline.currentTime);
    videoTag.removeAttribute("pause-time");
    updateAttributesLabel(videoTag);
  }

  function toggleEnabled(videoTag) {
    const enabled = videoTag.getAttribute("enabled") !== "false";
    videoTag.setAttribute("enabled", (!enabled).toString());
    updateAttributesLabel(videoTag);
  }

  function pause(videoTag) {
    videoTag.setAttribute("pause-time", document.timeline.currentTime);
    updateAttributesLabel(videoTag);
  }

  function unpause(videoTag) {
    videoTag.removeAttribute("pause-time");
    updateAttributesLabel(videoTag);
  }

  function resume(videoTag) {
    if (!videoTag.hasAttribute("pause-time")) return;
    const startTime = parseFloat(videoTag.getAttribute("start-time")) || 0;
    const pauseTime = parseFloat(videoTag.getAttribute("pause-time")) || 0;
    const playedDuration = pauseTime - startTime;
    const newStartTime = document.timeline.currentTime - playedDuration;
    videoTag.removeAttribute("pause-time");
    videoTag.setAttribute("start-time", newStartTime);
    updateAttributesLabel(videoTag);
  }

  for (const video of document.querySelectorAll("m-video")) {
    updateAttributesLabel(video);
  }
</script>

Last updated