How to Start Entrance Animations from scale(0.95): CSS and React Implementation
Start entrance animations from scale(0.95) (or any value between 0.9–0.97) combined with opacity: 0, then transition to scale(1) and opacity: 1 using a 200ms strong ease-out curve to create a subtle pop-in effect.
The emilkowalski/skills repository defines strict animation standards in skills/review-animations/STANDARDS.md that explicitly discourage scaling from zero. Instead, the guidelines prescribe a slight scale-down approach for entrance animations that feels responsive without visual jarring.
Why You Should Avoid scale(0) for Entrances
According to the source code in STANDARDS.md lines 53-60, you should never start entrance animations from scale(0). Scaling from zero creates a dramatic, distracting zoom effect that draws unnecessary attention to the animation itself rather than the content.
The standards define a modest shrink-to-scale range of 0.9–0.97 as the starting point. This range provides just enough movement to signal "new element arriving" while maintaining subtlety. A value like scale(0.95) sits perfectly in the middle of this recommended range, offering a balanced "pop-in" feel.
Core Animation Standards from STANDARDS.md
The Scale and Opacity Combination
Always pair the initial scale reduction with opacity: 0. The standards require elements to fade in while scaling up, creating a cohesive entrance. In STANDARDS.md lines 53-60, the reference implementation sets both properties in the initial state class.
Recommended Easing Curves
For the transition timing, use the strong ease-out curve defined in STANDARDS.md lines 31-34:
cubic-bezier(0.23, 1, 0.32, 1)
This curve provides a responsive feel with a quick start and gentle deceleration, making the animation feel snappy yet smooth.
Duration Constraints
Keep entrance animations under 300ms. As specified in STANDARDS.md lines 41-48, 200ms is the recommended sweet spot for UI-level entrances. Longer durations feel sluggish, while shorter durations risk appearing abrupt.
Implementing the scale(0.95) Entrance Pattern
CSS Implementation with data-mounted
The preferred CSS approach uses a base .enter class for the hidden state and a data-mounted attribute to trigger the transition:
/* Base style – initial hidden state */
.enter {
transform: scale(0.95);
opacity: 0;
}
/* Active state – triggered via data attribute */
.enter[data-mounted="true"] {
transform: scale(1);
opacity: 1;
transition: transform 200ms cubic-bezier(0.23, 1, 0.32, 1),
opacity 200ms cubic-bezier(0.23, 1, 0.32, 1);
}
This pattern allows JavaScript to control the timing precisely by toggling the data-mounted attribute when the element is ready to appear.
React Component Pattern
As referenced in STANDARDS.md lines 99-100, use a useEffect hook to trigger the animation after mount:
import { useEffect, useState } from "react";
export default function EntranceCard({ children }) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
// Trigger entrance animation after component mounts
setMounted(true);
}, []);
return (
<div className="enter" data-mounted={mounted}>
{children}
</div>
);
}
The useState and useEffect combination ensures the animation runs only after the DOM element exists, preventing flashes of unstyled content or premature transitions.
Web Animations API Approach
For JavaScript-only implementations without CSS classes, use the WAAPI with the same parameters:
const element = document.querySelector(".enter");
element.animate(
[
{ transform: "scale(0.95)", opacity: 0 },
{ transform: "scale(1)", opacity: 1 }
],
{
duration: 200,
easing: "cubic-bezier(0.23, 1, 0.32, 1)",
fill: "forwards"
}
);
This approach provides the same scale(0.95) starting point and 200ms duration while allowing dynamic control via JavaScript.
Summary
- Never use
scale(0)for entrance animations; start fromscale(0.9)toscale(0.97)instead. - Combine scale with opacity: Begin at
opacity: 0and transition toopacity: 1simultaneously. - Use the strong ease-out curve:
cubic-bezier(0.23, 1, 0.32, 1)as defined inSTANDARDS.md. - Keep duration at 200ms: Under the 300ms maximum specified in the standards for UI entrances.
- Toggle visibility via
data-mounted: The recommended pattern inemilkowalski/skillsuses attribute selectors for clean state management.
Frequently Asked Questions
Why is scale(0.95) better than scale(0) for entrance animations?
Starting from scale(0) creates a jarring, dramatic zoom effect that distracts users from the content. The emilkowalski/skills standards explicitly prohibit this approach in STANDARDS.md lines 53-60 because it violates principles of subtle, functional animation. Starting from scale(0.95) provides just enough motion to signal a new element without drawing attention to the animation mechanics.
Can I use a different scale value like 0.9 or 0.97?
Yes. The standards specify a range of 0.9–0.97, so any value within this range is acceptable depending on your design context. Use scale(0.9) for a more pronounced entrance or scale(0.97) for an extremely subtle fade-in effect. The key is avoiding the extremes of 0 (too dramatic) or 1 (no animation).
How do I handle entrance animations for server-side rendered React components?
Apply the data-mounted pattern client-side only. Initialize the mounted state as false and set it to true inside useEffect (as shown in STANDARDS.md lines 99-100). This ensures the server renders the initial scale(0.95) state while the client handles the transition to scale(1) after hydration, preventing layout shifts or animation flashes on initial page load.
Where are the official animation standards documented?
The primary reference is skills/review-animations/STANDARDS.md in the emilkowalski/skills repository. This file contains the specific line references for scale ranges (lines 53-60), easing curves (lines 31-34), duration limits (lines 41-48), and React implementation patterns (lines 99-100). The SKILL.md file in the same directory provides additional context on how these standards are packaged for team use.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →