mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-06 04:27:40 +00:00
shell: fish functions -> ~/.local/bin executables + bash/zsh ports; manage ~/.agents
- 16 cross-shell utilities converted to sh/bash chezmoi executables: ai c2p cp-appid extract_agents fab gdc gh-sonr-org-migrate ghg-clone ghn gho git-summary launch_omp_livediff_overlay lc-elir mdcp mdp pj (ghg-clone not named ghg: unrelated cargo binary owns that name) - cwd/history helpers stay per-shell: yy c cd clip-last + ghg/ghn/gho cd-wrappers in bash/functions/ and zsh/functions/, loaded by rc files - fish keeps only shell-state functions; converted ones now hit PATH - cp-appid ignore gating moved to .local/bin path - dot_agents/skills: 82 skills materialized from dotstate storage so dot_claude skill symlinks resolve on fresh bootstrap; dotstate profile/symlinks.json released .agents/skills .bashrc .zshrc
This commit is contained in:
1 parent
6776366ce6
commit
6406208b35
637 files changed
+100297
-497
No files matched your search
@@ -0,0 +1,186 @@
|
||||
# Animating Elements
|
||||
|
||||
## What This Covers
|
||||
|
||||
How to animate insertion, removal, and layout changes of elements. Read this when the task involves:
|
||||
|
||||
- Adding entrance, exit, or shared-layout transitions to UI
|
||||
- Choosing between spring physics (`spring(...)`) and time-based easing (`tween`)
|
||||
- Coordinating CSS transitions with the same easing as JS animations
|
||||
- Imperative animation loops via `requestAnimationFrame`
|
||||
|
||||
Import animation APIs from `remix/ui/animation`. For the smaller set of animation helpers that show up alongside other mixins, see `mixins-styling-events.md`.
|
||||
|
||||
## Animation Mixins
|
||||
|
||||
### `animateEntrance(config)`
|
||||
|
||||
Animates an element when inserted. Config specifies the **starting** style the element animates **from**:
|
||||
|
||||
```tsx
|
||||
<div
|
||||
mix={animateEntrance({
|
||||
opacity: 0,
|
||||
transform: 'translateY(8px)',
|
||||
...spring('smooth'),
|
||||
})}
|
||||
/>
|
||||
```
|
||||
|
||||
### `animateExit(config)`
|
||||
|
||||
Animates an element when removed. Config specifies the **ending** style the element animates **to**. The element stays in the DOM until the animation completes:
|
||||
|
||||
```tsx
|
||||
{
|
||||
isVisible && (
|
||||
<div
|
||||
key="panel"
|
||||
mix={[
|
||||
animateEntrance({ opacity: 0, transform: 'scale(0.98)', ...spring('smooth') }),
|
||||
animateExit({ opacity: 0, duration: 120, easing: 'ease-in' }),
|
||||
]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### `animateLayout(config?)`
|
||||
|
||||
Animates layout changes (position/size) using FLIP-style transforms:
|
||||
|
||||
```tsx
|
||||
{
|
||||
items.map((item) => (
|
||||
<li key={item.id} mix={animateLayout({ ...spring({ duration: 500, bounce: 0.2 }) })} />
|
||||
))
|
||||
}
|
||||
```
|
||||
|
||||
Options: `duration` (default 200ms), `easing` (default spring snappy), `size` (default true — include scale projection for size changes).
|
||||
|
||||
### Combining mixins
|
||||
|
||||
```tsx
|
||||
<div
|
||||
key="card"
|
||||
mix={[
|
||||
animateEntrance({ opacity: 0, transform: 'scale(0.95)', ...spring('snappy') }),
|
||||
animateExit({ opacity: 0, transform: 'scale(0.98)', duration: 120, easing: 'ease-in' }),
|
||||
animateLayout({ duration: 220, easing: 'ease-out' }),
|
||||
]}
|
||||
/>
|
||||
```
|
||||
|
||||
### Shared-layout swap
|
||||
|
||||
```tsx
|
||||
<div mix={css({ display: 'grid', '& > *': { gridArea: '1 / 1' } })}>
|
||||
{stateA ? (
|
||||
<div key="a" mix={[animateEntrance({ opacity: 0 }), animateExit({ opacity: 0 })]} />
|
||||
) : (
|
||||
<div key="b" mix={[animateEntrance({ opacity: 0 }), animateExit({ opacity: 0 })]} />
|
||||
)}
|
||||
</div>
|
||||
```
|
||||
|
||||
## Spring API
|
||||
|
||||
Physics-based spring animation. Returns a `SpringIterator` with `duration`, `easing`, and `toString()` for CSS.
|
||||
|
||||
### Presets
|
||||
|
||||
| Preset | Bounce | Duration | Character |
|
||||
| -------- | ------ | -------- | --------------------------- |
|
||||
| `smooth` | -0.3 | 400ms | Overdamped, no overshoot |
|
||||
| `snappy` | 0 | 200ms | Critically damped, quick |
|
||||
| `bouncy` | 0.3 | 400ms | Underdamped, visible bounce |
|
||||
|
||||
```tsx
|
||||
spring('bouncy')
|
||||
spring('snappy')
|
||||
spring('smooth')
|
||||
spring('bouncy', { duration: 300 }) // override duration
|
||||
```
|
||||
|
||||
### Custom spring
|
||||
|
||||
```tsx
|
||||
spring({ duration: 500, bounce: 0.3 })
|
||||
spring({ duration: 500, bounce: 0.3, velocity: 2 }) // continue momentum from gesture
|
||||
```
|
||||
|
||||
### Spread into animation mixins
|
||||
|
||||
Spreading a spring gives both `duration` and `easing`:
|
||||
|
||||
```tsx
|
||||
animateEntrance({ opacity: 0, ...spring('bouncy') })
|
||||
```
|
||||
|
||||
### CSS transitions
|
||||
|
||||
The iterator stringifies to `"550ms linear(...)"`:
|
||||
|
||||
```tsx
|
||||
css({ transition: `width ${spring('bouncy')}` })
|
||||
```
|
||||
|
||||
Or use the `spring.transition()` helper for multiple properties:
|
||||
|
||||
```tsx
|
||||
css({ transition: spring.transition('width', 'bouncy') })
|
||||
css({ transition: spring.transition(['left', 'top'], 'snappy') })
|
||||
```
|
||||
|
||||
### Web Animations API
|
||||
|
||||
```tsx
|
||||
element.animate(keyframes, { ...spring('bouncy') })
|
||||
```
|
||||
|
||||
### JS iteration
|
||||
|
||||
The iterator yields position values from 0 to 1, one per frame:
|
||||
|
||||
```tsx
|
||||
for (let t of spring('bouncy')) {
|
||||
let x = from + (to - from) * t
|
||||
updateSomething(x)
|
||||
await nextFrame()
|
||||
}
|
||||
```
|
||||
|
||||
## Tween API
|
||||
|
||||
Generator-based tween for animating values over time with cubic bezier easing. Prefer animation mixins or CSS transitions with `spring` for most UI work. Use `tween` for imperative `requestAnimationFrame` loops, canvas/WebGL, or non-CSS properties.
|
||||
|
||||
```tsx
|
||||
import { tween, easings } from 'remix/ui/animation'
|
||||
|
||||
let animation = tween({
|
||||
from: 0,
|
||||
to: 100,
|
||||
duration: 300,
|
||||
curve: easings.easeOut,
|
||||
})
|
||||
|
||||
animation.next() // initialize
|
||||
function tick(timestamp: number) {
|
||||
if (handle.signal.aborted) return
|
||||
let { value, done } = animation.next(timestamp)
|
||||
element.style.transform = `translateX(${value}px)`
|
||||
if (!done) requestAnimationFrame(tick)
|
||||
}
|
||||
requestAnimationFrame(tick)
|
||||
```
|
||||
|
||||
Built-in easings: `easings.linear`, `easings.ease`, `easings.easeIn`, `easings.easeOut`, `easings.easeInOut`.
|
||||
|
||||
## Practical Guidance
|
||||
|
||||
- Always key conditional or switching elements you expect to animate.
|
||||
- Use `animateLayout` only on the element whose position or size changes.
|
||||
- Prefer one clear transition intent per mixin: entrance starts from a style, exit ends at a style.
|
||||
- Default to `...spring()` for duration and easing in most cases.
|
||||
- Keep DOM work in `handle.queueTask(...)` or `ref(...)`, not in render.
|
||||
Reference in new issue
Block a user