Cinematic Scroll Lens
🔵 InteractiveA premium DSLR-graded viewport featuring smooth scroll-reactive physical blur, custom Fuji Classic Chrome desaturated colors, and constant-ratio reading vignette contrast protection.
Responsive Horizontal Leaderboard
Slot ID: ca-pub-detail-below-preview
Interactive Settings
Medium Rectangle Block
Slot ID: ca-pub-detail-after-customization
Quick Copy Actions
Download File Packages
Keyboard Shortcuts
Responsive Horizontal Leaderboard
Slot ID: ca-pub-detail-before-related
More in Cinematic & Optical
Cinematic Scroll Lens - CSS-only Cinematic & Optical background for React & Tailwind
Integrate the Cinematic Scroll Lens directly into your website. This asset is rendered using pure CSS and HTML keyframes. It is optimized for zero layout-shifts and runs with high-performance hardware-accelerated processing.
⚡ Performance Specifications
- Render Mode: INTERACTIVE (CSS-only)
- Fluidity: Locked at 60fps dynamic loop
- Bundle Footprint: Zero external NPM dependencies
- SEO Indexing status: 100% Crawlable static semantic HTML
🛠️ Integration Capabilities
Our templates expose inline design tokens like --color-1 and --color-2 for infinite color palettes. This template is designed to fit inside hero elements, full-screen landing pages, and interactive presentation cards.
Technical Code Reference & Syntaxes for Googlebot & Crawlers
The snippets below display the direct, unminified source code utilized for rendering this background.
HTML & Inline CSS Snippet (Vanilla)
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cinematic Scroll Lens</title>
<style>
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background: #09090b;
}
.cinematic-scroll-lens-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #050508;
overflow: hidden;
}
.cinematic-image-wrapper {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
transform-origin: center center;
filter: contrast(1.18) saturate(0.72) brightness(0.92) sepia(0.06) blur(var(--scroll-blur, 0px));
transform: scale(var(--scroll-scale, 1.05));
animation: cinematic-breathe-static 45s ease-in-out infinite alternate;
}
.cinematic-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.cinematic-vignette {
position: absolute;
inset: 0;
background: radial-gradient(circle at center, transparent 35%, rgba(0,0,0,0.85) 100%);
pointer-events: none;
opacity: 0.75;
mix-blend-mode: multiply;
}
.cinematic-dark-overlay {
position: absolute;
inset: 0;
background: #09090b;
pointer-events: none;
opacity: var(--scroll-opacity, 0.3);
}
@keyframes cinematic-breathe-static {
0% {
transform: scale(var(--scroll-scale, 1.05)) translate(0px, 0px) rotate(0deg);
}
50% {
transform: scale(calc(var(--scroll-scale, 1.05) * 1.035)) translate(-10px, -4px) rotate(0.15deg);
}
100% {
transform: scale(calc(var(--scroll-scale, 1.05) * 1.07)) translate(8px, 6px) rotate(-0.1deg);
}
}
</style>
</head>
<body>
<div class="cinematic-scroll-lens-container">
<div class="cinematic-image-wrapper">
<img src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?q=80&w=1920&auto=format&fit=crop" alt="Cinematic Landscape" class="cinematic-image" />
</div>
<div class="cinematic-vignette"></div>
<div class="cinematic-dark-overlay"></div>
</div>
<script>
(function() {
const container = document.querySelector('.cinematic-scroll-lens-container');
const imageWrapper = document.querySelector('.cinematic-image-wrapper');
const darkOverlay = document.querySelector('.cinematic-dark-overlay');
if (!container || !imageWrapper || !darkOverlay) return;
let targetScrollRatio = 0;
let currentScrollRatio = 0;
function handleScroll() {
const scrollY = window.scrollY;
const maxScroll = document.documentElement.scrollHeight - window.innerHeight || 1;
targetScrollRatio = scrollY / maxScroll;
}
function handleMessage(e) {
if (e.data && e.data.type === 'scroll') {
targetScrollRatio = e.data.percent;
}
}
window.addEventListener('scroll', handleScroll, { passive: true });
window.addEventListener('message', handleMessage);
function update() {
currentScrollRatio += (targetScrollRatio - currentScrollRatio) * 0.12;
const blurVal = currentScrollRatio * 16;
const opacityVal = 0.3 + currentScrollRatio * 0.5;
const scaleVal = 1.05 + currentScrollRatio * 0.05;
imageWrapper.style.setProperty('--scroll-blur', blurVal + 'px');
imageWrapper.style.setProperty('--scroll-scale', scaleVal);
darkOverlay.style.setProperty('--scroll-opacity', opacityVal);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
})();
</script>
<script>
// Throttled interactive cursor coordinates mapping
(function() {
document.documentElement.style.setProperty('--mouse-x', '0');
document.documentElement.style.setProperty('--mouse-y', '0');
let targetX = 0, targetY = 0;
let currentX = 0, currentY = 0;
window.addEventListener('mousemove', (e) => {
targetX = (e.clientX / window.innerWidth) - 0.5;
targetY = (e.clientY / window.innerHeight) - 0.5;
});
window.addEventListener('mouseleave', () => {
targetX = 0;
targetY = 0;
});
function update() {
currentX += (targetX - currentX) * 0.08;
currentY += (targetY - currentY) * 0.08;
document.documentElement.style.setProperty('--mouse-x', currentX.toFixed(4));
document.documentElement.style.setProperty('--mouse-y', currentY.toFixed(4));
requestAnimationFrame(update);
}
requestAnimationFrame(update);
})();
</script>
</body>
</html>React Component Wrapper (TSX)
import React, { useEffect, useRef } from 'react';
export default function CinematicScrollLensBackground() {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
let targetX = 0, targetY = 0;
let currentX = 0, currentY = 0;
let frameId: number;
const handleMouseMove = (e: MouseEvent) => {
targetX = (e.clientX / window.innerWidth) - 0.5;
targetY = (e.clientY / window.innerHeight) - 0.5;
};
const handleMouseLeave = () => {
targetX = 0;
targetY = 0;
};
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseleave', handleMouseLeave);
const updateCoordinates = () => {
currentX += (targetX - currentX) * 0.08;
currentY += (targetY - currentY) * 0.08;
if (containerRef.current) {
containerRef.current.style.setProperty('--mouse-x', currentX.toFixed(4));
containerRef.current.style.setProperty('--mouse-y', currentY.toFixed(4));
}
frameId = requestAnimationFrame(updateCoordinates);
};
frameId = requestAnimationFrame(updateCoordinates);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseleave', handleMouseLeave);
cancelAnimationFrame(frameId);
};
}, []);
return (
<div
ref={containerRef}
style={{ width: '100%', height: '100%', position: 'relative', overflow: 'hidden' }}
>
<style dangerouslySetInnerHTML={{ __html: `
.cinematic-scroll-lens-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #050508;
overflow: hidden;
}
.cinematic-image-wrapper {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
transform-origin: center center;
filter: contrast(1.18) saturate(0.72) brightness(0.92) sepia(0.06) blur(var(--scroll-blur, 0px));
transform: scale(var(--scroll-scale, 1.05));
animation: cinematic-breathe-static 45s ease-in-out infinite alternate;
}
.cinematic-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.cinematic-vignette {
position: absolute;
inset: 0;
background: radial-gradient(circle at center, transparent 35%, rgba(0,0,0,0.85) 100%);
pointer-events: none;
opacity: 0.75;
mix-blend-mode: multiply;
}
.cinematic-dark-overlay {
position: absolute;
inset: 0;
background: #09090b;
pointer-events: none;
opacity: var(--scroll-opacity, 0.3);
}
@keyframes cinematic-breathe-static {
0% {
transform: scale(var(--scroll-scale, 1.05)) translate(0px, 0px) rotate(0deg);
}
50% {
transform: scale(calc(var(--scroll-scale, 1.05) * 1.035)) translate(-10px, -4px) rotate(0.15deg);
}
100% {
transform: scale(calc(var(--scroll-scale, 1.05) * 1.07)) translate(8px, 6px) rotate(-0.1deg);
}
}
` }} />
{/* HTML Structure */}
<div
style={{ width: '100%', height: '100%' }}
dangerouslySetInnerHTML={{ __html: `
<div class="cinematic-scroll-lens-container">
<div class="cinematic-image-wrapper">
<img src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?q=80&w=1920&auto=format&fit=crop" alt="Cinematic Landscape" class="cinematic-image" />
</div>
<div class="cinematic-vignette"></div>
<div class="cinematic-dark-overlay"></div>
</div>
<script>
(function() {
const container = document.querySelector('.cinematic-scroll-lens-container');
const imageWrapper = document.querySelector('.cinematic-image-wrapper');
const darkOverlay = document.querySelector('.cinematic-dark-overlay');
if (!container || !imageWrapper || !darkOverlay) return;
let targetScrollRatio = 0;
let currentScrollRatio = 0;
function handleScroll() {
const scrollY = window.scrollY;
const maxScroll = document.documentElement.scrollHeight - window.innerHeight || 1;
targetScrollRatio = scrollY / maxScroll;
}
function handleMessage(e) {
if (e.data && e.data.type === 'scroll') {
targetScrollRatio = e.data.percent;
}
}
window.addEventListener('scroll', handleScroll, { passive: true });
window.addEventListener('message', handleMessage);
function update() {
currentScrollRatio += (targetScrollRatio - currentScrollRatio) * 0.12;
const blurVal = currentScrollRatio * 16;
const opacityVal = 0.3 + currentScrollRatio * 0.5;
const scaleVal = 1.05 + currentScrollRatio * 0.05;
imageWrapper.style.setProperty('--scroll-blur', blurVal + 'px');
imageWrapper.style.setProperty('--scroll-scale', scaleVal);
darkOverlay.style.setProperty('--scroll-opacity', opacityVal);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
})();
</script>
` }}
/>
</div>
);
}Next.js App Router Component (use client)
'use client';
import React, { useEffect, useRef } from 'react';
export default function CinematicScrollLensBackground() {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
let targetX = 0, targetY = 0;
let currentX = 0, currentY = 0;
let frameId: number;
const handleMouseMove = (e: MouseEvent) => {
targetX = (e.clientX / window.innerWidth) - 0.5;
targetY = (e.clientY / window.innerHeight) - 0.5;
};
const handleMouseLeave = () => {
targetX = 0;
targetY = 0;
};
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseleave', handleMouseLeave);
const updateCoordinates = () => {
currentX += (targetX - currentX) * 0.08;
currentY += (targetY - currentY) * 0.08;
if (containerRef.current) {
containerRef.current.style.setProperty('--mouse-x', currentX.toFixed(4));
containerRef.current.style.setProperty('--mouse-y', currentY.toFixed(4));
}
frameId = requestAnimationFrame(updateCoordinates);
};
frameId = requestAnimationFrame(updateCoordinates);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseleave', handleMouseLeave);
cancelAnimationFrame(frameId);
};
}, []);
return (
<div
ref={containerRef}
className="w-full h-full relative overflow-hidden"
>
<style dangerouslySetInnerHTML={{ __html: `
.cinematic-scroll-lens-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #050508;
overflow: hidden;
}
.cinematic-image-wrapper {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
transform-origin: center center;
filter: contrast(1.18) saturate(0.72) brightness(0.92) sepia(0.06) blur(var(--scroll-blur, 0px));
transform: scale(var(--scroll-scale, 1.05));
animation: cinematic-breathe-static 45s ease-in-out infinite alternate;
}
.cinematic-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.cinematic-vignette {
position: absolute;
inset: 0;
background: radial-gradient(circle at center, transparent 35%, rgba(0,0,0,0.85) 100%);
pointer-events: none;
opacity: 0.75;
mix-blend-mode: multiply;
}
.cinematic-dark-overlay {
position: absolute;
inset: 0;
background: #09090b;
pointer-events: none;
opacity: var(--scroll-opacity, 0.3);
}
@keyframes cinematic-breathe-static {
0% {
transform: scale(var(--scroll-scale, 1.05)) translate(0px, 0px) rotate(0deg);
}
50% {
transform: scale(calc(var(--scroll-scale, 1.05) * 1.035)) translate(-10px, -4px) rotate(0.15deg);
}
100% {
transform: scale(calc(var(--scroll-scale, 1.05) * 1.07)) translate(8px, 6px) rotate(-0.1deg);
}
}
` }} />
{/* HTML Structure */}
<div
className="w-full h-full"
dangerouslySetInnerHTML={{ __html: `
<div class="cinematic-scroll-lens-container">
<div class="cinematic-image-wrapper">
<img src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?q=80&w=1920&auto=format&fit=crop" alt="Cinematic Landscape" class="cinematic-image" />
</div>
<div class="cinematic-vignette"></div>
<div class="cinematic-dark-overlay"></div>
</div>
<script>
(function() {
const container = document.querySelector('.cinematic-scroll-lens-container');
const imageWrapper = document.querySelector('.cinematic-image-wrapper');
const darkOverlay = document.querySelector('.cinematic-dark-overlay');
if (!container || !imageWrapper || !darkOverlay) return;
let targetScrollRatio = 0;
let currentScrollRatio = 0;
function handleScroll() {
const scrollY = window.scrollY;
const maxScroll = document.documentElement.scrollHeight - window.innerHeight || 1;
targetScrollRatio = scrollY / maxScroll;
}
function handleMessage(e) {
if (e.data && e.data.type === 'scroll') {
targetScrollRatio = e.data.percent;
}
}
window.addEventListener('scroll', handleScroll, { passive: true });
window.addEventListener('message', handleMessage);
function update() {
currentScrollRatio += (targetScrollRatio - currentScrollRatio) * 0.12;
const blurVal = currentScrollRatio * 16;
const opacityVal = 0.3 + currentScrollRatio * 0.5;
const scaleVal = 1.05 + currentScrollRatio * 0.05;
imageWrapper.style.setProperty('--scroll-blur', blurVal + 'px');
imageWrapper.style.setProperty('--scroll-scale', scaleVal);
darkOverlay.style.setProperty('--scroll-opacity', opacityVal);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
})();
</script>
` }}
/>
</div>
);
}Raw CSS Stylesheet Snippet
.cinematic-scroll-lens-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #050508;
overflow: hidden;
}
.cinematic-image-wrapper {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
transform-origin: center center;
filter: contrast(1.18) saturate(0.72) brightness(0.92) sepia(0.06) blur(var(--scroll-blur, 0px));
transform: scale(var(--scroll-scale, 1.05));
animation: cinematic-breathe-static 45s ease-in-out infinite alternate;
}
.cinematic-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.cinematic-vignette {
position: absolute;
inset: 0;
background: radial-gradient(circle at center, transparent 35%, rgba(0,0,0,0.85) 100%);
pointer-events: none;
opacity: 0.75;
mix-blend-mode: multiply;
}
.cinematic-dark-overlay {
position: absolute;
inset: 0;
background: #09090b;
pointer-events: none;
opacity: var(--scroll-opacity, 0.3);
}
@keyframes cinematic-breathe-static {
0% {
transform: scale(var(--scroll-scale, 1.05)) translate(0px, 0px) rotate(0deg);
}
50% {
transform: scale(calc(var(--scroll-scale, 1.05) * 1.035)) translate(-10px, -4px) rotate(0.15deg);
}
100% {
transform: scale(calc(var(--scroll-scale, 1.05) * 1.07)) translate(8px, 6px) rotate(-0.1deg);
}
}