<html lang="en" >
<head>
<meta charset="UTF-8">
<title>CodePen - Shadow cast spotlight</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- partial:index.partial.html -->
<div id="container">
<div id="title">Move your cursor over the box to cast a shadow with the spotlight.</div>
<div id="box">
<div class="shadow__wall">
<div class="shadow__box" id="shadow__box--back"></div>
<p id="shadow__text">12:34:56</p>
<div class="shadow__box" id="shadow__box--front"></div>
</div>
<div id="shadow__spot"></div>
</div>
</div>
<!-- partial -->
<script src="./script.js"></script>
</body>
</html>
* {
box-sizing: border-box;
}
html, body {
margin: 0;
padding: 0;
}
body {
background: black;
color: #f28282;
font-family: sans-serif;
font-size: 16px;
overscroll-behavior: none;
display: flex;
flex-direction: column;
align-items: center;
height: 100vh;
}
#container {
width: 100vw;
height: 100vh;
}
#title {
text-align: center;
width: 100%;
padding: 10px 0 10px 0;
}
#box {
position: relative;
width: 100%;
height: 100%;
background: #ff0303;
overflow: hidden;
/*cursor: none;*/
border: 1px solid #333;
tap-highlight-color: rgba(0,0,0,0);
user-select: none;
}
.shadow__wall {
position: absolute;
top: 50%;
left: 0;
width: 100%;
}
#shadow__text {
position: absolute;
width: 100%;
margin: 0;
color: #06a9d2;
font-family: Helvetica, Arial, sans-serif;
font-size: 5rem;
font-weight: bold;
text-align: center;
white-space: nowrap;
}
.shadow__box {
position: absolute;
background: #c85151;
top: 4.5rem;
height: 50vh;
}
#shadow__box--back {
left: -5%;
width: 110%;
}
#shadow__box--front {
left: 0;
width: 100%;
}
#spotlight {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
mask-composite: destination-out;
mask-composite: exclude;
z-index: 1;
}
#shadow__spot {
position: absolute;
top: 0;
left: 0;
width: 200%;
height: 200%;
background: gradient(radial, center center, 0, center center, 250, from(rgba(0,0,0,0)), to(rgba(0,0,0,1)));
}
const textElem = document.querySelector('#shadow__text');
const spotElem = document.querySelector('#shadow__spot');
const boxElem = document.querySelector('#shadow__box--back');
const container = document.querySelector('#box');
var width = container.offsetWidth;
var height = container.offsetHeight;
const relMousePos = {
_x: 0, _y: 0, x: 0, y: 0,
updatePos: function(e) {
const event = (e || window.event) && (e.touches && e.touches[0]) || e;
this.x = event.clientX - this._x;
this.y = event.clientY - this._y;
},
setOrigin: function(e) {
this._x = e.offsetLeft + Math.floor(e.offsetWidth / 2);
this._y = e.offsetTop + Math.floor(e.offsetHeight / 2);
}
}
relMousePos.setOrigin(container);
container.addEventListener('mousemove', relMousePos.updatePos);
function updateSize(e) {
width = container.offsetWidth;
height = container.offsetHeight;
relMousePos.setOrigin(container);
onMouseMove({clientX: relMousePos._x, clientY: relMousePos._y + 25});
}
function updateTime() {
let date = new Date();
let time = date.toLocaleTimeString();
textElem.innerText = time;
setTimeout(updateTime, 1000);
}
function onMouseMove(e) {
relMousePos.updatePos(e);
var xm = relMousePos.x;
var ym = relMousePos.y;
var d = Math.round(Math.sqrt(xm*xm + ym*ym) / 10);
textElem.style.textShadow = -xm + 'px ' + -ym + 'px ' + (d + 10) + 'px black';
boxElem.style.boxShadow = '0 ' + -ym + 'px ' + (d + 30) + 'px black';
spotElem.style.backgroundPosition = (xm - (width / 2)) + 'px ' + (ym - (height / 2)) + 'px';
}
function init() {
updateTime();
container.addEventListener('mousemove', onMouseMove);
container.addEventListener('touchmove', function (e) {
e.preventDefault();
e.stopPropagation();
onMouseMove(e);
}, {passive: false});
onMouseMove({clientX: relMousePos._x, clientY: relMousePos._y + 25});
}
document.addEventListener('resize', updateSize);
document.addEventListener('DOMContentLoaded', init);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.