%h4 Drag the phone right and left
.phone
    .phone_frame
    %canvas.grain
    .guitar
    .phone_inner
        .phone_inner__nav
            .menu
            %h3 Product details
        .phone_inner__cube
            .face--front
                .shadow
                    %img{:src => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/217233/gshadow.png'}
                -(1..100).each do
                    %h1 Fender
                %h2 Fender American Elite Strat
            .face--left
                .logo
                    %img{:src => 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/217233/logoStrings.png'}
                %ul.big
                    %li.active Guitars
                    %li Basses
                    %li Amps
                    %li Pedals
                    %li Other
                %ul.small
                    %li About
                    %li Support
                    %li Terms
                    %li FAQ
View Compiled
$height: 489px;
$width: 245px;
$perspective: 900;

$globalTransitionmTime: .5s;
$globalTransitionEasing: cubic-bezier(0.615, 0.000, 0.280, 1.005);

@import url('https://fonts.googleapis.com/css?family=Heebo:400,500,800,900&display=swap');

:root {
    --bg: #efdece;
}

h4 {
    color: white;
    margin: 0;
    padding-top: 20px;
    text-align: center;
}

canvas {
    position: absolute;
    z-index: 1;
    opacity: 0.6;
    pointer-events: none;
}

.dynamicCursor {
    max-width: 50px;
    min-width: 18px;
    transition: width 0s;
    background: transparent !important;
    border: 2px solid white !important;

}

@keyframes in {
    from{opacity: 0;}
    to{opacity: 1;}
}

body {
    padding: 0;
    background: #a92913;
    padding: 0;
    margin: 0;
    box-shadow: 50vw 0 #381313 inset;
    height: 100vh;
    font-family: 'Heebo', sans-serif;

    -webkit-user-select: none;  /* Chrome all / Safari all */
    -moz-user-select: none;     /* Firefox all */
    -ms-user-select: none;      /* IE 10+ */
    user-select: none;          /* Likely future */ 

    %center {
        position: absolute;
        left: 0;
        right: 0;
        margin: auto;
        top: 50%;
        transform: translateY(-50%);
    }
    .guitar {

        width: 85px;
        height: 175px;
        z-index: 10;
        position: absolute;
        transition: all 0.7s 0.3s cubic-bezier(0.5, 0.005, 0.075, 0.985), transform 0.1s 0.7s, -webkit-transform 0.1s;
        left: 92px;
        transform: scale(1.8);
        top: 130px;
        background-size: 1920px !important;
        background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/217233/gt.png);
        animation: guitar2 $globalTransitionmTime 0s steps(23, end) forwards;


        @keyframes guitar {
            0% {background-position: 0 0;transform: scale(1.8)}
            10% { transform: scale(1.8);}
            100% {background-position: -1840px 0; transform: scale(1.8)}
        }

        @keyframes guitar2 {
            0% {background-position: -1840px 0;transform: scale(1.8)}
            10% { transform: scale(1.8);}
            100% {background-position: 0 0; transform: scale(1.8)}
        }
    }

    .phone {
        @extend %center;
        opacity: 0;
        animation: in 1s .5s forwards;

        width: $width;
        height: $height;
        perspective: $perspective;
        border-radius: 24px;
        overflow: hidden;
        border-radius: 40px;

        box-shadow: 0 0 40px 10px rgba(0, 0, 0, 0.3);

        -webkit-box-reflect: below 4px linear-gradient(to top, rgba(255, 255, 255, 1) -120%, rgba(255,255,255,0) 25%);

        &.open {
            .guitar {
                animation: guitar $globalTransitionmTime 0s steps(23, end) forwards;
            }

            & .phone_inner__nav {
                left: 170px;

                h3 {
                    opacity: 0;
                }
            }

            & .phone_inner__cube {
                transform: rotateY(90deg);
                left: 50px;

                h2 {
                    opacity: 0;
                    transform: translateZ(50px);
                }
            }
        }

        &_frame {
            width: $width;
            height: $height;

            position: absolute;
            z-index: 2;
            background: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/217233/frameIphone.png');

            pointer-events: none;
        }

        &_inner {
            width: $width - 20px;
            height: $height - 14px;

            position: relative;
            left: 10px;
            top: 6px;
            overflow: hidden;
            transform-style: preserve-3D;
            background: #ada59c;

            &__nav {
                position: absolute;
                z-index: 2;
                text-transform: uppercase;
                text-align: center;
                width: 100%;
                font-weight: 400;
                transition: all $globalTransitionmTime $globalTransitionEasing;
                top: 39px;
                left: 0;

                h3 {
                    margin: 0;
                    font-size: 9px;
                    opacity: 1;
                    transition: all $globalTransitionmTime $globalTransitionEasing;
                }

                & .menu {
                    width: 18px;
                    height: 2px;
                    background: #111114;
                    position: absolute;
                    left: 16px;

                    &:after {
                        content: '';
                        display: block;
                        position: relative;
                        top: 2px;
                        width: 18px;
                        height: 2px;
                        background: #111114;
                    }

                    &:before {
                        content: '';
                        display: block;
                        position: relative;
                        top: 9px;
                        width: 10px;
                        height: 2px;
                        background: #111114;
                    }
                }
            }

            &__cube {
                transform-style: preserve-3D;
                height: 100%;
                position: relative;
                left: 0;
                transition: all $globalTransitionmTime + .009s $globalTransitionEasing;

                .shadow {
                    img {
                        position: absolute;
                        width: 210px;
                        top: 90px;
                        left: 20px;
                    }
                }

                h1 {
                    text-transform: uppercase;
                    margin: 0;
                    transform-origin: 0 50%;
                    position: absolute;
                    line-height: 0;
                    left: 47px;
                    letter-spacing: 3px;
                    top: 92px;
                    color: #c6bdad;
                    font-size: 55px;
                    text-shadow: 0 0 1px #bdb5ad;
                    transform-style: preserve-3D;

                    @for $i from 1 through 100 {
                        &:nth-of-type(#{$i}) {
                            transform: rotate(90deg) translateZ(($i / 24) - 1 + px);
                        }
                    }
                }

                h2 {
                    font-size: 20px;
                    font-weight: 500;
                    position: absolute;
                    bottom: 14px;
                    line-height: 20px;
                    left: 24px;
                    width: 100px;
                    opacity: 1;
                    transform: translateZ(0);
                    transition: all $globalTransitionmTime $globalTransitionEasing;
                }

                .logo {
                    position: absolute;
                    z-index: auto;
                    top: 64px;
                    left: 20px;

                    img {
                        width: 50px;
                        image-rendering: pixelated;
                        mix-blend-mode: darken;
                    }
                }

                ul {
                    padding: 0;
                    margin: 0 0 0 30px;

                    li {
                        list-style-type: none;
                        text-transform: uppercase;
                        font-weight: 900;
                        margin: 0 0 4px 0;
                        color: #111008;
                        cursor: pointer;
                        transition: all .2s;

                        &:hover {
                            color: #a23426;
                        }

                        &.active {
                            color: #a23426;
                        }
                    }

                    &.small {
                        font-size: 7px;
                        margin-top: 80px;

                        li {
                            margin: 0 0 6px 0
                        }
                    }

                    &.big {
                        margin-top: 157px; 
                    }
                }

                %face {
                    width: 100%;
                    height: 100%;
                    transform-style: preserve-3D;
                    background: linear-gradient(
                        to right, 
                        #f0ece5,
                        var(--bg) 6%,
                        var(--bg)
                    ), var(--bg);
                    position: absolute;
                    transform-style: preserve-3D;
                }

                & .face {
                    &--left,
                    &--front {
                        @extend %face;
                    }

                    &--left {
                        transform: rotateY(-90deg) translateX(-150px);
                        width: 150px;
                        transform-origin: 0 0;
                        z-index: -1;
                    }
                }
            }
        }
    }
}
View Compiled
dragging = false;

'use strict';

///console.clear();

class Grain {
    constructor (el) {
        /**
     * Options
     * Increase the pattern size if visible pattern
     */
        this.patternSize = 150;
        this.patternScaleX = 1;
        this.patternScaleY = 1;
        this.patternRefreshInterval = 3; // 8
        this.patternAlpha = 28; // int between 0 and 255,

        /**
     * Create canvas
     */
        this.canvas = el;
        this.ctx = this.canvas.getContext('2d');
        this.ctx.scale(this.patternScaleX, this.patternScaleY);

        /**
     * Create a canvas that will be used to generate grain and used as a
     * pattern on the main canvas.
     */
        this.patternCanvas = document.createElement('canvas');
        this.patternCanvas.width = this.patternSize;
        this.patternCanvas.height = this.patternSize;
        this.patternCtx = this.patternCanvas.getContext('2d');
        this.patternData = this.patternCtx.createImageData(this.patternSize, this.patternSize);
        this.patternPixelDataLength = this.patternSize * this.patternSize * 4; // rgba = 4

        /**
     * Prebind prototype function, so later its easier to user
     */
        this.resize = this.resize.bind(this);
        this.loop = this.loop.bind(this);

        this.frame = 0;

        window.addEventListener('resize', this.resize);
        this.resize();

        window.requestAnimationFrame(this.loop);
    }

    resize () {
        this.canvas.width = window.innerWidth * devicePixelRatio;
        this.canvas.height = window.innerHeight * devicePixelRatio;
    }

    update () {
        const {patternPixelDataLength, patternData, patternAlpha, patternCtx} = this;

        // put a random shade of gray into every pixel of the pattern
        for (let i = 0; i < patternPixelDataLength; i += 4) {
            // const value = (Math.random() * 255) | 0;
            const value = Math.random() * 255;

            patternData.data[i] = value;
            patternData.data[i + 1] = value;
            patternData.data[i + 2] = value;
            patternData.data[i + 3] = patternAlpha;
        }

        patternCtx.putImageData(patternData, 0, 0);
    }

    draw () {
        const {ctx, patternCanvas, canvas, viewHeight} = this;
        const {width, height} = canvas;

        // clear canvas
        ctx.clearRect(0, 0, width, height);

        // fill the canvas using the pattern
        ctx.fillStyle = ctx.createPattern(patternCanvas, 'repeat');
        ctx.fillRect(0, 0, width, height);
    }

    loop () {
        // only update grain every n frames
        const shouldDraw = ++this.frame % this.patternRefreshInterval === 0;
        if (shouldDraw) {
            this.update();
            this.draw();
        }

        window.requestAnimationFrame(this.loop);
    }
}


/**
 * Initiate Grain
 */
const el = document.querySelector('.grain');
const grain = new Grain(el);



$('.phone').mousedown(function(e) {
    initX = e.clientX;
    dragging = true;
})

$('html').mouseup(function(){
    dragging = false
    $('.dynamicCursor').css('width', '18px')
})
$('.phone').mousemove(function(e) {
    if(dragging) {
        let mouseX = e.clientX;
        difference = mouseX - initX;

        console.log(difference)

        $('.dynamicCursor').css('width', Math.abs(difference) + 'px')

        if(difference > 60) {
            $('.phone').addClass('open')
        }

        if(difference < -60) {
            $('.phone').removeClass('open')
        }

    }
});

function drawMouseSpeedDemo() {
    var mrefreshinterval = 30; // update display every 500ms
    var lastmousex=-1; 
    var lastmousey=-1;
    var lastmousetime;
    var mousetravel = 0;
    var mpoints = [];
    var mpoints_max = 30;
    var direction;

    $('html').mousemove(function(e) {
        var mousex = e.pageX;
        var mousey = e.pageY;
        if (lastmousex > -1) {
            mousetravel += Math.max( Math.abs(mousex-lastmousex), Math.abs(mousey-lastmousey) );
        }
        // console.log(mousex-lastmousex)

        if(mousex-lastmousex > 0) {
            direction = '+'
        } else {
            direction = '-'
        }

        //console.log(direction);

        lastmousex = mousex;
        lastmousey = mousey;
    });
    var mdraw = function() {
        var md = new Date();
        var timenow = md.getTime();
        if (lastmousetime && lastmousetime!=timenow) {
            var pps = Math.round(mousetravel / (timenow - lastmousetime) * 1000);
            mpoints.push(pps);
            if (mpoints.length > mpoints_max)
                mpoints.splice(0,1);
            mousetravel = 0;
            //console.log(pps)
            if(dragging) {

            }

        }
        lastmousetime = timenow;
        setTimeout(mdraw, mrefreshinterval);
    }
    // We could use setInterval instead, but I prefer to do it this way
    setTimeout(mdraw, mrefreshinterval); 
};

drawMouseSpeedDemo()


/* -------------------------------------------------

Dynamic cursor

--------------------------------------------------- */

const cursorSettings = {
    'class' : 'dynamicCursor',
    'size' : '18',
    'expandedSize' : '40',
    'expandSpeed' : 0.4,
    'background' : 'rgba(161, 142, 218, 0.25)',
    'opacity' : '1',
    'transitionTime' : '1.4s',
    'transitionEase' : 'cubic-bezier(0.075, 0.820, 0.165, 1.000)',
    'borderWidth' : '0',
    'borderColor' : 'black',
    'iconSize': '11px',
    'iconColor': 'white',
    'triggerElements': {
        'trigger' : {
            'className' : 'trigger',
            'icon' : '<i class="fa fa-plus"></i>'
        },
        'trigger2' : {
            'className' : 'slider_inner',
            'icon' : '<i class="fa fa-arrows-h"></i>'
        }
    }
}


function dynamicCursor(options) {

    document.write('<link rel="stylesheet" href="https://maxcdn.icons8.com/fonts/line-awesome/1.1/css/line-awesome-font-awesome.min.css">');

    var hold;
    cursor = document.createElement('div');
    let cursorIcon = document.createElement('div');

    cursorIcon.classList.add('cursorIcon');
    cursorIcon.style.position = 'absolute';
    cursorIcon.style.fontFamily = 'Raleway';
    cursorIcon.style.textTransform = 'uppercase';
    cursorIcon.style.fontWeight = '800';
    cursorIcon.style.textAlign = 'center'
    cursorIcon.style.top = '50%';
    cursorIcon.style.width = '100%';
    cursorIcon.style.transform = 'translateY(-50%)';
    cursorIcon.style.color = options.iconColor;
    cursorIcon.style.fontSize = options.iconSize;
    cursorIcon.style.opacity = 0;
    cursorIcon.style.transition = `opacity ${options.expandSpeed}s`;

    cursor.classList.add(options.class);
    cursor.style.boxSizing = 'border-box';
    cursor.style.width = `${options.size}px`;
    cursor.style.height = `${options.size}px`;
    cursor.style.borderRadius = `${options.expandedSize}px`;
    cursor.style.opacity = 0;

    cursor.style.pointerEvents = 'none';
    cursor.style.zIndex = 999;
    cursor.style.transition = `transform ${options.transitionTime} ${options.transitionEase}, width 0s, height ${options.expandSpeed}s .2s, opacity 1s .2s`;
    cursor.style.border = `${options.borderWidth}px solid ${options.borderColor}`;
    cursor.style.position = 'fixed';
    cursor.style.background = options.background;

    cursor.appendChild(cursorIcon);
    document.body.appendChild(cursor);

    setTimeout(function() {
        cursor.style.opacity = options.opacity;
    }, 500)

    var idle;

    document.onmousemove = e => {
        console.log('test')
        x = e.pageX;
        y = e.pageY;

        cursor.style.opacity = options.opacity;
        clearInterval(idle)

        idle = setTimeout(function() {
            cursor.style.opacity = 0;
        }, 4000)

        cursor.style.top = '0';
        cursor.style.left = '0';
        cursor.style.transform = `translateX(calc(${x}px - 50%)) translateY(calc(${y}px - 50%))`;
    }

    for(i in options.triggerElements) {

        let trigger = $(`.${options.triggerElements[i].className}`);

        console.log(trigger);


        let icon = options.triggerElements[i].icon;

        if(!trigger) {
            console.warn('You dont have any triggers');
        } else {
            trigger.each(function(el){

                console.log()
                trigger[el].style.cursor = 'default';
                trigger[el].addEventListener('mouseover', () => {
                    console.log('over')
                    cursor.style.width = `${options.expandedSize}px`;
                    cursor.style.height = `${options.expandedSize}px`;
                    cursorIcon.innerHTML = icon;
                    cursorIcon.style.opacity = 1;


                    console.log($(this))


                })

                trigger[el].addEventListener('mouseout', () => {
                    cursor.style.width = `${options.size}px`;
                    cursor.style.height = `${options.size}px`;
                    cursorIcon.style.opacity = 0;
                })
            })

        }
    }
}

dynamicCursor(cursorSettings);

$('.back').click(function(){
    $(this).parent().parent().removeClass('expand')
})
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js