skill
delete-icon-motion
Upgrade a static Delete button into a polished semantic sweep-into-bin motion for React, Vue, and Web Components.
Set up
Skills are installed by placing their folder where your agent loads skills.
The download comes from github.com/youwenjiujiu/delete-icon-motion itself, not from our server, so what you get is exactly what its author published.
Install instructions come from the README
README
synced Oct 23, 2026delete-icon-motion
Generate and integrate a polished semantic Delete button motion — the trash lid lifts and hovers level, a broom winds up and sweeps the "Delete" label away letter-by-letter, debris arcs into the open bin mouth, the returning stroke reveals "Done", and the lid drops shut with a settle bounce. The loop is seam-free.
No Figma. No Lottie. No runtime dependency in the Web Component core. Pure CSS keyframes + SVG in a Shadow DOM custom element.
→ Open the interactive demo
What it does
delete-icon-motion is an Agent Skill for upgrading an existing static Delete button into a full delete narrative. It can:
- replace the button's visual with the animated control while preserving the real
<button>, its click handler, focus behavior, and accessible name; - integrate into React, Next.js, Vue, or Nuxt via thin wrappers, or any other frontend via the framework-neutral Web Component;
- play once per activation (
restart()), firingmotion-completewhen the real delete should run; - re-brand through attributes only —
accent,label,result-label,duration— no CSS surgery; - respect
prefers-reduced-motionby holding the resting sealed-bin icon; - stay SSR-safe (the ES module registers the element only in a browser).
The skill is intentionally Delete-only. Home, Search, and unrelated icon meanings are outside its scope.
Quick start
Claude Code
git clone https://github.com/youwenjiujiu/delete-icon-motion.git ~/.claude/skills/delete-motion
Then ask naturally — "give this delete button the delete motion" — or invoke /delete-motion.
Codex
git clone https://github.com/youwenjiujiu/delete-icon-motion.git ~/.agents/skills/delete-icon-motion
$delete-icon-motion Upgrade the static Delete button in this React app.
Direct integration
Web Component (any framework)
import "./icon-motion/web-component/icon-motion.js";
<button type="button" aria-label="Delete" id="del"
style="position:relative;width:202px;height:62px">
<icon-motion id="delMotion" accent="#CC0033" label="Delete" result-label="Done"
autoplay="false" loop="false" presentation="inline" aria-hidden="true"
style="position:absolute;inset:0;overflow:visible"></icon-motion>
</button>
<script>
del.addEventListener("click", () => delMotion.restart());
delMotion.addEventListener("motion-complete", () => {/* real delete */});
</script>
React
import { useRef } from "react";
import { IconMotion } from "./icon-motion/react/IconMotion.js";
export function DeleteButton({ onDelete }) {
const motion = useRef(null);
return (
<button type="button" aria-label="Delete"
onClick={() => motion.current?.restart()}
style={{ position: "relative", width: 202, height: 62 }}>
<IconMotion ref={motion} accent="#CC0033" label="Delete" result-label="Done"
autoplay={false} loop={false} presentation="inline" aria-hidden="true"
onMotionComplete={onDelete}
style={{ position: "absolute", inset: 0, overflow: "visible" }} />
</button>
);
}
Vue 3
<script setup>
import { ref } from "vue";
import { IconMotion } from "./icon-motion/vue/IconMotion.js";
const motion = ref(null);
const emit = defineEmits(["delete"]);
</script>
<template>
<button type="button" aria-label="Delete" @click="motion?.restart()">
<IconMotion ref="motion" accent="#CC0033" label="Delete" result-label="Done"
:autoplay="false" :loop="false" presentation="inline" aria-hidden="true"
@motion-complete="emit('delete')" />
</button>
</template>
Runtime API
| Kind | Names |
|---|---|
| Attributes | accent light background bar foreground muted shadow label result-label duration autoplay loop paused presentation |
| Methods | play() pause() restart() seek(ms) setProgress(0..1) |
| Events | motion-ready motion-play motion-pause motion-seek motion-loop motion-complete |
Booleans must be set explicitly when false: autoplay="false". The control's design aspect is 300 : 92 (≈ 202 × 62 px slot). duration rescales the whole timeline (default 4180 ms) — every beat is percentage-based, so rescaling is safe.
"Done" shows during 72–93 % of the timeline. A non-looping run intentionally ends back at the resting "Delete" state (the loop is seam-free); to hold on "Done", call setProgress(0.8); pause() inside motion-complete.
Motion design notes
- Anticipation → stroke → follow-through: the broom winds back before the sweep, accelerates through the text, and lifts to the bin mouth to empty the debris.
- Contact-coupled erase: the label starts disappearing exactly when the broom foot reaches its last letter, and the erase edge tracks the foot — no independent timelines.
- Seam-free loop: surface tint, both labels, lid, and broom all resolve to the 0 % pose by 100 %.
- Do not edit the keyframes'
transform-originvalues. They are pre-converted fortransform-box: fill-box(bounding-box-relative): broom pivot17px 58px, lid pivot12.6px 10.2px. The lid's closed pose carries a constant +7° corrective rotation compensating the artwork's own tilt.