Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              input.flash(id='flash', type='checkbox')
input.arms(id='arms', type='checkbox')
input.bounce(id='bounce', type='checkbox')
label.bounce-label(for='bounce')
label.arms-label(for='arms')
label.flash-label(for='flash')
input.command(id='command', pattern=".*sweep", placeholder='Type to command')
label.broom-container(for='command')
  .broom
    .broom__handle
      .broom__handle-shade
      .broom__arm.broom__arm--left
        .broom__arm-bicep
        .broom__arm-forearm
          .broom__hand
            .broom__finger
            .broom__finger
            .broom__finger
            .broom__finger
      .broom__arm.broom__arm--right
        .broom__arm-bicep
        .broom__arm-forearm
          .broom__hand
            .broom__finger
            .broom__finger
            .broom__finger
            .broom__finger
    .broom__brush
      .broom__bristles
        .broom__bristles-wrap
          .broom__bristle
      .broom__bristles.broom__bristles--left
        .broom__bristles-wrap
          .broom__bristle
label.instruction(for='flash') Tap
label.instruction(for='arms') Tap again
label.instruction(for='bounce') Again
label.catch-all(for='command')
label.instruction.tap(for='command') Tap & type sweep
            
          
!
            
              *
  box-sizing border-box

// Escape the slash so Stylus doesn't do Math
$sweep-radius = 0 50% 35% 0 \/ 0 50% 15% 0
$running-radius = 0 80% 20% 100% \/ 0 50% 0% 150%
$walking-radius = 0 50% 35% 40% \/ 0 50% 0% 40%

:root
  --bristle-color hsl(49, 75%, 70%)
  --bristle-band red
  --brush-color-one hsl(35, 79%, 25%)
  --brush-color-two hsl(35, 79%, 47%)
  --bg #111
  --transition .1
  --sweep 0
  --speed 1
  --rotation 2
  --scale-end 0.95
  --bristle-radius $walking-radius
  --bristle-scale 1
  --bristle-after-x 0
  --bristle-after-rotation 15
  --bristle-before-scale 1
  --bristle-before-rotation 20
  --arm-scale 1
  --arm-angle 30
  --forearm-angle -20
  --swing 1
  --txt-color hsl(206, 100%, 80%)

body
  align-items center
  background #111
  display flex
  justify-content center
  min-height 100vh

input
  opacity 0

/**
* If the input is valid, make the broom sweep
* But also hide the curved out bristles by rotating the whiskers back
*/
.bounce:checked ~ .command:valid ~ .broom-container .broom
  --speed 0
  --sweep 1
  --bristle-radius $sweep-radius
  --bristle-after-x -100
  --bristle-after-rotation 45
  --bristle-before-scale 0
  --bristle-before-rotation 15
  --bristle-scale 1
  --arm-scale 0

  .broom__arm
    --arm-scale 0
    animation-name none
    animation-duration 0s
    animation-delay 0s
    animation-duration calc(var(--speed) * var(--swing) * 1s)
    animation-delay calc((var(--is-right) * (var(--speed) / 2)) * 1s)
    animation-iteration-count infinite
    animation-timing-function ease
    animation-fill-mode none

  .broom__bristles-wrap
    animation-name none

.arms:checked ~ .broom-container .broom
  --arm-scale 1
  --arm-angle 45

.bounce:checked ~ .command:invalid ~ .broom-container .broom
  --bristle-radius $running-radius
  --bristle-scale 1.15
  --speed .5
  --rotation 4
  --scale-end 0.85
  --bristle-after-x 0
  --bristle-after-rotation 15
  --bristle-before-scale 1
  --bristle-before-rotation 20
  --arm-scale 1
  --arm-angle 60
  --forearm-angle -50
  --sweep 0
  --swing 1
  animation-name none
  .broom__arm
    --arm-angle 60
    animation-name swing
/**
* This is the default state as the placeholder is shown.
* As soon as we start tapping keys, let's up the pace and make the broom
* pointy toed
*/
.bounce:checked ~ .command:placeholder-shown ~ .broom-container .broom
  --sweep 0
  --speed 1
  --rotation 2
  --scale-end 0.95
  --bristle-radius $walking-radius
  --bristle-scale 1
  --bristle-after-x 0
  --bristle-after-rotation 15
  --bristle-before-scale 1
  --bristle-before-rotation 20
  --arm-scale 1
  --arm-angle 30
  --forearm-angle -20
  --swing 1
  // Safari
  animation-name none
  .broom__arm
    --arm-scale 1
    animation-name swing
  .broom__bristles-wrap
    animation-name waddle


/**
* Controls related styling
*/
.flash
.arms
.bounce
.command
  position absolute
  top 10px
  left 10px
.arms
  left 50px
.bounce
  left 90px
.command
  left 130px

// .flash:checked
// .arms:checked
// .bounce:checked

.flash:checked ~ [for='flash']
.arms:checked ~ [for='arms']
.bounce:checked ~ [for='bounce']
  display none
.flash:checked ~ .broom-container .broom
  animation-name flash, jump
  animation-duration .25s, .25s
  animation-iteration-count 4, 1
  animation-timing-function steps(1), ease-in

.flash-label
.bounce-label
.arms-label
  opacity .5
  height 100vh
  width 100vw
  position absolute
  z-index 10

.instruction
  position absolute
  bottom 20px
  right 20px
  color var(--txt-color)
  font-weight bold
  font-variant small-caps
  font-size 2rem
  font-family -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif
  display none

  @media(min-width 768px)
    font-size 4rem

.instruction[for='flash']
  display block

.flash:checked
  display none

  ~ .instruction[for='arms']
    display block

.arms:checked
  display none
  ~ .instruction[for='arms']
    display none
  ~ .instruction[for='bounce']
    display block

.bounce:checked
  display none

  ~ .instruction[for='bounce']
    display none
  ~ .instruction.tap
  ~ .catch-all
    display block

.catch-all
  display none
  top 0
  left 0
  height 100vh
  width 100vw
  position absolute
  z-index 100
/** End controls related styling */

.bounce:checked ~ .broom-container .broom
  animation-name sweep
  animation-duration calc(var(--sweep) * 1s)
  animation-iteration-count infinite
  animation-timing-function ease

.broom
  --bristle-radius $sweep-radius
  --speed 0
  --bristle-after-x -100
  --bristle-after-rotation 15
  --bristle-before-scale 0
  --bristle-before-rotation 20
  --bristle-scale 1
  --arm-angle 40
  --forearm-angle 0
  --arm-scale 0
  --swing 1
  height 100%
  transform-origin 50% 10%
  transition transform calc(var(--transition, .2) * 1s) ease
  width 100%
  z-index 2
  animation-name sweep
  animation-duration calc(var(--sweep) * 1s)
  animation-iteration-count infinite
  animation-timing-function ease

  &__handle
    position absolute
    top 0
    left 50%
    // Required for overlap cross browser
    height 66%
    background linear-gradient(90deg, var(--brush-color-one), var(--brush-color-two))
    width 8%
    transform translate(-50%, 0)
    transform-origin bottom center
    border-radius 50% 50% 0 0 / 5% 5% 0 0
    animation-duration calc(var(--speed) * 1s)
    animation-iteration-count infinite
    animation-name shake
    animation-timing-function ease

    // Purely used for covering the arm joints
    &-shade
      border-radius 50% 50% 0 0 / 5% 5% 0 0
      height 60%
      width 100%
      background linear-gradient(90deg, var(--brush-color-one), var(--brush-color-two))
      z-index 2
      top 0
      left 0
      position absolute


    &:before
      background var(--bristle-band)
      bottom 0
      content ''
      height 5%
      left 50%
      position absolute
      transform translate(-50%, 0)
      width 250%
      z-index 2

    &:after
      $clip = polygon(0 0, 100% 0, 85% 100%, 15% 100%)
      -webkit-clip-path $clip
      background var(--bristle-color)
      bottom 5%
      clip-path $clip
      content ''
      height 5%
      left 50%
      position absolute
      transform translate(-50%, 0)
      width 300%
      z-index 2

  &__arm
    --is-right 0
    position absolute
    width 50%
    height 35%
    top 40%
    transition transform calc(var(--transition, .2) * 1s)
    transform-origin top center
    animation-name none
    animation-duration calc(var(--speed) * var(--swing) * 1s)
    animation-delay calc((var(--is-right) * (var(--speed) / 2)) * 1s)
    animation-iteration-count infinite
    animation-timing-function ease
    animation-fill-mode both

    &--left
      --bg var(--brush-color-one)
      left 0
      transform rotateY(calc(var(--is-right) * 180 * 1deg)) rotate(calc(var(--arm-angle) * 1deg)) scaleY(var(--arm-scale))

    &--right
      --bg var(--brush-color-two)
      --is-right 1
      right 0
      transform rotateY(calc(var(--is-right) * 180 * 1deg)) rotate(calc(var(--arm-angle) * 1deg)) scaleY(var(--arm-scale))

    &-bicep
      background var(--bg)
      height 50%
      width 100%
      position absolute
      top 0
      left 0
      border-radius 50% 50% 0 0 / 5% 5% 0 0
    &-forearm
      position absolute
      background var(--bg)
      height 50%
      top 48%
      left 0
      width 100%
      transform rotate(calc(var(--forearm-angle) * 1deg))
      transform-origin top center

  &__hand
    height 14px
    width 14px
    background var(--bg)
    border-radius 100%
    position absolute
    bottom 0
    left 50%
    transform translate(-50%, 50%)

  &__finger
    height 80%
    background var(--bg)
    width 25%
    position absolute
    top 50%
    left 50%
    border-radius 50%

    &:nth-of-type(1)
      transform translate(-50%, -50%) rotate(-80deg) translate(0, 50%)

    &:nth-of-type(2)
      transform translate(-50%, -50%) rotate(-20deg) translate(0, 50%)

    &:nth-of-type(3)
      transform translate(-50%, -50%) rotate(20deg) translate(0, 50%)

    &:nth-of-type(4)
      transform translate(-50%, -50%) rotate(60deg) translate(0, 50%)


  &__brush
    bottom 0
    height 35%
    left 0
    overflow hidden
    position absolute
    width 100%

  &__bristles
    height 100%
    left 49%
    overflow hidden
    position absolute
    top 0
    width 50%

    &--left
      transform-origin left center
      transform rotateY(180deg) translate(-3%, 0)

      .broom__bristles-wrap
        animation-delay calc(var(--speed) * -0.5s)

  &__bristles-wrap
    animation-duration calc(var(--speed) * 1s)
    animation-iteration-count infinite
    animation-name waddle
    animation-timing-function ease
    height 100%
    left 0
    overflow hidden
    position absolute
    top 0
    transform-origin top left
    width 100%

  &__bristle
    background var(--bristle-color)
    border-radius var(--bristle-radius)
    height 100%
    left 0
    position absolute
    top 0
    transform scaleX(var(--bristle-scale))
    transition border-radius calc(var(--transition, .2) * 1s) ease, transform calc(var(--transition, .2) * 1s) ease
    width 40%

    &:after
      bottom -2%
      border-radius 100%
      box-shadow 0 -15px 0px 0px var(--bristle-color) inset
      content ''
      height 40%
      left 45%
      position absolute
      transform translate(calc(var(--bristle-after-x) * 1%), 0) rotate(calc(var(--bristle-after-rotation) * 1deg))
      transition transform calc(var(--transition, .2) * 1s) ease
      width 100%
      z-index 2

    &:before
      border-radius 100%
      bottom 12%
      box-shadow 0 -5px 0 0 var(--bristle-color) inset
      content ''
      height 20%
      left 95%
      position absolute
      transform scale(var(--bristle-before-scale)) rotate(calc(var(--bristle-before-rotation) * 1deg))
      transition transform calc(var(--transition, .2) * 1s) ease
      width 50%

// Container element for the broom
.broom-container
  display block
  height 250px
  position relative
  transform translate(calc(var(--x, 0) * 1%), calc(var(--y, 0) * 1%))
  transition transform calc(var(--transition, .2) * 1s) ease
  width 150px
  z-index 5


@keyframes waddle
  0%, 100%
    transform scaleY(1)
  50%
    transform scaleY(var(--scale-end)) rotate(calc(var(--rotation) * 1deg))

@keyframes shake
  0%, 100%
    transform translate(-50%, 0) rotate(calc(var(--rotation) * -1deg))
  50%
    transform translate(-50%, 0) rotate(calc(var(--rotation) * 1deg))

@keyframes swing
  0%, 100%
    transform rotateY(calc((var(--is-right) * 180) * 1deg)) rotate(calc(var(--arm-angle) * 1deg)) scaleY(var(--arm-scale))
  50%
    transform rotateY(calc((var(--is-right) * 180) * 1deg)) rotate(calc(var(--arm-angle) * .85deg)) scaleY(var(--arm-scale))

@keyframes sweep
  0%, 5%, 95%, 100%
    transform rotate(15deg)
  45%, 50%, 55%
    transform rotate(-15deg)

@keyframes jump
  0%, 100%
    transform translate(0, 0) scale(1)
  50%
    transform translate(0, -50%) scale(1.15)

@keyframes flash
  0%
    filter drop-shadow(0 0 20px yellow)
  20%
    filter drop-shadow(0 0 20px purple)
  40%
    filter drop-shadow(0 0 20px blue)
  60%
    filter drop-shadow(0 0 20px green)
  80%
    filter drop-shadow(0 0 20px red)
  100%
    filter drop-shadow(0 0 20px dodgerblue)
            
          
!
            
              // 404
// Nope, not here!
            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.

Console