v2.2
MENU ANIMATIONS
UI SURECART
BUTTONS
<!DOCTYPE html>
<html lang="en">
<head>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vertical Parallax Configurator - BricksFusion</title>
<style>
:root {
--background: #000;
--card-bg: #1e1e1e;
--card-bg-hover: #252525;
--text-primary: #f2f2f7;
--text-secondary: #8e8e93;
--accent: #ef6013;
--accent-hover: #c64c0c;
--border: #2c2c2e;
--shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
--track: #2c2c2e;
--thumb: #ef6013;
--card-radius: 16px;
--input-radius: 8px;
--button-radius: 12px;
--transition: all 0.25s ease;
--font: 'Inter', BlinkMacSystemFont, "San Francisco", "Helvetica Neue", Helvetica, Arial, sans-serif;
--action-bar-height: 70px;
--success: #28a745;
--warning: #ffc107;
--danger: #dc3545;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: var(--font);
background-color: var(--background);
color: var(--text-primary);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding-bottom: var(--action-bar-height);
}
.action-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: var(--action-bar-height);
background: linear-gradient(145deg, #1a1a1a, #0f0f0f);
border-top: 1px solid var(--border);
z-index: 1000;
display: flex;
align-items: center;
padding: 0 1.5rem;
gap: 1rem;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
}
.breadcrumb {
display: flex;
align-items: center;
gap: 0.5rem;
flex: 1;
}
.breadcrumb-item {
color: var(--text-secondary);
font-size: var(--text-xs);
font-weight: 500;
text-decoration: none;
transition: var(--transition);
padding: 0.5rem 0.75rem;
border-radius: 6px;
}
.breadcrumb-item:hover {
color: var(--text-primary);
background-color: rgba(255, 255, 255, 0.05);
}
.breadcrumb-item.active {
color: var(--accent);
background-color: rgba(239, 96, 19, 0.1);
}
.breadcrumb-separator {
color: var(--text-secondary);
font-size: var(--text-xs);
opacity: 0.5;
}
.action-buttons {
display: flex;
align-items: center;
gap: 0.75rem;
}
.action-btn {
padding: 0.6rem 1rem;
background-color: var(--card-bg);
color: var(--text-primary);
font-family: var(--font);
font-size: var(--text-xs);
font-weight: 500;
border: 1px solid var(--border);
border-radius: var(--button-radius);
cursor: pointer;
transition: var(--transition);
display: flex;
align-items: center;
gap: 0.5rem;
text-decoration: none;
white-space: nowrap;
}
.action-btn:hover {
background-color: var(--card-bg-hover);
border-color: var(--accent);
transform: translateY(-1px);
}
.action-btn.primary {
background: linear-gradient(90deg, var(--accent), #ff8c51);
border-color: var(--accent);
color: white;
}
.action-btn.primary:hover {
background: linear-gradient(90deg, var(--accent-hover), #e67a3f);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(239, 96, 19, 0.3);
}
.data-attribute-display {
background-color: rgba(50, 50, 50, 0.8);
border: 1px solid var(--border);
border-radius: 6px;
padding: 0.5rem 0.75rem;
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
font-size: var(--text-xs);
color: #ff8c51;
cursor: pointer;
transition: var(--transition);
user-select: all;
}
.data-attribute-display:hover {
background-color: rgba(239, 96, 19, 0.2);
border-color: var(--accent);
}
.container {
max-width: 100%;
margin: 0 auto;
padding: 2rem 1.5rem;
}
.page-header {
text-align: center;
margin-bottom: 2rem;
}
.page-title {
font-size: 2.5rem;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 0.5rem;
background: linear-gradient(90deg, var(--accent), #ff8c51);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.page-subtitle {
font-size: var(--text-s);
color: var(--text-secondary);
font-weight: 500;
}
.instructions-toggle {
margin-bottom: 2rem;
}
.instructions-card {
background-color: var(--card-bg);
border: 1px solid var(--border);
border-radius: var(--card-radius);
box-shadow: var(--shadow);
overflow: hidden;
transition: var(--transition);
}
.instructions-header {
padding: 1rem 1.5rem;
cursor: pointer;
transition: var(--transition);
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid transparent;
}
.instructions-header:hover {
background-color: var(--card-bg-hover);
}
.instructions-card.expanded .instructions-header {
border-bottom-color: var(--border);
}
.instructions-title {
font-size: var(--text-s);
font-weight: 600;
}
.toggle-icon {
font-size: 1.2em;
transition: transform 0.3s ease;
}
.toggle-icon.expanded {
transform: rotate(180deg);
}
.instructions-content {
padding: 0 1.5rem;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease, padding 0.3s ease;
}
.instructions-content.show {
max-height: 500px;
padding: 1.5rem;
}
.instructions-grid {
display: grid;
grid-template-columns: 1fr;
gap: 1.5rem;
}
.how-to-use ol {
padding-left: 1.5rem;
}
.how-to-use li {
margin-bottom: 0.75rem;
font-size: var(--text-xs);
color: var(--text-secondary);
line-height: 1.6;
}
.how-to-use strong {
color: var(--text-primary);
font-weight: 600;
}
.how-to-use code {
background-color: rgba(50, 50, 50, 0.5);
padding: 0.2rem 0.5rem;
border-radius: 4px;
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
font-size: var(--text-xs);
color: #ff8c51;
}
.content {
display: grid;
grid-template-columns: 1fr 500px;
gap: 2rem;
align-items: start;
}
.preview-section {
position: sticky;
top: 2rem;
}
.controls-section {
max-width: 500px;
}
.card {
background-color: var(--card-bg);
border-radius: var(--card-radius);
box-shadow: var(--shadow);
overflow: hidden;
margin-bottom: 1.5rem;
border: 1px solid var(--border);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4);
}
.preview-container {
height: 400px;
width: 100%;
position: relative;
overflow-y: auto;
overflow-x: hidden;
border-radius: var(--card-radius);
background-color: #252525;
border: 1px solid var(--border);
box-shadow: var(--shadow);
scroll-behavior: smooth;
}
.preview-container::-webkit-scrollbar {
width: 8px;
}
.preview-container::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
}
.preview-container::-webkit-scrollbar-thumb {
background: var(--accent);
border-radius: 4px;
}
.preview-container::-webkit-scrollbar-thumb:hover {
background: var(--accent-hover);
}
.preview-container::before {
content: '';
display: block;
height: 800px;
width: 100%;
}
.scroll-badge {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 1rem 1.5rem;
border-radius: 12px;
backdrop-filter: blur(15px);
border: 1px solid rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
gap: 0.75rem;
font-size: var(--text-xs);
font-weight: 500;
z-index: 10;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
animation: pulse 2s infinite;
}
.scroll-icon {
font-size: 1.2em;
color: var(--accent);
animation: bounce 1.5s infinite;
}
.scroll-icon:first-child {
animation-delay: 0s;
}
.scroll-icon:last-child {
animation-delay: 0.75s;
}
@keyframes pulse {
0%, 100% {
transform: translate(-50%, -50%) scale(1);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}
50% {
transform: translate(-50%, -50%) scale(1.05);
box-shadow: 0 12px 40px rgba(239, 96, 19, 0.2);
}
}
@keyframes bounce {
0%, 20%, 50%, 80%, 100% {
transform: translateY(0);
}
40% {
transform: translateY(-4px);
}
60% {
transform: translateY(-2px);
}
}
.preview-content {
color: white;
text-align: center;
font-weight: bold;
font-size: var(--text-s);
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 2;
}
.card-heading {
padding: 1rem 1.5rem;
font-size: var(--text-s);
font-weight: 600;
border-bottom: 1px solid var(--border);
letter-spacing: 0.3px;
display: flex;
justify-content: space-between;
align-items: center;
}
.card-actions {
display: flex;
gap: 0.5rem;
}
.card-action-btn {
padding: 0.4rem 0.8rem;
background-color: transparent;
color: var(--text-secondary);
border: 1px solid var(--border);
border-radius: 6px;
cursor: pointer;
font-size: var(--text-xs);
transition: var(--transition);
}
.card-action-btn:hover {
color: var(--text-primary);
border-color: var(--accent);
background-color: rgba(239, 96, 19, 0.1);
}
.card-content {
padding: 1.5rem;
}
.control-group {
margin-bottom: 1.5rem;
position: relative;
}
.control-group:last-child {
margin-bottom: 0;
}
.control-label {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.75rem;
}
.label-text {
font-size: var(--text-xs);
font-weight: 500;
letter-spacing: 0.2px;
display: flex;
align-items: center;
gap: 0.5rem;
}
.help-tooltip {
cursor: help;
opacity: 0.7;
transition: var(--transition);
}
.help-tooltip:hover {
opacity: 1;
color: var(--accent);
}
.value-display {
display: flex;
align-items: center;
gap: 0.5rem;
}
.value-text {
font-size: var(--text-xs);
color: var(--text-secondary);
background-color: rgba(50, 50, 50, 0.5);
padding: 2px 8px;
border-radius: 4px;
min-width: 45px;
text-align: center;
}
.reset-btn {
padding: 0.2rem 0.4rem;
background-color: transparent;
color: var(--text-secondary);
border: 1px solid var(--border);
border-radius: 4px;
cursor: pointer;
font-size: 10px;
transition: var(--transition);
}
.reset-btn:hover {
color: var(--danger);
border-color: var(--danger);
background-color: rgba(220, 53, 69, 0.1);
}
input[type="range"] {
-webkit-appearance: none;
width: 100%;
height: 6px;
background: var(--track);
border-radius: 3px;
outline: none;
margin: 0.8rem 0;
position: relative;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
background: var(--thumb);
border-radius: 50%;
cursor: pointer;
transition: var(--transition);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
input[type="range"]::-webkit-slider-thumb:hover {
transform: scale(1.2);
box-shadow: 0 0 10px rgba(239, 96, 19, 0.5);
}
input[type="text"],
input[type="number"],
input[type="url"],
select {
width: 100%;
padding: 0.75rem;
border: 1px solid var(--border);
border-radius: var(--input-radius);
font-family: var(--font);
font-size: var(--text-xs);
color: var(--text-primary);
background-color: var(--card-bg);
margin-bottom: 0.75rem;
outline: none;
transition: var(--transition);
}
input[type="text"]:focus,
input[type="number"]:focus,
input[type="url"]:focus,
select:focus {
border-color: var(--accent);
box-shadow: 0 0 0 2px rgba(239, 96, 19, 0.2);
}
select {
cursor: pointer;
}
.image-input-container {
position: relative;
margin-bottom: 1rem;
}
.image-preview {
width: 100%;
height: 120px;
border-radius: var(--input-radius);
background-size: cover;
background-position: center;
background-repeat: no-repeat;
border: 2px dashed var(--border);
display: flex;
align-items: center;
justify-content: center;
color: var(--text-secondary);
font-size: var(--text-xs);
margin-bottom: 0.75rem;
transition: var(--transition);
background-color: rgba(30, 30, 30, 0.5);
}
.image-preview:hover {
border-color: var(--accent);
}
.image-preview.has-image {
border-style: solid;
border-color: var(--accent);
}
.sample-images {
display: flex;
gap: 0.5rem;
margin-top: 0.5rem;
flex-wrap: wrap;
}
.sample-image {
width: 60px;
height: 40px;
border-radius: 4px;
background-size: cover;
background-position: center;
cursor: pointer;
border: 2px solid transparent;
transition: var(--transition);
}
.sample-image:hover {
border-color: var(--accent);
transform: scale(1.05);
}
.sample-image.active {
border-color: var(--accent);
}
.notification {
position: fixed;
bottom: calc(var(--action-bar-height) + 1rem);
left: 50%;
background-color: var(--success);
color: white;
padding: 0.75rem 1rem;
border-radius: var(--input-radius);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
z-index: 1001;
transform: translate(-50%, 200px);
opacity: 0;
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s ease;
font-size: var(--text-xs);
font-weight: 500;
max-width: 320px;
word-wrap: break-word;
line-height: 1.4;
text-align: center;
}
.notification.show {
transform: translate(-50%, 0);
opacity: 1;
}
@media (max-width: 1200px) {
.content {
grid-template-columns: 1fr;
gap: 1.5rem;
}
.preview-section {
position: static;
}
.controls-section {
max-width: 100%;
}
}
@media (max-width: 768px) {
.action-bar {
flex-direction: column;
height: auto;
min-height: var(--action-bar-height);
padding: 0.75rem;
}
.breadcrumb {
order: 1;
width: 100%;
}
.action-buttons {
order: 2;
width: 100%;
justify-content: center;
flex-wrap: wrap;
}
body {
padding-bottom: calc(var(--action-bar-height) + 20px);
}
.notification {
bottom: calc(var(--action-bar-height) + 2rem);
max-width: 280px;
transform: translate(-50%, 250px);
}
.notification.show {
transform: translate(-50%, 0);
opacity: 1;
}
.preview-container {
height: 300px;
}
.data-attribute-display {
font-size: 10px;
padding: 0.4rem 0.6rem;
}
.action-btn {
font-size: 11px;
padding: 0.5rem 0.8rem;
}
.page-title {
font-size: 2rem;
}
}
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
button:focus-visible,
input:focus-visible,
.action-btn:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: var(--background);
}
::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--accent);
}
.loading {
opacity: 0.6;
pointer-events: none;
position: relative;
}
.loading::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 20px;
height: 20px;
margin: -10px 0 0 -10px;
border: 2px solid var(--border);
border-top-color: var(--accent);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="action-bar">
<nav class="breadcrumb">
<a href="https://bricksfusion.com" class="breadcrumb-item">Home</a>
<span class="breadcrumb-separator">›</span>
<a href="https://bricksfusion.com/interaction/" class="breadcrumb-item">Interactions</a>
<span class="breadcrumb-separator">›</span>
<span class="breadcrumb-item active">Vertical Parallax</span>
</nav>
<div class="action-buttons">
<div class="data-attribute-display" id="quick-attribute" title="Click to copy data attribute">
data-vertical-parallax
</div>
<button class="action-btn primary" id="download-config" title="Copy JavaScript code (Ctrl+D)" data-protection-animation="true">
<span>📋</span>
Copy JS
</button>
<button class="action-btn" id="copy-full-section" title="Copy complete section JSON for Bricks Builder (Ctrl+S)" data-protection-animation="true">
<span>📦</span>
Copy Full Section
</button>
</div>
</div>
<div class="container">
<div class="page-header">
<h1 class="page-title">Vertical Parallax</h1>
<p class="page-subtitle">Interactive scrolling effects for Bricks Builder</p>
</div>
<div class="instructions-toggle">
<div class="instructions-card" id="instructions-card">
<div class="instructions-header" id="instructions-toggle">
<div class="instructions-title">
How to Use & Code Information
</div>
<span class="toggle-icon">▼</span>
</div>
<div class="instructions-content" id="instructions-content">
<div class="instructions-grid">
<div class="how-to-use">
<ol>
<li>Customize your vertical parallax effect using the controls below</li>
<li>Click <strong>Copy JS</strong> to copy the JavaScript code to clipboard</li>
<li>In Bricks Builder, add a <strong>Code</strong> element</li>
<li>Paste or upload the JavaScript code</li>
<li>To add the effect to any section: go to <strong>Section → Style → Attributes</strong>, add <code>data-vertical-parallax</code> as attribute name (leave value empty)</li>
</ol>
</div>
</div>
</div>
</div>
</div>
<div class="content">
<section class="preview-section">
<div class="preview-container" id="parallax-preview" data-vertical-parallax>
<div class="scroll-badge">
<div class="scroll-icon">⬇</div>
<span>Scroll to see effect</span>
<div class="scroll-icon">⬆</div>
</div>
</div>
</section>
<section class="controls-section">
<div class="card">
<div class="card-heading">
Background Image
<div class="card-actions">
<button class="card-action-btn" id="reset-image" title="Reset Image Settings">↺</button>
</div>
</div>
<div class="card-content">
<div class="control-group">
<div class="control-label">
<span class="label-text">Image URL</span>
</div>
<div class="image-input-container">
<div class="image-preview" id="image-preview">
<span>Enter image URL below or click a sample</span>
</div>
<input type="url" id="image-url" placeholder="https://example.com/image.jpg" value="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?ixlib=rb-4.0.3&auto=format&fit=crop&w=2000&q=80">
<div class="sample-images">
<div class="sample-image" data-url="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?ixlib=rb-4.0.3&auto=format&fit=crop&w=2000&q=80" style="background-image: url('https://images.unsplash.com/photo-1506905925346-21bda4d32df4?ixlib=rb-4.0.3&auto=format&fit=crop&w=200&q=80')"></div>
<div class="sample-image" data-url="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?ixlib=rb-4.0.3&auto=format&fit=crop&w=2000&q=80" style="background-image: url('https://images.unsplash.com/photo-1441974231531-c6227db76b6e?ixlib=rb-4.0.3&auto=format&fit=crop&w=200&q=80')"></div>
<div class="sample-image" data-url="https://images.unsplash.com/photo-1547036967-23d11aacaee0?ixlib=rb-4.0.3&auto=format&fit=crop&w=2000&q=80" style="background-image: url('https://images.unsplash.com/photo-1547036967-23d11aacaee0?ixlib=rb-4.0.3&auto=format&fit=crop&w=200&q=80')"></div>
<div class="sample-image" data-url="https://images.unsplash.com/photo-1519904981063-b0cf448d479e?ixlib=rb-4.0.3&auto=format&fit=crop&w=2000&q=80" style="background-image: url('https://images.unsplash.com/photo-1519904981063-b0cf448d479e?ixlib=rb-4.0.3&auto=format&fit=crop&w=200&q=80')"></div>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-heading">
Animation Settings
<div class="card-actions">
<button class="card-action-btn" id="reset-animation" title="Reset Animation Settings">↺</button>
</div>
</div>
<div class="card-content">
<div class="control-group">
<div class="control-label">
<span class="label-text">
Parallax Intensity
<span class="help-tooltip" title="Controls how strong the parallax effect is">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="intensity-value">0.25</span></span>
<button class="reset-btn" onclick="resetParameter('parallax-intensity', 0.25)">↺</button>
</div>
</div>
<input type="range" id="parallax-intensity" min="0.05" max="0.8" step="0.05" value="0.25">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Zoom Factor
<span class="help-tooltip" title="Background image zoom level">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="zoom-value">1.6</span></span>
<button class="reset-btn" onclick="resetParameter('zoom-factor', 1.6)">↺</button>
</div>
</div>
<input type="range" id="zoom-factor" min="1.2" max="3.0" step="0.1" value="1.6">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Transition Duration
<span class="help-tooltip" title="Animation transition timing">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="transition-value">0.3</span>s</span>
<button class="reset-btn" onclick="resetParameter('transition-duration', 0.3)">↺</button>
</div>
</div>
<input type="range" id="transition-duration" min="0.1" max="1" step="0.1" value="0.3">
</div>
</div>
</div>
<div class="card">
<div class="card-heading">
Advanced Options
<div class="card-actions">
<button class="card-action-btn" id="reset-advanced" title="Reset Advanced Settings">↺</button>
</div>
</div>
<div class="card-content">
<div class="control-group">
<div class="control-label">
<span class="label-text">
Brightness
<span class="help-tooltip" title="Image brightness level">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="brightness-value">100</span>%</span>
<button class="reset-btn" onclick="resetParameter('brightness', 100)">↺</button>
</div>
</div>
<input type="range" id="brightness" min="20" max="200" step="5" value="100">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Contrast
<span class="help-tooltip" title="Image contrast level">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="contrast-value">100</span>%</span>
<button class="reset-btn" onclick="resetParameter('contrast', 100)">↺</button>
</div>
</div>
<input type="range" id="contrast" min="50" max="200" step="5" value="100">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Saturation
<span class="help-tooltip" title="Image color saturation">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="saturation-value">100</span>%</span>
<button class="reset-btn" onclick="resetParameter('saturation', 100)">↺</button>
</div>
</div>
<input type="range" id="saturation" min="0" max="200" step="5" value="100">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Blur
<span class="help-tooltip" title="Image blur effect">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="blur-value">0</span>px</span>
<button class="reset-btn" onclick="resetParameter('blur', 0)">↺</button>
</div>
</div>
<input type="range" id="blur" min="0" max="10" step="0.5" value="0">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Sepia
<span class="help-tooltip" title="Sepia filter effect">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="sepia-value">0</span>%</span>
<button class="reset-btn" onclick="resetParameter('sepia', 0)">↺</button>
</div>
</div>
<input type="range" id="sepia" min="0" max="100" step="5" value="0">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Grayscale
<span class="help-tooltip" title="Grayscale filter effect">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="grayscale-value">0</span>%</span>
<button class="reset-btn" onclick="resetParameter('grayscale', 0)">↺</button>
</div>
</div>
<input type="range" id="grayscale" min="0" max="100" step="5" value="0">
</div>
</div>
</div>
</section>
</div>
</div>
<div class="notification" id="notification"></div>
<script>
document.addEventListener('DOMContentLoaded', function() {
let parallaxConfig = {
imageUrl: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?ixlib=rb-4.0.3&auto=format&fit=crop&w=2000&q=80',
intensity: 0.25,
zoomFactor: 1.6,
transitionDuration: 0.3,
brightness: 100,
contrast: 100,
saturation: 100,
blur: 0,
sepia: 0,
grayscale: 0
};
const defaultConfig = { ...parallaxConfig };
let previewParallaxEffect = null;
let previewState = {
bgElement: null,
container: null,
currentImageUrl: null,
scrollContainer: null,
rafId: null,
throttledParallax: null,
handleResize: null
};
let updateTimeout = null;
function debouncedUpdatePreview() {
if (updateTimeout) clearTimeout(updateTimeout);
updateTimeout = setTimeout(() => {
updatePreview();
}, 50);
}
function showNotification(message, type = 'success') {
const notification = document.getElementById('notification');
notification.textContent = message;
notification.className = `notification ${type}`;
notification.offsetHeight;
notification.style.visibility = 'visible';
notification.classList.add('show');
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => {
if (!notification.classList.contains('show')) {
notification.style.visibility = 'hidden';
}
}, 400);
}, 3000);
}
function generateUniqueId() {
return Math.random().toString(36).substring(2, 8);
}
function generateFullSectionJSON() {
// Generar IDs únicos para todos los elementos
const sectionId = generateUniqueId();
const containerId = generateUniqueId();
const codeId = generateUniqueId();
const attributeId1 = generateUniqueId();
const attributeId2 = generateUniqueId();
// Obtener el JavaScript actual con la configuración del usuario
const jsCode = generateJavaScriptCode();
// Crear el objeto JSON completo de Bricks Builder
const bricksJSON = {
"content": [
{
"id": sectionId,
"name": "section",
"parent": 0,
"children": [containerId, codeId],
"settings": {
"_justifyContent": "center",
"_height": "800",
"_attributes": [
{
"id": attributeId1,
"name": "data-vertical-parallax"
}
]
},
"label": "Vertical Parallax Section"
},
{
"id": containerId,
"name": "container",
"parent": sectionId,
"children": [],
"settings": {
"_alignSelf": "center",
"_justifyContent": "center",
"_alignItems": "center",
"_direction": "row",
"_attributes": [
{
"id": attributeId2,
"name": "data-float-container"
}
]
}
},
{
"id": codeId,
"name": "code",
"parent": sectionId,
"children": [],
"settings": {
"javascriptCode": jsCode,
"executeCode": true,
"_display": "none"
},
"label": "Vertical Parallax JS"
}
],
"source": "bricksCopiedElements",
"sourceUrl": "https://test.bricksfusion.com",
"version": "2.0.1",
"globalClasses": [],
"globalElements": []
};
return JSON.stringify(bricksJSON, null, 2);
}
function generateJavaScriptCode() {
return `(function() {
const ATTR_NAME = 'data-vertical-parallax';
const defaultConfig = {
imageUrl: '${parallaxConfig.imageUrl}',
intensity: ${parallaxConfig.intensity},
zoomFactor: ${parallaxConfig.zoomFactor},
transitionDuration: ${parallaxConfig.transitionDuration},
brightness: ${parallaxConfig.brightness},
contrast: ${parallaxConfig.contrast},
saturation: ${parallaxConfig.saturation},
blur: ${parallaxConfig.blur},
sepia: ${parallaxConfig.sepia},
grayscale: ${parallaxConfig.grayscale}
};
const styleSheet = document.createElement('style');
styleSheet.textContent = \`
[\${ATTR_NAME}] {
position: relative;
overflow: hidden;
width: 100%;
height: 100%;
min-height: 200px;
}
[\${ATTR_NAME}] .parallax-bg {
will-change: transform;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
transform: translateZ(0);
min-width: 100%;
min-height: 100%;
transition: background-size 0.3s ease-out;
}
[\${ATTR_NAME}] .parallax-content {
position: relative;
z-index: 1;
width: 100%;
}
\`;
document.head.appendChild(styleSheet);
function getParallaxIntensity() {
if (window.matchMedia("(max-width: 480px)").matches) return defaultConfig.intensity * 0.7;
if (window.matchMedia("(max-width: 767px)").matches) return defaultConfig.intensity * 0.8;
if (window.matchMedia("(min-width: 768px) and (max-width: 1024px)").matches) return defaultConfig.intensity * 0.9;
return defaultConfig.intensity;
}
function adjustBackgroundSize(bgElement, state) {
const containerWidth = bgElement.offsetWidth;
const containerHeight = bgElement.offsetHeight;
const mobileZoom = state.isMobile ? (defaultConfig.zoomFactor * 1.2) : defaultConfig.zoomFactor;
const minHeight = containerHeight * mobileZoom;
if (state.imageRatio > 1) {
const width = minHeight * state.imageRatio;
const finalWidth = Math.max(width, containerWidth * 1.6);
bgElement.style.backgroundSize = \`\${Math.ceil(finalWidth)}px \${Math.ceil(minHeight)}px\`;
} else {
const minWidth = containerWidth * (state.isMobile ? 1 : 1.6);
const height = minWidth / state.imageRatio;
const finalHeight = Math.max(height, minHeight);
bgElement.style.backgroundSize = \`\${Math.ceil(minWidth)}px \${Math.ceil(finalHeight)}px\`;
}
}
function applyParallax(bgElement, state) {
const previewContainer = bgElement.closest('.preview-container');
if (previewContainer) {
const scrollTop = previewContainer.scrollTop;
const containerHeight = previewContainer.offsetHeight;
const scrollableHeight = previewContainer.scrollHeight - containerHeight;
const scrollProgress = scrollableHeight > 0 ? scrollTop / scrollableHeight : 0;
const parallaxOffset = (scrollProgress * state.intensity * 100);
const yPosition = 50 - parallaxOffset;
bgElement.style.backgroundPosition = \`center \${yPosition}%\`;
} else {
const rect = bgElement.getBoundingClientRect();
const viewportHeight = window.innerHeight;
const elementTop = rect.top;
const elementBottom = rect.bottom;
if (elementBottom >= 0 && elementTop <= viewportHeight) {
const scrollPosition = window.pageYOffset;
const elementOffsetTop = rect.top + scrollPosition;
const viewportCenter = viewportHeight / 2;
const elementCenter = elementOffsetTop + (rect.height / 2);
const distanceFromCenter = (elementCenter - (scrollPosition + viewportCenter)) / viewportHeight;
const parallaxOffset = distanceFromCenter * state.intensity * 100;
const yPosition = 50 + parallaxOffset;
bgElement.style.backgroundPosition = \`center \${yPosition}%\`;
}
}
}
function applyFilters(bgElement, config) {
const filters = [];
if (config.brightness !== 100) {
filters.push(\`brightness(\${config.brightness / 100})\`);
}
if (config.contrast !== 100) {
filters.push(\`contrast(\${config.contrast / 100})\`);
}
if (config.saturation !== 100) {
filters.push(\`saturate(\${config.saturation / 100})\`);
}
if (config.blur > 0) {
filters.push(\`blur(\${config.blur}px)\`);
}
if (config.sepia > 0) {
filters.push(\`sepia(\${config.sepia / 100})\`);
}
if (config.grayscale > 0) {
filters.push(\`grayscale(\${config.grayscale / 100})\`);
}
bgElement.style.filter = filters.join(' ');
}
function throttledParallax(bgElement, state) {
if (state.rafId === null) {
state.rafId = requestAnimationFrame(() => {
applyParallax(bgElement, state);
state.rafId = null;
});
}
}
function loadBackgroundImage(bgElement, state) {
const img = new Image();
img.onload = () => {
state.imageRatio = img.width / img.height;
adjustBackgroundSize(bgElement, state);
applyParallax(bgElement, state);
applyFilters(bgElement, state.config);
};
img.onerror = (e) => {
bgElement.style.backgroundColor = '#ccc';
};
const imageUrl = bgElement.style.backgroundImage.replace(/^url\\(['"]?(.+?)['"]?\\)$/, '$1');
img.src = imageUrl;
}
function setupParallaxElement(element) {
const customConfig = {
intensity: defaultConfig.intensity,
zoomFactor: defaultConfig.zoomFactor,
brightness: defaultConfig.brightness,
contrast: defaultConfig.contrast,
saturation: defaultConfig.saturation,
blur: defaultConfig.blur,
sepia: defaultConfig.sepia,
grayscale: defaultConfig.grayscale
};
const state = {
intensity: getParallaxIntensity(),
rafId: null,
imageRatio: 1,
isMobile: window.matchMedia("(max-width: 767px)").matches,
config: customConfig
};
const bgElement = document.createElement('div');
bgElement.className = 'parallax-bg';
Object.assign(bgElement.style, {
position: 'absolute',
top: '0',
left: '0',
width: '100%',
height: '100%',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover',
transition: 'filter ' + defaultConfig.transitionDuration + 's ease-in-out'
});
const contentContainer = document.createElement('div');
contentContainer.className = 'parallax-content';
contentContainer.style.position = 'relative';
contentContainer.style.zIndex = '1';
while (element.firstChild) {
contentContainer.appendChild(element.firstChild);
}
element.appendChild(bgElement);
element.appendChild(contentContainer);
const imageUrl = defaultConfig.imageUrl;
if (imageUrl) {
bgElement.style.backgroundImage = 'url(\\'' + imageUrl + '\\')';
loadBackgroundImage(bgElement, state);
}
const scrollContainer = element.closest('.preview-container') || window;
const isPreview = scrollContainer !== window;
scrollContainer.addEventListener('scroll', () => throttledParallax(bgElement, state), { passive: true });
window.addEventListener('resize', () => {
state.intensity = getParallaxIntensity();
state.isMobile = window.matchMedia("(max-width: 767px)").matches;
adjustBackgroundSize(bgElement, state);
throttledParallax(bgElement, state);
}, { passive: true });
}
function initParallaxEffect() {
const parallaxElements = document.querySelectorAll('[' + ATTR_NAME + ']');
parallaxElements.forEach(setupParallaxElement);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initParallaxEffect);
} else {
initParallaxEffect();
}
window.addEventListener('load', initParallaxEffect);
})();`;
}
function copyJsToClipboard() {
const jsCode = generateJavaScriptCode();
navigator.clipboard.writeText(jsCode)
.then(() => {
showNotification('JavaScript code copied to clipboard!');
})
.catch(err => {
try {
const textArea = document.createElement('textarea');
textArea.value = jsCode;
textArea.style.position = 'fixed';
textArea.style.opacity = '0';
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
showNotification('JavaScript code copied to clipboard!');
} catch (fallbackErr) {
showNotification('Failed to copy to clipboard. Please try again.', 'error');
}
});
}
function copyFullSectionToClipboard() {
const sectionJSON = generateFullSectionJSON();
if (!sectionJSON) {
showNotification('Full section feature coming soon!', 'warning');
return;
}
navigator.clipboard.writeText(sectionJSON)
.then(() => {
showNotification('Full section JSON copied to clipboard!');
})
.catch(err => {
try {
const textArea = document.createElement('textarea');
textArea.value = sectionJSON;
textArea.style.position = 'fixed';
textArea.style.opacity = '0';
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
showNotification('Full section JSON copied to clipboard!');
} catch (fallbackErr) {
showNotification('Failed to copy to clipboard. Please try again.', 'error');
}
});
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text)
.then(() => {
showNotification('Copied to clipboard!');
})
.catch(err => {
showNotification('Failed to copy to clipboard', 'error');
});
}
function createParallaxEffect(element) {
const existingBg = element.querySelector('.parallax-bg');
if (existingBg) existingBg.remove();
const existingContent = element.querySelector('.parallax-content');
if (existingContent) {
while (existingContent.firstChild) {
element.appendChild(existingContent.firstChild);
}
existingContent.remove();
}
const imageUrl = parallaxConfig.imageUrl;
const intensity = parallaxConfig.intensity;
const zoomFactor = parallaxConfig.zoomFactor;
const transitionDuration = parallaxConfig.transitionDuration + 's';
const brightness = parallaxConfig.brightness;
const contrast = parallaxConfig.contrast;
const saturation = parallaxConfig.saturation;
const blur = parallaxConfig.blur;
const sepia = parallaxConfig.sepia;
const grayscale = parallaxConfig.grayscale;
const styles = getComputedStyle(element);
if (styles.position === 'static') {
element.style.position = 'relative';
}
const bgElement = document.createElement('div');
bgElement.className = 'parallax-bg';
Object.assign(bgElement.style, {
position: 'absolute',
top: '0',
left: '0',
width: '100%',
height: '100%',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover',
backgroundImage: `url('${imageUrl}')`,
willChange: 'transform',
WebkitBackfaceVisibility: 'hidden',
backfaceVisibility: 'hidden',
transform: 'translateZ(0)',
transition: `filter ${transitionDuration} ease-in-out, background-size ${transitionDuration} ease-out`
});
const contentContainer = document.createElement('div');
contentContainer.className = 'parallax-content';
contentContainer.style.position = 'relative';
contentContainer.style.zIndex = '1';
contentContainer.style.width = '100%';
while (element.firstChild) {
contentContainer.appendChild(element.firstChild);
}
element.appendChild(bgElement);
element.appendChild(contentContainer);
previewState.bgElement = bgElement;
previewState.container = element;
previewState.currentImageUrl = imageUrl;
const img = new Image();
img.onload = () => {
const imageRatio = img.width / img.height;
const isMobile = window.matchMedia("(max-width: 767px)").matches;
adjustBackgroundSize(bgElement, element, imageRatio, zoomFactor, isMobile);
applyParallax(bgElement, element, intensity, isMobile);
applyFilters(bgElement, brightness, contrast, saturation, blur, sepia, grayscale);
};
img.src = imageUrl;
let rafId = null;
function throttledParallax() {
if (rafId === null) {
rafId = requestAnimationFrame(() => {
const img = new Image();
img.onload = () => {
const imageRatio = img.width / img.height;
const isMobile = window.matchMedia("(max-width: 767px)").matches;
applyParallax(bgElement, element, intensity, isMobile);
};
img.src = imageUrl;
rafId = null;
});
}
}
function handleResize() {
const img = new Image();
img.onload = () => {
const imageRatio = img.width / img.height;
const isMobile = window.matchMedia("(max-width: 767px)").matches;
adjustBackgroundSize(bgElement, element, imageRatio, zoomFactor, isMobile);
throttledParallax();
};
img.src = imageUrl;
}
const scrollContainer = element.closest('.preview-container') || window;
const isPreview = scrollContainer !== window;
scrollContainer.addEventListener('scroll', throttledParallax, { passive: true });
window.addEventListener('resize', handleResize, { passive: true });
return {
cleanup: () => {
if (isPreview) {
scrollContainer.removeEventListener('scroll', throttledParallax);
} else {
window.removeEventListener('scroll', throttledParallax);
}
window.removeEventListener('resize', handleResize);
if (rafId) {
cancelAnimationFrame(rafId);
}
previewState.bgElement = null;
previewState.container = null;
previewState.currentImageUrl = null;
}
};
}
function adjustBackgroundSize(bgElement, container, imageRatio, zoomFactor, isMobile) {
const containerWidth = container.offsetWidth;
const containerHeight = container.offsetHeight;
const mobileZoom = isMobile ? 2.5 : zoomFactor;
const minHeight = containerHeight * mobileZoom;
if (imageRatio > 1) {
const width = minHeight * imageRatio;
const finalWidth = Math.max(width, containerWidth * 1.6);
bgElement.style.backgroundSize = `${Math.ceil(finalWidth)}px ${Math.ceil(minHeight)}px`;
} else {
const minWidth = containerWidth * (isMobile ? 1 : 1.6);
const height = minWidth / imageRatio;
const finalHeight = Math.max(height, minHeight);
bgElement.style.backgroundSize = `${Math.ceil(minWidth)}px ${Math.ceil(finalHeight)}px`;
}
}
function applyParallax(bgElement, container, intensity, isMobile) {
const previewContainer = container.closest('.preview-container');
if (previewContainer) {
const scrollTop = previewContainer.scrollTop;
const containerHeight = previewContainer.offsetHeight;
const scrollableHeight = previewContainer.scrollHeight - containerHeight;
const scrollProgress = scrollableHeight > 0 ? scrollTop / scrollableHeight : 0;
const parallaxOffset = (scrollProgress * intensity * 100);
const yPosition = 50 - parallaxOffset;
bgElement.style.backgroundPosition = `center ${yPosition}%`;
} else {
const rect = container.getBoundingClientRect();
const viewportHeight = window.innerHeight;
const elementTop = rect.top;
const elementBottom = rect.bottom;
if (elementBottom >= 0 && elementTop <= viewportHeight) {
const scrollPosition = window.pageYOffset;
const elementOffsetTop = rect.top + scrollPosition;
const viewportCenter = viewportHeight / 2;
const elementCenter = elementOffsetTop + (rect.height / 2);
const distanceFromCenter = (elementCenter - (scrollPosition + viewportCenter)) / viewportHeight;
const parallaxOffset = distanceFromCenter * intensity * 100;
const yPosition = 50 + parallaxOffset;
bgElement.style.backgroundPosition = `center ${yPosition}%`;
}
}
}
function applyFilters(bgElement, brightness, contrast, saturation, blur, sepia, grayscale) {
const filters = [];
if (brightness !== 100) {
filters.push(`brightness(${brightness / 100})`);
}
if (contrast !== 100) {
filters.push(`contrast(${contrast / 100})`);
}
if (saturation !== 100) {
filters.push(`saturate(${saturation / 100})`);
}
if (blur > 0) {
filters.push(`blur(${blur}px)`);
}
if (sepia > 0) {
filters.push(`sepia(${sepia / 100})`);
}
if (grayscale > 0) {
filters.push(`grayscale(${grayscale / 100})`);
}
bgElement.style.filter = filters.join(' ');
}
function updateContainerAttributes(container) {
container.setAttribute('data-vertical-parallax-image', parallaxConfig.imageUrl);
container.setAttribute('data-vertical-parallax-intensity', parallaxConfig.intensity);
container.setAttribute('data-vertical-parallax-zoom', parallaxConfig.zoomFactor);
container.setAttribute('data-vertical-parallax-transition', parallaxConfig.transitionDuration + 's');
container.setAttribute('data-vertical-parallax-brightness', parallaxConfig.brightness);
container.setAttribute('data-vertical-parallax-contrast', parallaxConfig.contrast);
container.setAttribute('data-vertical-parallax-saturation', parallaxConfig.saturation);
container.setAttribute('data-vertical-parallax-blur', parallaxConfig.blur);
container.setAttribute('data-vertical-parallax-sepia', parallaxConfig.sepia);
container.setAttribute('data-vertical-parallax-grayscale', parallaxConfig.grayscale);
}
function updatePreview() {
parallaxConfig.intensity = parseFloat(document.getElementById('parallax-intensity').value);
parallaxConfig.zoomFactor = parseFloat(document.getElementById('zoom-factor').value);
parallaxConfig.transitionDuration = parseFloat(document.getElementById('transition-duration').value);
parallaxConfig.brightness = parseInt(document.getElementById('brightness').value);
parallaxConfig.contrast = parseInt(document.getElementById('contrast').value);
parallaxConfig.saturation = parseInt(document.getElementById('saturation').value);
parallaxConfig.blur = parseFloat(document.getElementById('blur').value);
parallaxConfig.sepia = parseInt(document.getElementById('sepia').value);
parallaxConfig.grayscale = parseInt(document.getElementById('grayscale').value);
const container = document.getElementById('parallax-preview');
updateContainerAttributes(container);
if (previewState.bgElement && previewState.currentImageUrl === parallaxConfig.imageUrl) {
updatePreviewParameters();
} else {
if (previewParallaxEffect && typeof previewParallaxEffect.cleanup === 'function') {
previewParallaxEffect.cleanup();
}
previewParallaxEffect = createParallaxEffect(container);
}
}
function updatePreviewParameters() {
if (!previewState.bgElement || !previewState.container) return;
const isMobile = window.matchMedia("(max-width: 767px)").matches;
previewState.bgElement.style.transition = `filter ${parallaxConfig.transitionDuration}s ease-in-out, background-size ${parallaxConfig.transitionDuration}s ease-out`;
applyFilters(previewState.bgElement, parallaxConfig.brightness, parallaxConfig.contrast, parallaxConfig.saturation, parallaxConfig.blur, parallaxConfig.sepia, parallaxConfig.grayscale);
const img = new Image();
img.onload = () => {
const imageRatio = img.width / img.height;
adjustBackgroundSize(previewState.bgElement, previewState.container, imageRatio, parallaxConfig.zoomFactor, isMobile);
applyParallax(previewState.bgElement, previewState.container, parallaxConfig.intensity, isMobile);
};
img.src = parallaxConfig.imageUrl;
}
function updateImagePreview() {
const imagePreview = document.getElementById('image-preview');
if (parallaxConfig.imageUrl) {
imagePreview.style.backgroundImage = `url('${parallaxConfig.imageUrl}')`;
imagePreview.classList.add('has-image');
imagePreview.innerHTML = '';
} else {
imagePreview.style.backgroundImage = '';
imagePreview.classList.remove('has-image');
imagePreview.innerHTML = '<span>Enter image URL below or click a sample</span>';
}
}
function initializePreview() {
const container = document.getElementById('parallax-preview');
if (!container.id) {
container.id = 'parallax-preview';
}
updateContainerAttributes(container);
previewParallaxEffect = createParallaxEffect(container);
updatePreview();
}
window.resetParameter = function(parameterId, defaultValue) {
const element = document.getElementById(parameterId);
if (element) {
element.value = defaultValue;
const valueElement = document.getElementById(`${parameterId}-value`) ||
document.getElementById(parameterId.replace('-', '') + '-value');
if (valueElement) {
valueElement.textContent = defaultValue;
}
switch (parameterId) {
case 'parallax-intensity':
parallaxConfig.intensity = defaultValue;
break;
case 'zoom-factor':
parallaxConfig.zoomFactor = defaultValue;
break;
case 'transition-duration':
parallaxConfig.transitionDuration = defaultValue;
break;
case 'brightness':
parallaxConfig.brightness = defaultValue;
break;
case 'contrast':
parallaxConfig.contrast = defaultValue;
break;
case 'saturation':
parallaxConfig.saturation = defaultValue;
break;
case 'blur':
parallaxConfig.blur = defaultValue;
break;
case 'sepia':
parallaxConfig.sepia = defaultValue;
break;
case 'grayscale':
parallaxConfig.grayscale = defaultValue;
break;
}
debouncedUpdatePreview();
showNotification(`${parameterId.replace(/-/g, ' ')} reset to default`);
}
};
function initializeUI() {
initializePreview();
updateImagePreview();
const instructionsToggle = document.getElementById('instructions-toggle');
const instructionsContent = document.getElementById('instructions-content');
const instructionsCard = document.getElementById('instructions-card');
const toggleIcon = instructionsToggle.querySelector('.toggle-icon');
instructionsToggle.addEventListener('click', () => {
const isVisible = instructionsContent.classList.contains('show');
if (isVisible) {
instructionsContent.classList.remove('show');
instructionsCard.classList.remove('expanded');
toggleIcon.classList.remove('expanded');
} else {
instructionsContent.classList.add('show');
instructionsCard.classList.add('expanded');
toggleIcon.classList.add('expanded');
}
});
document.getElementById('quick-attribute').addEventListener('click', () => {
copyToClipboard('data-vertical-parallax');
});
document.getElementById('download-config').addEventListener('click', () => {
copyJsToClipboard();
});
document.getElementById('copy-full-section').addEventListener('click', () => {
copyFullSectionToClipboard();
});
const imageUrlInput = document.getElementById('image-url');
imageUrlInput.addEventListener('input', function() {
parallaxConfig.imageUrl = this.value;
updateImagePreview();
debouncedUpdatePreview();
});
const sampleImages = document.querySelectorAll('.sample-image');
sampleImages.forEach(img => {
img.addEventListener('click', function() {
const url = this.getAttribute('data-url');
document.getElementById('image-url').value = url;
parallaxConfig.imageUrl = url;
updateImagePreview();
debouncedUpdatePreview();
sampleImages.forEach(i => i.classList.remove('active'));
this.classList.add('active');
});
});
if (sampleImages.length > 0) {
sampleImages[0].classList.add('active');
}
document.getElementById('reset-image').addEventListener('click', () => {
parallaxConfig.imageUrl = defaultConfig.imageUrl;
document.getElementById('image-url').value = defaultConfig.imageUrl;
updateImagePreview();
debouncedUpdatePreview();
showNotification('Image settings reset to default');
});
document.getElementById('reset-animation').addEventListener('click', () => {
parallaxConfig.intensity = defaultConfig.intensity;
parallaxConfig.zoomFactor = defaultConfig.zoomFactor;
parallaxConfig.transitionDuration = defaultConfig.transitionDuration;
document.getElementById('parallax-intensity').value = defaultConfig.intensity;
document.getElementById('zoom-factor').value = defaultConfig.zoomFactor;
document.getElementById('transition-duration').value = defaultConfig.transitionDuration;
document.getElementById('intensity-value').textContent = defaultConfig.intensity;
document.getElementById('zoom-value').textContent = defaultConfig.zoomFactor;
document.getElementById('transition-value').textContent = defaultConfig.transitionDuration;
debouncedUpdatePreview();
showNotification('Animation settings reset');
});
document.getElementById('reset-advanced').addEventListener('click', () => {
parallaxConfig.brightness = defaultConfig.brightness;
parallaxConfig.contrast = defaultConfig.contrast;
parallaxConfig.saturation = defaultConfig.saturation;
parallaxConfig.blur = defaultConfig.blur;
parallaxConfig.sepia = defaultConfig.sepia;
parallaxConfig.grayscale = defaultConfig.grayscale;
document.getElementById('brightness').value = defaultConfig.brightness;
document.getElementById('contrast').value = defaultConfig.contrast;
document.getElementById('saturation').value = defaultConfig.saturation;
document.getElementById('blur').value = defaultConfig.blur;
document.getElementById('sepia').value = defaultConfig.sepia;
document.getElementById('grayscale').value = defaultConfig.grayscale;
document.getElementById('brightness-value').textContent = defaultConfig.brightness;
document.getElementById('contrast-value').textContent = defaultConfig.contrast;
document.getElementById('saturation-value').textContent = defaultConfig.saturation;
document.getElementById('blur-value').textContent = defaultConfig.blur;
document.getElementById('sepia-value').textContent = defaultConfig.sepia;
document.getElementById('grayscale-value').textContent = defaultConfig.grayscale;
debouncedUpdatePreview();
showNotification('Advanced settings reset');
});
const rangeInputs = document.querySelectorAll('input[type="range"]');
rangeInputs.forEach(input => {
const valueElement = document.getElementById(`${input.id}-value`) ||
document.getElementById(input.id.replace('-', '') + '-value');
if (valueElement) {
valueElement.textContent = input.value;
}
input.addEventListener('input', () => {
if (valueElement) {
valueElement.textContent = input.value;
}
switch (input.id) {
case 'parallax-intensity':
parallaxConfig.intensity = parseFloat(input.value);
break;
case 'zoom-factor':
parallaxConfig.zoomFactor = parseFloat(input.value);
break;
case 'transition-duration':
parallaxConfig.transitionDuration = parseFloat(input.value);
break;
case 'brightness':
parallaxConfig.brightness = parseInt(input.value);
break;
case 'contrast':
parallaxConfig.contrast = parseInt(input.value);
break;
case 'saturation':
parallaxConfig.saturation = parseInt(input.value);
break;
case 'blur':
parallaxConfig.blur = parseFloat(input.value);
break;
case 'sepia':
parallaxConfig.sepia = parseInt(input.value);
break;
case 'grayscale':
parallaxConfig.grayscale = parseInt(input.value);
break;
}
debouncedUpdatePreview();
});
});
document.addEventListener('keydown', (e) => {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
return;
}
if (e.ctrlKey || e.metaKey) {
switch (e.key.toLowerCase()) {
case 'd':
e.preventDefault();
const downloadBtn = document.getElementById('download-config');
if (downloadBtn && downloadBtn.hasAttribute('data-protection-animation')) {
downloadBtn.click();
} else {
copyJsToClipboard();
}
break;
case 's':
e.preventDefault();
const fullSectionBtn = document.getElementById('copy-full-section');
if (fullSectionBtn && fullSectionBtn.hasAttribute('data-protection-animation')) {
fullSectionBtn.click();
} else {
copyFullSectionToClipboard();
}
break;
}
}
});
function saveConfiguration() {
try {
localStorage.setItem('bricksfusion-parallax-config', JSON.stringify(parallaxConfig));
} catch (e) {
}
}
function loadConfiguration() {
try {
const saved = localStorage.getItem('bricksfusion-parallax-config');
if (saved) {
const savedConfig = JSON.parse(saved);
Object.assign(parallaxConfig, savedConfig);
document.getElementById('image-url').value = savedConfig.imageUrl;
document.getElementById('parallax-intensity').value = savedConfig.intensity;
document.getElementById('zoom-factor').value = savedConfig.zoomFactor;
document.getElementById('transition-duration').value = savedConfig.transitionDuration;
document.getElementById('brightness').value = savedConfig.brightness;
document.getElementById('contrast').value = savedConfig.contrast;
document.getElementById('saturation').value = savedConfig.saturation;
document.getElementById('blur').value = savedConfig.blur;
document.getElementById('sepia').value = savedConfig.sepia;
document.getElementById('grayscale').value = savedConfig.grayscale;
document.getElementById('intensity-value').textContent = savedConfig.intensity;
document.getElementById('zoom-value').textContent = savedConfig.zoomFactor;
document.getElementById('transition-value').textContent = savedConfig.transitionDuration;
document.getElementById('brightness-value').textContent = savedConfig.brightness;
document.getElementById('contrast-value').textContent = savedConfig.contrast;
document.getElementById('saturation-value').textContent = savedConfig.saturation;
document.getElementById('blur-value').textContent = savedConfig.blur;
document.getElementById('sepia-value').textContent = savedConfig.sepia;
document.getElementById('grayscale-value').textContent = savedConfig.grayscale;
updateImagePreview();
debouncedUpdatePreview();
}
} catch (e) {
}
}
const originalUpdatePreview = debouncedUpdatePreview;
debouncedUpdatePreview = function() {
originalUpdatePreview();
saveConfiguration();
};
loadConfiguration();
setTimeout(() => {
showNotification('BricksFusion Vertical Parallax Configurator loaded!');
}, 500);
}
initializeUI();
});
</script>
</body>
</html>
Vertical Parallax
Creates smooth vertical parallax scrolling effect on background images. Image shifts up and down based on scroll position for depth perception. Features adjustable intensity with responsive scaling, zoom control, and comprehensive image filters including sepia and grayscale. Uses CSS transforms with requestAnimationFrame for 60fps performance. Perfect for hero sections, feature blocks, or adding dynamic visual depth.
Vertical Parallax
Scroll the page to see the vertical parallax effect.
Vertical Parallax
The background moves as you scroll
↕ Scroll to see the effect ↕
Image
Background image for parallax effect. Automatically sized and positioned for optimal display.
Required
Initial zoom level of background image. Higher values create closer crop with more vertical parallax range.
Default: 1.6
Parallax Effect
Strength of vertical movement. Higher creates more dramatic shift as page scrolls. Automatically adjusts for mobile devices.
Default: 0.25
Duration of smooth transitions for filters and size changes. Standard CSS time values.
Default: 0.3s
Image Filters
Image brightness level. 100 is normal, lower is darker, higher is brighter.
Default: 100
Image contrast level. 100 is normal, lower is flatter, higher is more dramatic.
Default: 100
Color saturation level. 0 is grayscale, 100 is normal, higher is more vibrant.
Default: 100
Gaussian blur intensity. Creates soft focus or depth-of-field effect.
Default: 0
Sepia tone intensity. Creates vintage, warm brown tinted effect. 0 is no effect, 100 is full sepia.
Default: 0
Grayscale intensity. Removes color from image. 0 is full color, 100 is complete black and white.
Default: 0
Performance
This element uses CSS transforms with background-position for vertical parallax effect. Calculates vertical offset based on scroll position using requestAnimationFrame with throttling. Features passive scroll listeners and hardware-accelerated transforms with backface-visibility optimization. Automatically scales intensity for mobile devices (70% on phones, 80% on tablets, 90% on small laptops). Very lightweight - suitable for all devices and multiple instances per page with smooth 60fps performance.