cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - ActiveLovehtmlicon-new-collectionicon-personicon-teamlog-outoctocatpop-outspinnerstartv

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.

            
              <script type="text/x-template" id="picker">
  <div>
  <svg v-bind:style="{ transform: 'rotate(' + (shift * -360 % 360) + 'deg)' }"class="picker__svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="-10 -10 220 220">
      <defs>
        <linearGradient v-bind:id="'redyel-' + id" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="1">
            <stop offset="0%" v-bind:stop-color="colors[0]"/>   
            <stop offset="100%" v-bind:stop-color="colors[1]"/>   
        </linearGradient>
        <linearGradient v-bind:id="'yelgre-' + id" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" v-bind:stop-color="colors[1]"/>   
            <stop offset="100%" v-bind:stop-color="colors[2]"/>   
        </linearGradient>
        <linearGradient v-bind:id="'grecya-' + id" gradientUnits="objectBoundingBox" x1="1" y1="0" x2="0" y2="1">
            <stop offset="0%" v-bind:stop-color="colors[2]"/>   
            <stop offset="100%" v-bind:stop-color="colors[3]"/>   
        </linearGradient>
        <linearGradient v-bind:id="'cyablu-' + id" gradientUnits="objectBoundingBox" x1="1" y1="1" x2="0" y2="0">
            <stop offset="0%" v-bind:stop-color="colors[3]"/>   
            <stop offset="100%" v-bind:stop-color="colors[4]"/>   
        </linearGradient>
        <linearGradient v-bind:id="'blumag-' + id" gradientUnits="objectBoundingBox" x1="0" y1="1" x2="0" y2="0">
            <stop offset="0%" v-bind:stop-color="colors[4]"/>   
            <stop offset="100%" v-bind:stop-color="colors[5]"/>   
        </linearGradient>
        <linearGradient v-bind:id="'magred-' + id" gradientUnits="objectBoundingBox" x1="0" y1="1" x2="1" y2="0">
            <stop offset="0%" v-bind:stop-color="colors[5]"/>   
            <stop offset="100%" v-bind:stop-color="colors[0]"/>   
        </linearGradient>
      </defs>
      <ellipse class="ellipse" cx="100" cy="100" rx="100.95" ry="100.95" fill="none" stroke="#212121"/>
      <g fill="none" transform="translate(100,100)">
        <path d="M -1,-100 A 100,100 0 0,1 86.6,-50" v-bind:stroke="'url(#redyel-' + id + ')'"/>
        <path d="M 86,-51 A 100,100 0 0,1 86.6,50" v-bind:stroke="'url(#yelgre-' + id + ')'"/>
        <path d="M 87,49 A 100,100 0 0,1 0,100" v-bind:stroke="'url(#grecya-' + id + ')'"/>
        <path d="M 1,100 A 100,100 0 0,1 -86.6,50" v-bind:stroke="'url(#cyablu-' + id + ')'"/>
        <path d="M -86,51 A 100,100 0 0,1 -86.6,-50" v-bind:stroke="'url(#blumag-' + id + ')'"/>
        <path d="M -87,-49 A 100,100 0 0,1 0,-100" v-bind:stroke="'url(#magred-' + id + ')'"/>
      </g>
  </svg>
  <div>
</script>

<script type="text/x-template" id="pointer">
  <div class="pointer" v-bind:style="{color: color}">
    <div class="pointer__marker" v-bind:style="{transform: 'translate(-50%,-50%) rotate(' + position * 380 + 'deg)'}"></div>
  </div>
</script>

<script type="text/x-template" id="bg">
  <div class="gradient" v-bind:style="{color: start, background: 'linear-gradient(' + start + ', ' + stop + ')'}">
  <transition name="pouf">
    <span v-if="!scrolled" class="gradient__text">  
      <strong>scroll to change color shift</strong>
    </span>
  </transition>
  </div>
</script>

<script type="text/x-template" id="ratio">
  <label v-bind:style="{color: color}" class="ratio">
    <strong class="ratio__label">Ratio</strong>
    <input class="ratio__range" type="range" v-bind:value="ratio" v-on:input="updateValue($event)" increment=0.01 min=0 max=1 step="0.001">
  </label>
</script>

<div id="app" class="app">
  <div class="app__wrap" v-bind:class="{ 'app--uihide': !visibleUI, 'app--uianimate': animateUI }">
    <v-style>
      :root {
        --colorInner: {{colorInner}};
        --colorOuter: {{colorOuter}};
        --colorUI: {{colorUI}}};
      }
    </v-style>
    <bg v-bind:stop="colorInner" 
        v-bind:scrolled="didScroll" 
        v-bind:start="colorOuter">
    </bg>
    <div class="controls">
      <!--pointer class="pointer--lower" v-bind:position="pointer"></pointer-->
      <picker class="picker picker--outer" v-bind:colors="colorsOuter"></picker>
      <picker class="picker picker--inner" v-bind:colors="colorsInner" v-bind:shift="shift"></picker>
      <pointer v-bind:position="pointer" v-bind:color="colorInner"></pointer>
      <ratio v-model="ratio"></ratio>
    </div>
    <div class="actions" v-bind:class="{ 'actions--up': didScroll }">
      <button title="copy to clipboard" v-bind:data-clipboard-text="'linear-gradient(' + colorOuter +', '+ colorInner +')'" class="button actions__button"><i class="button__icon"><svg viewBox="0 0 1151.25 1440.625125" xmlns="http://www.w3.org/2000/svg"><path d="m-5932.9762 2569.7556-362.8126-.3168v-143.7479-143.7479h-143.75-143.75v-431.875-431.875h431.875 431.8751v143.75 143.75h143.75 143.75v432.5 432.5001l-69.0625-.3104c-37.9844-.1707-232.3282-.4529-431.875-.6271zm362.1875-432.3559v-293.2934l-292.1875.9223c-160.7032.5072-292.3696 1.0931-292.5921 1.302-.2224.2089-.5457 131.7759-.7183 292.3711l-.3139 291.9914h292.9059 292.9059zm-725.0001-212.9567v-218.75h218.75 218.7501v-74.0625-74.0625l-292.4948.3177-292.4948.3178-.3177 292.4948-.3178 292.4948 74.0625-.0001h74.0625z" transform="translate(6583.2887 -1418.193)"/></svg></i><span class="button__text">copy</span></button>
      <button v-on:click="toggleDiscrete()" class="button actions__button"><i class="button__icon"><svg viewBox="0 0 1279.0173 1598.999125" xmlns="http://www.w3.org/2000/svg"><path d="m-2896.2791 556.86227c-20.5895-1.755-45.7549-4.81513-61.8496-7.521-232.2831-39.0512-423.5294-201.18751-500.3924-424.22668-14.6274-42.445313-25.1549-89.624913-31.0953-139.354163-3.2286-27.02832-3.2286-109.221637 0-136.249937 17.7073-148.2357 78.1511-276.1044 179.5379-379.8118 104.1372-106.5209 236.6946-170.9064 389.4244-189.1505 27.0283-3.2286 109.2216-3.2286 136.2499 0 152.7298 18.2441 285.2872 82.6296 389.4244 189.1505 101.3868 103.7074 161.8306 231.5761 179.5379 379.8118 3.2286 27.0283 3.2286 109.221617 0 136.249937-17.7073 148.235623-78.1511 276.104363-179.5379 379.811793-103.9338 106.31275-236.9979 171.02105-388.7994 189.07092-15.9852 1.90075-97.3955 3.5065-112.4999 2.21913zm98.1754-162.3659c184.4382-21.39347 338.9126-145.55761 399.6544-321.235943 10.9472-31.66149 19.6053-71.03906 23.6366-107.49999 2.1674-19.60284 2.1674-76.647147 0-96.249947-9.7254-87.9607-41.1265-169.0733-91.8694-237.3086-87.3017-117.397-220.3349-187.8181-366.7341-194.1305l-19.113-.8241v480.388147 480.388173l19.113-.82411c10.5121-.45326 26.4027-1.66967 35.3125-2.70313z" transform="translate(3492.0379 721.87326)"/></svg></i><span class="button__text">lightmode</span></button>
      <!--button v-on:click="toggleUI()" class="button actions__button"><i class="button__icon">☉</i><span class="button__text">toggle ui</span></button-->
      <button v-on:click="togglePlay()" class="button button--play actions__button"><i class="button__icon"><svg viewBox="0 0 560.62432 1401.56075" xmlns="http://www.w3.org/2000/svg"><path d="m-1464.3832 828.28949v-560.6243l280.3122 280.3121 280.31211 280.3122-280.31211 280.31211-280.3122 280.3122z" transform="translate(1464.3832 -267.66519)"/></svg></i><span class="button__text">play</span></button>
    </div>
  </div>
</div>
            
          
!
            
              @import url('https://fonts.googleapis.com/css?family=Space+Mono');

body, html {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
}
input {
  background-color: transparent;
}
input[type=range] {
  appearance: none;
}

// range sliders
input[type=range] {
  margin: 0;
  width: 20vmin;
}
input[type=range]:focus {
  outline: none;
  &::-webkit-slider-thumb {
    //height: .65rem;
    //clip-path: polygon(50% 0%, 50% 0%, 0% 100%, 100% 100%);
  }
}
@mixin slider-track {
  width: 100%;
  height: 1.4vmin;
  cursor: pointer;
  animate: 0.2s;
  background: transparent;
  color: transparent;
  border-radius: 0;
  border: solid var(--colorInner);
  border-width: 0 0 1px;
  
}

@mixin slider-thumb {
  position: relative;
  z-index: 1;
  font-size: 1.9vmin;
  border-radius: 50%;
  border-bottom-left-radius: 0;
  width: 1em; height: 1em;
  background-color: var(--colorInner);
  box-shadow: 0 0 0 .1em var(--colorUI);
  transition: 200ms box-shadow linear;
  cursor: pointer;
  -webkit-appearance: none;
  transform: translateY(-.8em) rotate(-45deg); 
}
input[type=range]::-webkit-slider-runnable-track {
  @include slider-track;
}
input[type=range]::-webkit-slider-thumb {
  @include slider-thumb;
}
input[type=range]:focus::-webkit-slider-runnable-track {
  //background: $c-black;
}
input[type=range]::-moz-range-track {
  @include slider-track;
}
input[type=range]::-moz-range-thumb {
  @include slider-thumb;
}
input[type=range]::-ms-track {
  @include slider-track;
}
input[type=range]::-ms-fill-lower {
  background: var(--colorUI);
  transition: 200ms background-color linear;
  border: none;
  border-radius: 100%;
}
input[type=range]::-ms-fill-upper {
  background: var(--colorUI);
  transition: 200ms background-color linear;
  border-radius: 100%;
  box-shadow: none;
}
input[type=range]::-ms-thumb {
  @include slider-thumb;
}

body, button, input {
  font-family: 'Space Mono', monospace;
}

:root {
  --colorUI: #212121;
}

.gradient {
  position: absolute;
  width: 100%; height: 100%;
  top: 0; left: 0;
  
  &__text,
  &::before {
    content: '';
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
  }
  
  &::before {
    background: var(--colorUI);
    transition: 200ms background-color linear;
    width: 54.9vmin; height: 54.9vmin;
    border-radius: 50%;
    box-shadow: 0 0 10rem currentColor;
    //clip-path: circle(40%);
  }
  
  &__text {
    line-height: 1.6;
    text-align: center;
    width: 20vmin;
    font-size: 1.9vmin;
    color: var(--colorInner);
    user-select: none;
    margin-top: 8vmin;
    
    strong {
      display: block;
      margin-bottom: 0.5em;
    }
    &.pouf-enter-active, 
    &.pouf-leave-active {
      opacity: 1;
      transition: opacity .3s linear, transform .4s cubic-bezier(.7,.3,0,1);;
    }
    
    &.pouf-enter, 
    &.pouf-leave-to {
      opacity: 0;
      transform: translate(-50%, -75%);
      transform-origin: 50% 0%;
    }
    
  }
  box-shadow: inset 0 0 0 1.6vmin var(--colorUI);
  transition: 200ms box-shadow linear;
}

.picker {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%,-50%);
  width: 100%; height: 100%;
  .ellipse {
    opacity: 0;
  }
  &__svg {
    stroke-width: 15;
    overflow: auto;
    width: 100%; 
    height: 100%;
    transform: scale(.925);
  }
  &--inner {
    transform: translate(-50%,-50%) scale(.87); 
    .ellipse {
      transform: translate(2px,2px) scale(.98);
    }
  }
}

.controls, .pointer, .pointer__marker {
  pointer-events: none;
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%,-50%);
  width: 57vmin; height: 57vmin;
}
.pointer {
  cursor: move;
  width: 100%; height: 100%;
  //mix-blend-mode: color-dodge;
  &__marker {
    width: 51.6vmin; height: 51.6vmin;
    &::before,
    &::after {
      content: '';
      position: absolute;
      left: 50%;
      top: 0;
      transform: translateX(-50%);
    }
    &::before {
      height: 5vmin;
      width: .1rem;
      background: var(--colorUI);
      transition: 200ms background-color linear;
    }
    &::after {
      background: currentColor;
      border-radius: 50%;
      transform: translateX(-50%) rotate(-45deg);
      border-bottom-left-radius: 0;
      font-size: 1.9vmin;
      margin-top: -.5em;
      width: 1em; height: 1em;
      box-shadow: 0 0 0 .1rem var(--colorUI); 
      transition: 200ms box-shadow linear;
    }
  }
  &--lower {
    .pointer__marker {
      margin-top: -.7rem;
      &::before {
        box-shadow: 0 0 0 .6rem var(--colorUI); 
        transition: 200ms box-shadow linear;
        width: .7rem;
        border-radius: 100%;
      }
      &::after {
        display: none;
      }
    }
  }
}

.title {
  position: absolute;
  top: 50%; left: 0; right: 0;
  text-align: center;
  font-size: .8em;
  margin-top: -6vmin;
}

.ratio {
  z-index: 2;
  position: absolute;
  pointer-events: auto;
  top: 50%; left: 50%;
  transform: translate(-50%,-50%);
  color: #fff;
  text-shadow: 0 0 .5em var(--colorUI);
  transition: 200ms text-shadow linear;
  
  &__label {
    display: none;
    font-size: .7rem;
    text-align: center;
    margin-bottom: .5em;
  }
}

.gradientval {
  display: none;
}

.actions {
  display: flex;
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  margin-top: 14.5vmin;
  will-change: transform;
  &--up {
    .actions__button {
      transform: translateY(-8vmin);
      transition: 340ms transform cubic-bezier(.8,.3,.5,1.2);
      &:nth-child(1) {
        transition-delay: 100ms;
        transform: translate(-3.5vmin,-8vmin);
      }
      &:nth-child(2) {
        transition-delay: 170ms;
      }
      &:nth-child(3) {
        transition-delay: 240ms;
        transform: translate(3.5vmin,-8vmin);
      }
      &:nth-child(4) {
        transition-delay: 250ms;
      }
    }
  }
}

.button {
  position: relative;
  user-select: none;
  color: var(--colorInner);
  background: transparent;
  border: none;
  cursor: pointer;
  display: inline-block;
  margin-right: -4px;
  font-size: 2.4vmin;
  outline: none;
  padding: .1em .3em;
  &:hover {
    svg {
      transform: scale(1);
    }
    .button__text {
      opacity: 1;
      transform: translateX(50%);
    }
  }
  &__icon {
    display: block;
    font-style: normal;
    width: 2.4vmin;
    height: 2.4vmin;
  }
  &__text {
    opacity: 0;
    pointer-events: none; 
    position: absolute;
    top: 110%; right: 50%;
    transform: translateX(50%) translateY(-50%);
    font-size: .6em;
    line-height: 1.3;
    padding: .2em .4em;
    transition: transform 200ms, opacity 100ms;
    transition-delay: 100ms, 100ms;
  }
  svg {
    width: 2.4vmin;
    transition: 100ms transform ease-out;
    transform: scale(.8);
    path {
      fill: currentColor;
    }
  }
  &--play {
    svg {
      width: 1.05vmin;
    }  
  }
  
}

.app--uianimate {
  .controls {
    transition: 444ms transform ease-in-out 200ms;
    will-change: transform;
  }
  .gradient::before {
    transition: 444ms transform ease-in-out 100ms;
    will-change: transform;
  }
}

.app--uihide {
  .controls {
    transform: translate(-50%, -50%) scale(0);
  }
  .gradient::before {
    transform: translate(-50%, -50%) scale(0);
  }
}
            
          
!
            
              Vue.component('v-style', {
  render: function (createElement) {
    return createElement('style', this.$slots.default)
  }
});

Vue.component('pointer', {
  template: '#pointer',
  props: {
    position: Number,
    color: String,
  }
});

Vue.component('bg', {
  template: '#bg',
  props: {
    stop: String,
    start: String,
    scrolled: Boolean,
  },
  data: function () {
    return {
      scrolled: this.didScroll
    }
  }
});

Vue.component('picker', {
  template: '#picker',
  data: function(){
    return { id: null };
  },
  props: {
    colors: Array,
    shift: Number,
  },
  mounted () {
    this.id = this._uid
  }
});

Vue.component('ratio', {
  template: '#ratio',
  props: {
    ratio: Number,
    color: String
  },
  methods: {
    updateValue: function (event) {
      this.$emit('input', event.target.value);
    }
  },
  mounted () {
    const $range = document.querySelector('.ratio__range');
    function stop (e) {
      e.stopPropagation();
    }
    $range.addEventListener('mousedown', stop, false);
    $range.addEventListener('touchstart', stop, false);
    $range.addEventListener('mouseup', stop, false);
    $range.addEventListener('touchend', stop, false);
  }
});

new Vue({
  el: '#app',
  data: function () { return {
    colorsOuter: ['#ff0000', '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#ff00ff'],
    shift: .05,
    mods: {
      brighten: 2.5
    },
    pointer: 0,
    nameInner: null,
    nameOuter: null,
    ratio: .5,
    
    colorUI: '#212121',
    isPlaying: false,
    visibleUI: true,
    animateUI: false,
    didScroll: false,
  }},
  computed: {
    colorsInner: function () {
      return this.colorsOuter.map(color => chroma(color).brighten(this.mod.brighten).hex());
    },
    colorOuter: function () {
      return chroma(`hsl(${this.pointer * 360}, 100%, 50%)`).hex();
    },
    colorInner: function () {
      return chroma(`hsl(${(this.pointer + this.shift) * 360 % 360}, 100%, 50%)`).brighten(this.mod.brighten).hex();
    },
    mod: function () {
      return this.mods = {
        brighten: 4 - this.ratio * 4
      }
    }
  },
  methods: {
    getColors: function () {
      /*
      <h1 class="title">{{ nameOuter }} → {{ nameInner }}</h1>
      fetch(`https://api.color.pizza/v1/${this.colorInner.replace('#','')},${this.colorOuter.replace('#','')}`)
        .then(data => data.json())
        .then(data => {
          this.nameInner = data.colors[0].name;
          this.nameOuter = data.colors[1].name;
        });*/
    },
    toggleDiscrete: function () {
      if (this.colorUI == '#212121' ) {
        this.colorUI = 'transparent';
      } else {
        this.colorUI = '#212121';
      }
    },
    togglePlay: function () {
      if (!this.isPlaying) {
        this.playAnimation = setInterval(() => {
          this.pointer += 0.0001;
          this.shift += .0025;
        }, 16.666);
        this.isPlaying = true;
      } else {
        clearTimeout(this.playAnimation);
        this.isPlaying = false;
      }
    },
    toggleUI: function () {
      /*Vue.nextTick().then(() => {
        this.animateUI = !this.animateUI;
        Vue.nextTick().then(() => {
          this.visibleUI = !this.visibleUI;
        })
      });*/
    }
  },
  mounted () {
    const $ui = document.querySelector('.actions');
    new ClipboardJS('[data-clipboard-text]');
    const hamster = Hamster(window);
 
    hamster.wheel((event, delta, deltaX, deltaY) => {
      this.shift +=  Math.sign(deltaY)/250;
      if (!this.didScroll && Math.abs(this.shift) > .05) {
        this.didScroll = true;
      }
    });
    
    document.addEventListener('keydown', (event) => {
      if (event.which === 38 /* up */ ) {
        this.shift += .005;
      } else if (event.which === 40 /* down */ ) {
        this.shift -= .005;
      }
    });
    
    let listen = false;
    
    const start = (e) => {
      listen = true;
      move(e);
    };
    const stop = () => {
      listen = false;
    };
    
    document.addEventListener('mousedown', start, false);
    document.addEventListener('touchstart', start, false);
    document.addEventListener('mouseup', stop, false);
    document.addEventListener('touchend', stop, false);
    
    function stopProp (e) {
      e.stopPropagation();
    }
    
    $ui.addEventListener('mousedown', stopProp, false);
    $ui.addEventListener('touchstart', stopProp, false);
    $ui.addEventListener('mouseup', stopProp, false);
    $ui.addEventListener('touchend', stopProp, false);
    
    const move = (e) => {
      if (!listen) { return; }
      const radians = Math.atan2(e.pageY - window.innerHeight * .5, e.pageX - window.innerWidth * .5);
      const deg = (radians * (180 / Math.PI));
      this.pointer = ((deg + 360 + 90) % 360) / 380;
      this.getColors();
    }
    
    
    document.addEventListener('mousemove', move);
    document.addEventListener('touchmove', move);
  }
});

/*
var copyText = document.querySelector("#input");
  copyText.select();
  document.execCommand("copy");
*/
            
          
!
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.
Loading ..................

Console