Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
info
https://codepen.io/jh3y/pen/eYpmBxQ
https://codemyui.com/?p=29617
- const POSITIONS = ['middle', 'left', 'right', 'bottom']
mixin shirt(posIndex)
svg.t-shirt(class=`t-shirt--${POSITIONS[posIndex]}` xmlns='http://www.w3.org/2000/svg' width='245' height='230' viewbox='0 0 64.8 60.9')
defs
if (posIndex === 0)
clipPath#clipMain
rect(width="65" height="61")
if (posIndex === 1)
clipPath#clipLeft
rect(width="22.5" height="61")
if (posIndex === 2)
clipPath#clipRight
rect(x="42.3" width="22.5" height="61")
g.t-shirt__shirt(stroke='#000')
if (posIndex === 1 || posIndex === 2)
g.t-shirt__arm(class=`t-shirt__arm--${posIndex === 1 ? 'left' : 'right'}` clip-path=`url(#clip${posIndex === 1 ? 'Left' : 'Right'})`)
path(d='M251.8 109.2a36 17.5 0 01-34 11.6 36 17.5 0 01-33.9-11.6l-31.5 4.8-50 50 37 36.8 13-13v142.7h130.9V187.7l13.1 13.1 36.9-36.8-50-50z' transform='matrix(.26468 0 0 .2626 -25.2 -27.2)' stroke-width='5' stroke-linecap='square')
if (posIndex === 0)
g.t-shirt__middle(clip-path="url(#clipMain)")
path(d='M90.5 151.3a9.5 4.6 0 01-9 3 9.5 4.6 0 01-9-3l-2.3.4v58.2h22.7v-58.2z' stroke-width='1.3' stroke-linecap='square' transform='matrix(1.00036 0 0 .99247 -49.2 -148.7)')
if (posIndex === 3)
g.t-shirt__fold
path(stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round' d='M70.2 197.8h22.7v12H70.2z' transform='matrix(1.00036 0 0 .99247 -49.2 -148.7)')
mixin cannon(posIndex)
svg(class=`${posIndex === 0 ? 'cannon__shirt' : 'cannon'}` xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewbox='0 0 16.7 87.1')
if (posIndex === 0)
g
path(stroke='#000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round' d='M55.1 223.9h22.7v12H55.1z' transform='matrix(0 -1.00036 .99247 0 -219.8 98)')
if (posIndex === 1)
g(transform='matrix(0 -1.00036 .99247 0 -219.8 98)')
path.cannon__plastic(stroke='#000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round' d='M11.6 222.1h85.7v15.5H11.6z')
rect.cannon__shine(width='20.4' height='1.9' x='63.2' y='223.7' ry='1')
g(stroke='#000' stroke-linecap='round' stroke-linejoin='round')
path.cannon__band(transform='matrix(-.26547 0 0 -.24756 81.3 272.7)' d='M-59.7 143v60.6h25.3v-60.7z' stroke-width='6.3')
button
.button
.t-shirt__cannon.button__cannon
.t-shirt__cannon-content
+cannon(0)
+cannon(1)
.t-shirt__container
.t-shirt__wrapper.button__shirt
//- Middle
+shirt(0)
//- Left arm
+shirt(1)
//- Right arm
+shirt(2)
//- Bottom
+shirt(3)
.button__text
.dummy Ordered
.text.text--order(data-splitting='') Order
.text.text--ordered(data-splitting='') Ordered
const {
Splitting,
gsap: { timeline, set },
} = window
const CLIP = new Audio(
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/605876/t-shirt-cannon-pop.mp3'
)
// Split the order letter
Splitting()
const SHIRT_SEGMENTS = [...document.querySelectorAll('.t-shirt')]
const SHIRT = document.querySelector('.t-shirt__wrapper')
const LEFT_ARM = SHIRT_SEGMENTS[1]
const RIGHT_ARM = SHIRT_SEGMENTS[2]
const FOLD = SHIRT_SEGMENTS[3].querySelector('.t-shirt__fold')
const CLIPS = [...document.querySelectorAll('clipPath rect')]
const BUTTON = document.querySelector('button')
document.documentElement.style.setProperty('--hue', Math.random() * 360)
set(FOLD, { transformOrigin: '50% 100%', scaleY: 0 })
set(CLIPS, { transformOrigin: '50% 0' })
set('.cannon__shirt', { opacity: 0 })
set('.cannon', { y: 28 })
set('.text--ordered .char', { y: '100%' })
const SPEED = 0.15
const FOLD_TL = () =>
new timeline()
.to(
LEFT_ARM,
{
duration: SPEED,
rotateY: -180,
transformOrigin: `${(22 / 65.3) * 100}% 50%`,
},
0
)
.to(
RIGHT_ARM,
{
duration: SPEED,
rotateY: -180,
transformOrigin: `${((65.3 - 22) / 65.3) * 100}% 50%`,
},
SPEED
)
.to(FOLD, { duration: SPEED / 4, scaleY: 1 }, SPEED * 2)
.to(FOLD, { duration: SPEED, y: -47 }, SPEED * 2 + 0.01)
.to(CLIPS, { duration: SPEED, scaleY: 0.2 }, SPEED * 2)
.to('.cannon', { duration: SPEED, y: 0 }, SPEED * 2)
// FOLD_TL()
const LOAD_TL = () =>
new timeline()
.to('.button__shirt', {
transformOrigin: '50% 13%',
rotate: 90,
duration: 0.15,
})
.to('.button__shirt', {
duration: 0.15,
y: 60,
})
.to('.t-shirt__cannon', {
y: 5,
repeat: 1,
yoyo: true,
duration: 0.1,
})
.to('.t-shirt__cannon', {
y: 50,
duration: 0.5,
delay: 0.1,
})
const FIRE_TL = () =>
new timeline()
.set('.t-shirt__cannon', {
rotate: 48,
x: -85,
scale: 2.5,
})
.set('.cannon__shirt', { opacity: 1 })
.to('.t-shirt__cannon-content', { duration: 1, y: -35 })
.to('.t-shirt__cannon-content', { duration: 0.25, y: -37.5 })
.to('.t-shirt__cannon-content', { duration: 0.015, y: -30.5 })
.to(
'.cannon__shirt',
{ onStart: () => CLIP.play(), duration: 0.5, y: '-25vmax' },
'<'
)
.to('.text--ordered .char', { duration: 0.15, stagger: 0.1, y: '0%' })
.to('button', { duration: 7 * 0.15, '--hue': 116, '--lightness': 55 }, '<')
const ORDER_TL = new timeline({ paused: true })
ORDER_TL.set('.cannon__shirt', { opacity: 0 })
ORDER_TL.set('button', { '--hue': 260, '--lightness': 20 })
ORDER_TL.to('button', { scale: 300 / BUTTON.offsetWidth, duration: SPEED })
ORDER_TL.to('.text--order .char', { stagger: 0.1, y: '100%', duration: 0.1 })
ORDER_TL.to(SHIRT, {
// Based on styling. 25px + 0.5rem
x: BUTTON.offsetWidth / 2 - 33,
duration: 0.2,
})
// ORDER_TL.to(BUTTON, { scale: 3 })
ORDER_TL.add(FOLD_TL())
ORDER_TL.add(LOAD_TL())
ORDER_TL.add(FIRE_TL())
BUTTON.addEventListener('click', () => {
if (ORDER_TL.progress() === 1) {
// ORDER_TL.restart()
document.documentElement.style.setProperty('--hue', Math.random() * 360)
ORDER_TL.time(0)
ORDER_TL.pause()
} else if (ORDER_TL.progress() === 0) {
ORDER_TL.play()
}
})
*
box-sizing border-box
body
min-height 100vh
display flex
align-items center
justify-content center
overflow hidden
:root
--color 'hsl(%s, 80%, 60%)' % var(--hue)
.t-shirt
height 100%
width 100%
position absolute
top 0
left 0
&__shirt
fill var(--color)
&__wrapper
position relative
&__cannon
position absolute
left 50%
top 50%
width 10px
transform translate(-50%, 0)
svg
position absolute
top 0
left 0
.cannon__shirt path
fill var(--color)
.cannon__band
fill hsl(50, 100%, 50%)
.cannon__plastic
fill hsla(190, 80%, 80%, 0.35)
.cannon__shine
fill hsla(0, 0%, 100%, 0.5)
.button
font-family sans-serif
font-weight bold
font-size 1rem
padding 1rem 2rem
padding-left calc(1rem + 50px)
position relative
border-radius 6px
border 0
color hsl(0, 0%, 100%)
outline transparent
min-width 120px
$clip = inset(-1000% -1000% 0 0)
// $clip = inset(-1000% -1000% -1000% -1000%)
-webkit-clip-path $clip
clip-path $clip
&__text
position relative
.dummy
color transparent
& > .text
position absolute
top 0
left 0
white-space nowrap
.word
display inline-block
-webkit-clip-path inset(0 0 0 0)
clip-path inset(0 0 0 0)
.char
display inline-block
&__shirt
position absolute
height 32px
width 32px
top 50%
left calc(0.5rem + 25px)
transform translate(-50%, -50%)
// Don't know why but I needed this little wrapper piece to hide the t-shirt
.t-shirt__container
position absolute
top 0
right 0
bottom 0
left 0
overflow hidden
border-radius 6px
button
--hue 260
cursor pointer
background transparent
padding 0
border 0
border-radius 6px
outline transparent
background 'hsl(%s, 46%, %s)' % (var(--hue, 260) calc(var(--lightness, 20) * 1%))
box-shadow 2px 2px 4px 0px #333
transition box-shadow .15s
&:active
box-shadow 0px 0px 0px 0px #333
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment