gsap.to(".ball", {
 y: 150,
 duration: 3,
 yoyo: true,
 repeat: -1,
 ease: "sine.inOut"
});
gsap.to(".ball", {
 keyframes: {
  "0%": { yPercent: 0, scaleX: 1, scaleY: 1 },
  "7%": { yPercent: 5, scaleY: 0.9, scaleX: 1.1 },
  "25%": { yPercent: 100, scaleX: 0.9},
  "50%": { yPercent: 500, scaleX: 1, scaleY: 1},
  "60%": { scaleX: 1.6, scaleY: 0.4},
  "65%": { yPercent: 500, scaleX: 1, scaleY: 1},
  "100%": { yPercent: 0, scaleX: 1, scaleY: 1},
  easeEach: "sine.out"
 },
 duration: 0.8,
 repeat: -1,
 transformOrigin: "center bottom"
});

background-image: url("moon.jpg");

background-image: url("candles.jpg");

background-image: none;

@keyframes nope {
  from {background-image: url("candles.jpg")}
  to {background-image: url("moon.jpg")}
}
.container {
  height: 20px;
  transition: height 2s ease-in-out;
}

.container:hover {
  height: calc-size(auto);
}

Coming soon?...

let tl = gsap.timeline()

tl.to("#lightning", { 
  morphSVG:  "#circle"
})
.to("#lightning", { 
  morphSVG:  "#star",
  scale: 0.6, 
  rotation: 360,
  transformOrigin: "center center"
})

The web is an infinite and unknowable canvas.

- Miriam Suzanne

100vw

100lvh

700px

FIXED

relative

flexbox

absolute

Sounds hard.
Why bother?

- people with better stuff to be doing

central

peripheral

peripheral

visual awareness

central

peripheral

peripheral

visual awareness

visual awareness

visual awareness

sneaky stuff

sneaky stuff

Inattentional blindness

Use motion to signal change

Use motion to signal change

Exit

Entrance

Persistent

UI transitions

Vanishing

Appearing

Levitating

UI transitions

Layout > Paint > Composite

Layout > Paint > Composite

Layout > Paint > Composite

Layout > Paint > Composite

Layout > Paint > Composite

Artboard 152

Layout > Paint > Composite

Artboard 152

Layout > Paint > Composite

Artboard 152

with a little bit of...

Magic

with 

FLIP

F

L

I

P

irst

ast

nvert

lay

{
  top: 300,
  left: 900,
  width: 200,
  height: 500,
}

width

height

top

left

First

el.getBoundingClientRect()
{
  top: 10,
  left: 200,
  width: 500,
  height: 1000,
}

Last

Where the magic happens

Layout

Paint

Invert

translate(200px, 100px) scale(2.5)

Play!

translate(0px, 0px) scale(1)
const first = box.getBoundingClientRect();

switchItUp()

const last = box.getBoundingClientRect();

let delta = {
 x: -1 * (last.left - first.left),
 y: -1 * (last.top - first.top),
};

box.style.transform = `translate(${delta.x}px, ${delta.y}px)`;

requestAnimationFrame(function () {
  el.classList.add("animate");
  el.style.transform = "none";
});
.animate {
 transition: transform 1s ease-in-out;
}
let state = Flip.getState(card);

switchItUp()

Flip.from(state)

MAKE IT MORE IMPOSSIBLE!

EVEN MORE IMPOSSIBLE!

Sometimes you have to break the rules.

F

L

I

P

irst

ast

nvert

lay

F

L

O

P

irst

ast

ffset

arent

Any sufficiently advanced technology is indistinguishable from magic.

– Arthur C. Clarke

https://codepen.io/hexagoncircle

View Transitions!

View Transitions!

function switchHands(data) {
 // Fallback for browsers that don't support this API:
 if (!document.startViewTransition) {
  reparentCard(data);
  return;
 }

 // With a transition:
 document.startViewTransition(() => reparentCard(data));
}

function reparentCard() {
 left
  ? rightHand.append(...leftHand.childNodes)
  : leftHand.append(...rightHand.childNodes);
 left = !left;
}

View Transitions!

.card {
 view-transition-name: card;
}

::view-transition-group(card) {
 animation-duration: 2s;
}

View Transitions!

use your magical powers responsibly

const animationIsOk = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
).matches;

if (animationIsOk) {
  // magic time
}

The End