Skip to content

Every little fish swimming around is a visitor on this page right now, and one of them is you ( ´ ▽ ` )ノ If they get in the way of reading, feel free to turn them off.

Tangram Cursor cursor ​

A tangram that morphs with mouse cursor states, making your cursor super cool. ヽ(●`∀´●)ノ

TIP

This component is designed for mouse input. It is recommended to use a computer or a device with a mouse.

Tech Keywords ​

NameDescription
Anime.jsLightweight JavaScript animation library
Pointer EventsDetects pointer movement, clicks, hovers, and more, providing coordinates and target information
JS AnimationJavaScript-driven animation for more complex, precise control; popular libraries include GSAP and anime.js
SVG MorphSmoothly transitions SVG between different shapes
Document elementFromPoint()Gets the topmost element at the specified coordinates
Window getComputedStyle()Gets the resolved values of CSS properties on an element

Usage Examples ​

Basic Usage ​

Continuously transforms based on the cursor state.

none
pointer
text
wait
move
not-allowed
help
crosshair
zoom-in
zoom-out
grab
grabbing
vertical-text
cell
copy
alias
View example source code
vue
<template>
  <div class="w-full flex flex-col gap-10 p-6">
    <div class="example-ctrl flex flex-col gap-4">
      <base-checkbox
        v-model="visible"
        :label="t('show')"
      />
    </div>

    <div class="grid grid-cols-2 w-full gap-10 md:grid-cols-3">
      <div
        v-for="item in list"
        :key="item"
        class="border px-8 py-4 text-center"
        :style="{ cursor: item }"
      >
        <div class="text-sm opacity-60">
          {{ item }}
        </div>
      </div>
    </div>

    <cursor-trangram
      v-if="visible"
      class="z-[9999]"
    />
  </div>
</template>

<script setup lang="ts">
import type { CSSProperties } from 'vue'
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import BaseCheckbox from '../../base-checkbox.vue'
import CursorTrangram from '../cursor-trangram.vue'

interface Props {
  visible?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  visible: true,
})

const visible = ref(props.visible)

const list: CSSProperties['cursor'][] = [
  'none',
  'pointer',
  'text',
  'wait',
  'move',
  'not-allowed',
  'help',
  'crosshair',
  'zoom-in',
  'zoom-out',
  'grab',
  'grabbing',
  'vertical-text',
  'cell',
  'copy',
  'alias',
]

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

How It Works ​

Uses useElementByPoint to get the currently touched element.

Then uses getComputedStyle to get the target's specific CSS properties and sets the cursor style via the cursor property.

Finally, it's all about anime.js and SVG animations. (´,,•ω•,,)

Source Code ​

API ​

Props ​

type Cursor = NonNullable<CSSProperties['cursor']>

interface Props {
  /** 7 個積木顏色 */
  colors?: [string, string, string, string, string, string, string];
  size?: string;
  offsetX?: number | ((cursor: Cursor) => number);
  offsetY?: number | ((cursor: Cursor) => number);

  /** 可自定義位置。預設跟隨滑鼠 */
  positionProvider?: () => { x: number; y: number };
}

v0.90.7