tooyoung:blobity-cursor

Installation
SKILL.md

Blobity Cursor

Add a canvas-based custom cursor effect to landing pages. The cursor follows the mouse with spring physics, expands to wrap interactive elements, and inverts colors via mix-blend-mode: difference.

Core mechanism: Blobity creates a <canvas> overlay (position: fixed, pointer-events: none, z-index: max) and draws a blob that follows the cursor using the Kinet spring physics engine. With invert: true, the canvas uses mix-blend-mode: difference to create a color-inversion effect.

Quick Start (HTML)

Minimal working example — copy into any HTML page:

<!-- Hide default cursor -->
<style>
  body.blobity-active,
  body.blobity-active a,
  body.blobity-active button,
  body.blobity-active [data-blobity],
  body.blobity-active [data-blobity-tooltip] {
    cursor: none !important;
  }
</style>

<!-- Load Blobity via ESM CDN (npm: import Blobity from 'blobity') -->
<script type="module">
  import Blobity from "https://esm.sh/blobity@0.2.3";

  // Skip touch devices
  if ("ontouchstart" in window || navigator.maxTouchPoints > 0) {
    throw new Error("Touch device — skip Blobity");
  }

  const blobity = new Blobity({
    licenseKey: "opensource",
    invert: true,
    zIndex: 50,
    color: "#ffffff", // Canvas fill → difference with dark bg = light
    dotColor: "#10b981", // Resting cursor dot color
    radius: 6,
    magnetic: false,
    mode: "normal",
    focusableElements: "a, button, [data-blobity], [data-blobity-tooltip]",
    focusableElementsOffsetX: 5,
    focusableElementsOffsetY: 4,
    font: "'JetBrains Mono', monospace",
    fontSize: 16,
    fontWeight: 600,
    fontColor: "#0d1117", // Tooltip text color on canvas
    tooltipPadding: 12,
  });

  document.body.classList.add("blobity-active");
</script>

Add data-blobity-tooltip="Label text" to any element for tooltip mode:

<div class="card" data-blobity-tooltip="View details">...</div>

Installation

CDN (no build tool):

<script type="module">
  import Blobity from "https://esm.sh/blobity@0.2.3";
</script>

Other CDNs (cdn.jsdelivr.net, cdn.blobity.dev) have known 404/connection issues. Use esm.sh.

npm (with bundler):

# pnpm (recommended)
pnpm add blobity

# npm
npm install blobity

# yarn
yarn add blobity
import Blobity from "blobity";

Blobity has react and vue as optional peer dependencies. Ignore the warning if you're not using their bindings.

Theme Adaptation (Light/Dark)

The mix-blend-mode: difference formula is |page_pixel - canvas_pixel|. This means:

  • Dark page + white canvas → light result (standard inversion) ✓
  • Light page + dark canvas → light result (soft tint) ✓
  • Light page + white canvas → black result (harsh) ✗

Key rule: dark bg uses white color, light bg uses a dark color calculated from your target tint.

Recommended Color Scheme

Option Dark Mode Light Mode Notes
color #ffffff #190a11 Light mode produces soft mint #e6f5ee on white
dotColor #10b981 #111827 Accent green / dark gray
fontColor #0d1117 #000000 Tooltip text: dark→black on light bg, light→white on dark bg after difference

Theme Switching Pattern

Watch for theme attribute changes and update Blobity options dynamically:

const isDark = () =>
  document.documentElement.getAttribute("data-theme") !== "light";
// Alternative checks:
//   document.documentElement.classList.contains('dark')
//   window.matchMedia('(prefers-color-scheme: dark)').matches

const observer = new MutationObserver(() => {
  blobity.updateOptions({
    color: isDark() ? "#ffffff" : "#190a11",
    dotColor: isDark() ? "#10b981" : "#111827",
    fontColor: isDark() ? "#0d1117" : "#000000",
  });
});

observer.observe(document.documentElement, {
  attributes: true,
  attributeFilter: ["data-theme", "class"],
});

To calculate custom light-mode colors, see references/color-math.md.

Configuration Options

Option Type Default Description
licenseKey string Use 'opensource' for open-source projects
invert boolean false Enable mix-blend-mode: difference on canvas
color string '#000000' Canvas fill color when hovering focusable elements
dotColor string '#000000' Resting cursor dot color
radius number 4 Dot radius in pixels
magnetic boolean true Whether cursor snaps to element center on hover
mode string 'normal' Cursor mode
zIndex number -1 Canvas z-index
focusableElements string 'a, button' CSS selector for interactive elements
focusableElementsOffsetX number 0 Horizontal padding when wrapping elements
focusableElementsOffsetY number 0 Vertical padding when wrapping elements
font string Tooltip font family
fontSize number 16 Tooltip font size
fontWeight number 400 Tooltip font weight
fontColor string '#000000' Tooltip text color on canvas
tooltipPadding number 4 Tooltip inner padding

Tooltip Mode

Add data-blobity-tooltip to elements — cursor morphs into a text label instead of expanding:

<div class="step-card" data-blobity-tooltip="Step 1: Upload">...</div>
<a href="/docs" data-blobity-tooltip="Documentation">Docs</a>

Tooltip elements should be included in focusableElements via [data-blobity-tooltip] selector.

Light mode tooltip text visibility: tooltip background gets darkened by difference blend, so fontColor must also produce a light result after blending. Use #000000 for light mode (becomes white after |#fff - #000| = #fff).

Common Pitfalls

1. CDN 404 Errors

✗ cdn.jsdelivr.net/npm/blobity@latest/lib/blobity.min.js  → wrong path
✗ cdn.blobity.dev/by.js                                    → server down
✗ cdn.jsdelivr.net/npm/blobity@0.2.4                       → version doesn't exist
✓ esm.sh/blobity@0.2.3                                     → works

2. Cursor Invisible or Pure Black on Light Background

This is a mix-blend-mode: difference color math issue. See the Theme Adaptation section — use a dark color value for light backgrounds (NOT white).

3. Touch Device Detection

Always skip Blobity on touch devices — there's no mouse cursor to replace:

const isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
if (isTouchDevice) return;

4. SPA Page Navigation Cleanup

Blobity must be destroyed on route change to avoid canvas leaks:

// Astro view transitions
document.addEventListener(
  "astro:before-swap",
  () => {
    observer.disconnect();
    document.body.classList.remove("blobity-active");
    blobity.destroy();
  },
  { once: true },
);

// React Router / Vue Router
onUnmounted(() => {
  blobity.destroy();
});
// Or useEffect cleanup in React

5. Peer Dependency Warnings

Blobity declares react and vue as peer deps. Safe to ignore if not using their framework bindings:

# pnpm
pnpm add blobity --no-strict-peer-dependencies

# npm (if needed)
npm install blobity --legacy-peer-deps

6. z-index Conflicts

Set zIndex high enough to overlay page content but below modals/dialogs. 50 works for most cases. If your site has a sticky header at z-index: 100+, either raise Blobity's value or accept the cursor rendering behind the header.

Scroll Bounce

Add a playful bounce effect when user scrolls:

let scrollTimeout = null;
window.addEventListener(
  "scroll",
  () => {
    if (scrollTimeout) return;
    scrollTimeout = setTimeout(() => {
      blobity.bounce();
      scrollTimeout = null;
    }, 150);
  },
  { passive: true },
);

References

File Content
references/frameworks.md React hook, Vue 3 composable, Vue 2 mixin — complete templates
references/color-math.md mix-blend-mode: difference color calculation, lookup table, reverse formula
Related skills

More from shiqkuangsan/oh-my-daily-skills

Installs
21
GitHub Stars
15
First Seen
Feb 7, 2026