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

> Explore CSS transform properties like scale rotate and translate from the emilkowalski skills repository. Optimize animations for 60 fps with GPU acceleration.

- Repository: [Emil Kowalski/skills](https://github.com/emilkowalski/skills)
- Tags: deep-dive
- Published: 2026-08-07

---

**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`](https://github.com/emilkowalski/skills/blob/main/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.

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

```

Source: [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/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:**

```css
.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`](https://github.com/emilkowalski/skills/blob/main/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:**

```css
.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`](https://github.com/emilkowalski/skills/blob/main/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:**

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

```

Source: [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/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:**

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

```

Source: [`skills/emil-design-eng/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/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.

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

```

Source: [`skills/emil-design-eng/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/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):**

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

```

**Avoid (main thread execution):**

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

```

Source: [`skills/improve-animations/AUDIT.md`](https://github.com/emilkowalski/skills/blob/main/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.

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

```

Source: [`skills/prototype/PICKER.md`](https://github.com/emilkowalski/skills/blob/main/skills/prototype/PICKER.md) at line 60

---

## Source File Reference

| File | Purpose | Key Content |
|------|---------|-------------|
| [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) | Core animation standards | GPU-only rule, `transform-origin`, `scale()` feedback, `translateY()` keyframes |
| [`skills/review-animations/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/SKILL.md) | UI pattern guidelines | Popover vs. modal origin handling |
| [`skills/improve-animations/AUDIT.md`](https://github.com/emilkowalski/skills/blob/main/skills/improve-animations/AUDIT.md) | Performance auditing | Full transform strings, hardware acceleration |
| [`skills/emil-design-eng/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md) | Advanced techniques | 3D transforms, `preserve-3d`, reduced-motion |
| [`skills/prototype/PICKER.md`](https://github.com/emilkowalski/skills/blob/main/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`](https://github.com/emilkowalski/skills/blob/main/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`](https://github.com/emilkowalski/skills/blob/main/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`](https://github.com/emilkowalski/skills/blob/main/skills/prototype/PICKER.md) for the implementation pattern.