<div id="root"></div>
@font-face {
  font-family: Starjedi;
  src: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/718469/Starjedi.ttf);
  font-weight: normal;
}

@import url('https://fonts.googleapis.com/css?family=Luckiest+Guy');

body {
    background-color: white;
    margin: 0;
}

.darth-vader-saber {
    height: 65px;
    width: 880px;
    position: relative;
        
    .handle {
        width: 220px;
        height: 40px;
        background-color: #BABABA;
        border-radius: 12px;
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        margin: auto;
        
        .shadow {
            width: 220px;
            height: 20px;
            background-color: rgba(255, 255, 255, 0.2);
            position: absolute;
            left: 0;
            bottom: 0;
            border-bottom-left-radius: 8px;
        }
        
        .tip {
            width: 8px;
            height: 40px;
            background-color: #363636;
            border-top-left-radius: 12px;
            border-bottom-left-radius: 12px;
        }
        
        .grip {
            width: 80px;
            height: 10px;
            background-color: #212121;
            position: absolute;
        }
        
        .grip1 {
            left: 8px;
            top: 0px;
        }
        
        .grip2 {
            left: 8px;
            top: 0;
            bottom: 0;
            margin: auto;
        }
        
        .grip3 {
            left: 8px;
            bottom: 0px;
        }
        
        .center {
            width: 50px;
            height: 40px;
            position: absolute;
            background-color: #212121;
            left: 110px;
            top: 0;
        }
        
        .center-bottom {
            width: 40px;
            height: 12px;
            position: absolute;
            background-color: #363636;
            left: 115px;
            bottom: -12px;
            
            .screw {
                width: 5px;
                height: 5Px;
                border-radius: 50%;
                background-color: #BABABA;
                position: absolute;
                top: 0;
                bottom: 0;
                left: 0;
                right: 0;
                margin: auto;
            }
        }
        
        .cables {
            .hole {
                width: 4px;
                height: 12px;
                background-color: #444444;
                position: absolute;
                top: 20px;
                margin: auto;
                border-radius: 30px;
            }
            
            .hole1 {
                left: 175px;                
            }
            
            .hole2 {
                left: 185px;                
            }
            
            .cable {
                height: 2px;
                width: 11px;
                background-color: red;
                position: absolute;
                top: 23px;
                margin: auto;
                left: 175px;
            }
            
            .cable1 {
                top: 24px;
                left: 177px;
            }
            
            .cable2 {
                top: 26px;
                left: 177px;
                background-color: orange;
            }
        }
        
        .guard-tip {
            width: 40px;
            height: 15px;
            background-color: #212121;
            position: absolute;
            top: -5px;
            left: 180px;
        }
        
        .guard-rectangle {
            width: 20px;
            height: 45px;
            background-color: #212121;
            position: absolute;
            top: 0;
            bottom: 0;
            margin: auto;
            left: 210px;
            
            .shadow {
                width: 20px;
                height: 22.5px;
                background-color: rgba(255, 255, 255, 0.2);
                position: absolute;
                bottom: 0;
                left: 0;
            }
        }
        
        .guard-triangle {
            width: 0;
            height: 0;
            border-style: solid;
            border-width: 45px 35px 0 0;
            border-color: #212121 transparent transparent transparent;
            position: absolute;
            top: 0;
            bottom: 0;
            margin: auto;
            left: 230px;
            
            
        }
        
        .guard-triangle-shadow {
            width: 0;
            height: 0;
            border-style: solid;
            border-width: 22.5px 17px 0 0;
            border-color: rgba(255, 255, 255, 0.2) transparent transparent transparent;
            position: absolute;
            bottom: -2px;
            left: 230px;
        }
    }
    
    .laser-active {        
        box-shadow: 30px 0 30px #FC3030;
        animation: glowNeon 80ms linear infinite;
        animation-direction: alternate-reverse;
    }
    
    .laser {
        height: 35px;
        background-color: red;
        position: absolute;
        left: 220px;
        top: 0;
        bottom: 0;
        margin: auto;
        
        .laser-glow {
            width: 100%;
            height: 20px;
            background-color: rgba(255, 255, 255, 0.96);
            position: absolute;
            left: 0;
            top: 0;
            bottom: 0;
            margin: auto;
        }
        
        .laser-glow-active {
            animation: glow 80ms linear infinite;
            animation-direction: alternate-reverse;
        }
        
        .laser-tip {
            height: 35px;
            width: 30px;
            background-color: red;
            position: absolute;
            right: -30px;
            top: 0;
            bottom: 0;
            margin: auto;
            border-top-right-radius: 50%;
            border-bottom-right-radius: 50%;
            
            .laser-glow {
                width: 80%;
                border-top-right-radius: 50%;
                border-bottom-right-radius: 50%;
            }
        }
        
        @keyframes glowNeon {
            from {
                box-shadow: 30px 0 30px #FC3030;
            }
            to {
                box-shadow: 30px 0 26px #FC3030;
            }
        }
        
        @keyframes glow {
            from {
                background-color: rgba(255, 255, 255, 0.96);
            }
            to {
                background-color: rgba(255, 255, 255, 0.92);
            }
        }
    }
}

.saber-demo {
    width: 100%;
    height: 180px;
    position: absolute;
    text-align: center;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    margin: auto;

    h1 {
        position: absolute;
        top: 0; 
        left: 0;
        right: 0;
        margin: auto;
        font-family: 'Starjedi';
        color: #212121;
    }

    .saber, {
        position: absolute;
        top: 100px; 
        left: 0;
        right: 0;
        margin: auto;
    }

    .percent {
        color: #D2D5D6;
        position: absolute;
        top: 60px; 
        bottom: 0;
        left: 0;
        right: 0;
        margin: auto;
        font-family: 'Luckiest Guy';
        font-size: 30px;
    }
}
View Compiled
class DarthVaderSaber extends React.Component {
    render() {
        const laserMax = 630
        const percent = this.props.percent >= 1 ? 1 : this.props.percent
        const glowStyle = percent >= 1 ? 'laser-glow laser-glow-active' : 'laser-glow'
        const width = percent * laserMax
        const laserStyle = { width: width + 'px' }
        const laserClass = percent >= 1 ? 'laser laser-active' : 'laser'
        return (
            <div className="saber darth-vader-saber">
                <div className="handle">
                    <div className="tip"></div>
                    <div className="grip grip1"></div>
                    <div className="grip grip2"></div>
                    <div className="grip grip3"></div>
                    <div className="center"></div>
                    <div className="laser"></div>
                    <div className="center-bottom">
                        <div className="screw"></div>
                    </div>
                    <div className="cables">
                        <div className="hole hole1"></div>
                        <div className="hole hole2"></div>
                        <div className="cable cable1"></div>
                        <div className="cable cable2"></div>
                    </div>
                    <div className="shadow"></div>
                    <div className={laserClass} style={laserStyle}>
                        <div className={glowStyle}></div>
                        <div className="laser-tip">
                            <div className={glowStyle}></div>
                        </div>
                    </div>
                    <div className="guard-tip"></div>
                    <div className="guard-rectangle">
                        <div className="shadow"></div>
                    </div>
                    <div className="guard-triangle">
                    </div>
                    <div className="guard-triangle-shadow"></div>
                </div>
            </div>
        )
    }
}

class Demo extends React.Component {
    state = { percent: 0 }
    
    componentDidMount() {
        this.interval = setInterval(
          () => { 
              if (this.state.percent >= 1) {
                  clearInterval(this.interval)
              } else {
                  this.setState({ percent: this.state.percent + 0.001 }) 
              }
          },
          5
        )
    }
    
    render() {
        const { percent } = this.state
        return (
            <div className="saber-demo">
                <h1>Loading</h1>
                <div className="percent">{(percent * 100).toFixed(0)}%</div>
                <DarthVaderSaber percent={percent} />
            </div>
        )
    }
}

ReactDOM.render(<Demo />, document.getElementById('root'))
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.development.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.development.js