Skip to content

Render Glitch Card card

A tribute to the Windows XP window-dragging ghost trail bug.

Tech Keywords

NameDescription
Pointer EventsDetects pointer movement, clicks, hovers, and more, providing coordinates and target information
Canvas 2D APIBasic 2D drawing API that efficiently renders graphics too complex for the DOM
CSS AnimationImplemented with CSS transition and animation
DOM to ImageConverts DOM elements into images, based on SVG foreignObject

Usage Examples

Basic Usage

Try dragging the window! ( ´ ▽ ` )ノ

Hello, Windows XP!

Try dragging this window

View example source code
vue
<template>
  <div class="w-full flex flex-col gap-4 py-4">
    <div class="flex items-center justify-center py-[8vh]">
      <card-render-glitch
        v-slot="{ bindHandle }"
        :draggable
        class="window z-50 overflow-hidden border rounded-xl shadow-xl"
      >
        <div
          :ref="bindHandle"
          class="handle w-full flex items-center px-4"
          :class="draggable ? 'cursor-move' : 'cursor-no-drop'"
        >
          <div class="flex-1 select-none text-center text-sm font-medium">
            Hello, Windows XP!
          </div>

          <button class="mb-1 text-2xl">
            ×
          </button>
        </div>

        <div class="flex flex-col gap-2 p-8 px-12">
          <base-checkbox
            v-model="draggable"
            :label="t('enableDrag')"
          />

          <p class="leading-relaxed">
            {{ t('tryDrag') }}
          </p>
        </div>
      </card-render-glitch>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import BaseCheckbox from '../../base-checkbox.vue'
import CardRenderGlitch from '../card-render-glitch.vue'

const draggable = ref(true)

const { t } = useI18n()
</script>

<style lang="sass" scoped>
:deep(.window)
  background: light-dark(#FFF, #1e1e1e)
  border-color: light-dark(#d0d0d0, #888)
  color: light-dark(#374151, #d1d5db)
  .handle
    background: light-dark(#f3f4f6, #111827)
    color: light-dark(#1f2937, #d1d5db)
</style>

How It Works

Converts the DOM into an image, then continuously draws the image onto a canvas.

How to convert DOM to Image?

The original implementation idea was to use v-for to generate multiple default slot contents like btn-ninja, but the performance was terrible, so canvas was used instead.

The challenge was: "How to draw DOM onto a canvas? ლ(╹ε╹ლ)"

Both html2canvas and dom-to-image were not ideal. Later, a complete implementation was found in the vfx.js library.

So I copied it over and slightly modified it to fit my needs. ◝( •ω• )◟

Source Code

API

Props

interface Props {
  draggable?: boolean;
  throttle?: number;
}

Methods

interface Expose {
  clearArtifacts: () => void;
}

Slots

interface SlotScope {
  isDragging: boolean;
  /**
   * 用於綁定拖動把手
   * @param el - 要綁定的元素
   */
  bindHandle: (el: any) => void;
}

interface Slots {
  default?: (params: SlotScope) => unknown;
}

v0.69.0