install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/codex/svelte-transitions-animations" ~/.claude/skills/intense-visions-harness-engineering-svelte-transitions-animations-ecfda3 && rm -rf "$T"
manifest:
agents/skills/codex/svelte-transitions-animations/SKILL.mdsource content
Svelte Transitions and Animations
Add enter/exit animations, list reordering motion, and spring physics to Svelte elements using built-in and custom transitions
When to Use
- You need elements to animate in/out when they enter or leave the DOM based on conditional rendering
- You want to animate list reordering when items move within an
block{#each} - You need smooth value transitions (progress bars, counters) using tweened or spring stores
- You are building custom animation functions for reusable transition effects
Instructions
Built-in transitions:
- Import and apply transitions from
. They run when the element is conditionally rendered:svelte/transition
<script> import { fade, fly, slide, scale, blur } from 'svelte/transition' let show = $state(true) </script> <button onclick={() => show = !show}>Toggle</button> {#if show} <div transition:fade>Fades in and out</div> <div transition:fly={{ y: 20, duration: 300 }}>Flies from below</div> <div transition:slide>Slides open/closed</div> {/if}
- Use
andin:
directives to apply different transitions for enter and exit:out:
{#if show} <div in:fly={{ x: -100 }} out:fade> Flies in from left, fades out </div> {/if}
- Pass parameters to customize built-in transitions:
<div transition:fly={{ x: 0, y: 50, duration: 400, easing: quintOut }}> Parameterized fly </div>
Import easing functions from
svelte/easing: linear, cubicIn, cubicOut, cubicInOut, quintOut, elasticOut, backOut, etc.
Custom transitions:
- Write a custom transition function that returns CSS keyframes or a tick function:
// CSS-based custom transition (most performant) function swoosh(node: Element, { duration = 300 } = {}) { return { duration, css: (t: number) => ` transform: translateX(${(1 - t) * 100}%) rotate(${(1 - t) * 45}deg); opacity: ${t}; `, }; }
// JS-based tick function (for canvas or non-CSS animations) function typewriter(node: Element, { speed = 40 } = {}) { const text = node.textContent ?? ''; return { duration: text.length * speed, tick: (t: number) => { node.textContent = text.slice(0, Math.floor(t * text.length)); }, }; }
Animating list items with animate:flip:
- Use
to smoothly reorder elements inanimate:flip
blocks when items move:{#each}
<script> import { flip } from 'svelte/animate' import { fade } from 'svelte/transition' let items = $state(['A', 'B', 'C', 'D']) function shuffle() { items = [...items].sort(() => Math.random() - 0.5) } </script> <button onclick={shuffle}>Shuffle</button> {#each items as item (item)} <div animate:flip={{ duration: 300 }} transition:fade> {item} </div> {/each}
Note:
(item) — the key expression — is required for animate:flip to track element identity.
Tweened and spring stores for smooth value transitions:
- Use
for smooth numeric value interpolation (progress bars, counters):tweened
<script> import { tweened } from 'svelte/motion' import { cubicOut } from 'svelte/easing' const progress = tweened(0, { duration: 500, easing: cubicOut }) function complete() { progress.set(1) } </script> <progress value={$progress} /> <button onclick={complete}>Complete</button>
- Use
for physics-based motion that overshoots and settles:spring
<script> import { spring } from 'svelte/motion' const pos = spring({ x: 0, y: 0 }, { stiffness: 0.1, damping: 0.25 }) </script> <div style="transform: translate({$pos.x}px, {$pos.y}px)" onmousemove={(e) => pos.set({ x: e.clientX, y: e.clientY })} />
Deferred transitions (crossfade):
- Use
to animate an element from one position to another across the DOM (shared element transition):crossfade
<script> import { crossfade } from 'svelte/transition' const [send, receive] = crossfade({ duration: 400 }) </script> {#if inList} <div in:receive={{ key: item.id }} out:send={{ key: item.id }}> {item.name} </div> {:else} <div in:receive={{ key: item.id }} out:send={{ key: item.id }}> {item.name} </div> {/if}
Details
How transitions work:
Svelte compiles
transition:, in:, and out: directives into JavaScript that runs when the element is added to or removed from the DOM. CSS-based transitions run entirely on the compositor thread and do not block the main thread.
modifier:global
By default, transitions only run when the direct parent
{#if} changes. Add :global to run the transition when any ancestor condition changes:
{#if outerCondition} {#if innerCondition} <div transition:fade|global> Fades when either condition changes </div> {/if} {/if}
Transition events:
Listen to transition lifecycle events:
<div transition:fly onintrostart={() => console.log('entering')} onintroend={() => console.log('entered')} onoutrostart={() => console.log('leaving')} onoutroend={() => console.log('left')} />
Performance considerations:
- Prefer CSS-based custom transitions (return
) over JS tick functions — CSS runs off the main threadcss - Avoid animating
/width
— useheight
andtransform: scaleX()
insteadtransform: scaleY()
animates height and may cause layout thrash on complex elements; preferslide
or custom transitions for performance-sensitive casesscale
Source
https://svelte.dev/docs/svelte/transition
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.