CSS Transform Properties in the Emil Kowalski Skills Repository: A Complete Guide

Use transform, transform-origin, scale(), translateX/Y(), rotateX/Y(), transform-style: preserve-3d, and will-change: transform for GPU-accelerated, 60 fps animations.

The Skills repository by Emil Kowalski (emilkowalski/skills) documents battle-tested conventions for performant UI animations. This guide covers every CSS transform property discussed across the codebase, with source file references and production-ready code examples.


Core Transform Properties

transform

The foundational property that enables all GPU-accelerated motion. According to skills/review-animations/STANDARDS.md, only transform and opacity should be animated because they run exclusively on the compositor thread, bypassing layout and paint calculations.

/* GPU-only animation — no layout thrashing */
.card {
  transform: translateX(100px);
}

Source: skills/review-animations/STANDARDS.md at line 112


transform-origin

Controls the anchor point for scaling and rotation operations. The repository distinguishes between popover/tooltip origins (trigger-anchored) and modal origins (centered).

Popover pattern with custom property:

.popover {
  transform-origin: var(--transform-origin);
  transform: scale(0.95);
}

This aligns the popover's animation with the element that triggered it, creating natural visual continuity.

Source: skills/review-animations/STANDARDS.md at line 56


Transform Functions

scale()

Used for press feedback and entrance animations. The repository recommends scale(0.97) for button presses and scale(0.95) combined with opacity for element entrances.

Press feedback implementation:

.button:active {
  transform: scale(0.97);
  transition: transform 160ms ease-out;
}

Important: Scaling from 0 is discouraged as unrealistic. Use scale(0.95) with opacity instead.

Source: skills/review-animations/STANDARDS.md at line 59


translateX() and translateY()

The primary translation functions for horizontal and vertical movement. Used extensively in keyframe definitions.

Vertical slide-in animation:

@keyframes slideIn {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

Source: skills/review-animations/STANDARDS.md at line 86


rotateX() and rotateY()

Enable true 3D depth effects when combined with transform-style: preserve-3d. These create coin-flip, orbit, and depth animations without JavaScript overhead.

3D card flip:

.card {
  transform-style: preserve-3d;
  transition: transform 500ms ease;
}
.card:hover {
  transform: rotateY(180deg);
}

Source: skills/emil-design-eng/SKILL.md at lines 370–376


transform-style: preserve-3d

Required for 3D transformations to propagate to child elements. Without this property, children flatten into their parent's plane.

.scene {
  transform-style: preserve-3d;
  /* Now children can use rotateX/Y with depth preserved */
}

Source: skills/emil-design-eng/SKILL.md at line 376


Performance Optimizations

Full Transform Strings Over Shorthand

The repository explicitly rejects Framer Motion shorthand (x, y, scale) in favor of full transform strings. Shorthand properties execute on the main thread, risking frame drops.

Recommended (compositor thread):

<motion.div animate={{ transform: "translateX(100px)" }} />

Avoid (main thread execution):

<motion.div animate={{ x: 100 }} />

Source: skills/improve-animations/AUDIT.md at line 75


will-change: transform

Hints to browsers that an element will animate, allowing early layer promotion. Use sparingly—only on elements that will actually animate.

.picker-highlight {
  will-change: transform;
}

Source: skills/prototype/PICKER.md at line 60


Source File Reference

File Purpose Key Content
skills/review-animations/STANDARDS.md Core animation standards GPU-only rule, transform-origin, scale() feedback, translateY() keyframes
skills/review-animations/SKILL.md UI pattern guidelines Popover vs. modal origin handling
skills/improve-animations/AUDIT.md Performance auditing Full transform strings, hardware acceleration
skills/emil-design-eng/SKILL.md Advanced techniques 3D transforms, preserve-3d, reduced-motion
skills/prototype/PICKER.md Component examples will-change implementation

Summary

  • Restrict animations to transform and opacity for guaranteed compositor-thread execution
  • Use transform-origin: var(--transform-origin) for popovers aligned to triggers
  • Prefer scale(0.97) for press feedback, avoid scaling from 0
  • Combine rotateX/Y with preserve-3d for hardware-accelerated 3D without JavaScript
  • Write full transform strings in animation libraries to stay off the main thread
  • Apply will-change: transform only to elements that will actually animate

Frequently Asked Questions

Why does the repository recommend against Framer Motion's x, y, and scale props?

These shorthand properties execute animations on the main thread rather than the compositor thread. According to skills/improve-animations/AUDIT.md, using transform: "translateX(100px)" ensures hardware acceleration and prevents frame drops during complex animations.

What's the difference between popover and modal transform origins in this system?

Popovers use transform-origin: var(--transform-origin) to align their scaling animation with the trigger element, creating visual continuity. Modals, which have no triggering element, remain centered with the default origin. This distinction is documented in skills/review-animations/STANDARDS.md.

When should will-change: transform be applied?

Use it on elements that will imminently animate, such as a picker highlight moving between options. The repository warns against overuse—will-change consumes GPU memory, so apply it only as needed and consider removing it after animations complete. See skills/prototype/PICKER.md for the implementation pattern.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →