v1.0.1
MENU ANIMATIONS
ADVANCED EFFECTS
CORE BACKGROUND
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>Page Transition 002 Configurator - BricksFusion</title>
<style>
:root {
--background: #000;
--card-bg: #1e1e1e;
--card-bg-hover: #252525;
--text-primary: #f2f2f7;
--text-secondary: #8e8e93;
--accent: #b4ff99;
--accent-hover: #a1e588;
--border: #2c2c2e;
--shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
--track: #2c2c2e;
--thumb: #b4ff99;
--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(180, 255, 153, 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), #a1e588);
border-color: var(--accent);
color: #000;
font-weight: 600;
}
.action-btn.primary:hover {
background: linear-gradient(90deg, var(--accent-hover), #90d477);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(180, 255, 153, 0.3);
}
.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), #a1e588);
-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: #b4ff99;
}
.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: hidden;
border-radius: var(--card-radius);
background-color: #000000;
border: 1px solid var(--border);
box-shadow: var(--shadow);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.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;
}
.preview-controls {
position: absolute;
top: 1rem;
right: 1rem;
display: flex;
gap: 0.5rem;
z-index: 10;
}
.preview-btn {
padding: 0.5rem;
background-color: rgba(0, 0, 0, 0.7);
color: white;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 6px;
cursor: pointer;
transition: var(--transition);
font-size: var(--text-xs);
backdrop-filter: blur(5px);
}
.preview-btn:hover {
background-color: var(--accent);
border-color: var(--accent);
color: #000;
}
.preview-btn svg {
width: 18px;
height: 18px;
stroke: currentColor;
}
.background-selector-wrapper {
position: relative;
display: inline-block;
}
.background-selector-btn {
position: relative;
}
.background-selector-btn:hover {
background-color: rgba(180, 255, 153, 0.2);
border-color: var(--accent);
box-shadow: 0 0 8px rgba(180, 255, 153, 0.3);
}
.hidden-color-input {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
z-index: 1;
}
.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(180, 255, 153, 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(180, 255, 153, 0.5);
}
.color-list {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 1.5rem;
}
.color-row {
display: flex;
align-items: center;
gap: 1.25rem;
padding: 1rem 1.25rem;
background-color: rgba(30, 30, 30, 0.7);
border: 1px solid var(--border);
border-radius: var(--input-radius);
transition: var(--transition);
}
.color-row:hover {
border-color: var(--accent);
box-shadow: 0 0 0 1px rgba(180, 255, 153, 0.1);
}
.color-picker-container {
position: relative;
width: 40px;
height: 40px;
border-radius: 8px;
overflow: hidden;
border: 2px solid var(--border);
cursor: pointer;
transition: var(--transition);
flex-shrink: 0;
background: var(--card-bg);
display: flex;
align-items: center;
justify-content: center;
--selected-color: #000000;
}
.color-picker-container:hover {
border-color: var(--accent);
transform: scale(1.05);
box-shadow: 0 0 12px rgba(180, 255, 153, 0.3);
}
.color-picker-container::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--selected-color, #000000);
border-radius: 6px;
transition: var(--transition);
}
input[type="color"] {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
cursor: pointer;
background: transparent;
opacity: 0;
z-index: 2;
}
.color-input-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.color-label {
font-size: 10px;
font-weight: 500;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-left: 0.25rem;
}
.color-input {
padding: 0.5rem 0.75rem;
background-color: rgba(0, 0, 0, 0.3);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-primary);
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
font-size: 12px;
transition: var(--transition);
min-width: 0;
}
.color-input:focus {
border-color: var(--accent);
box-shadow: 0 0 0 1px rgba(180, 255, 153, 0.2);
outline: none;
}
.color-input.invalid {
border-color: var(--danger);
box-shadow: 0 0 0 1px rgba(220, 53, 69, 0.2);
}
.hex-input,
.hsl-input {
width: 100%;
}
.color-input-group:nth-child(2) {
flex: 0.3;
}
.color-input-group:nth-child(3) {
flex: 0.7;
}
.toggle-switch {
position: relative;
display: inline-block;
width: 60px;
height: 32px;
}
.toggle-switch input {
opacity: 0;
width: 0;
height: 0;
}
.toggle-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--track);
transition: var(--transition);
border-radius: 32px;
border: 1px solid var(--border);
}
.toggle-slider:before {
position: absolute;
content: "";
height: 24px;
width: 24px;
left: 3px;
bottom: 3px;
background-color: var(--text-secondary);
transition: var(--transition);
border-radius: 50%;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.toggle-switch input:checked + .toggle-slider {
background-color: var(--accent);
border-color: var(--accent);
}
.toggle-switch input:checked + .toggle-slider:before {
transform: translateX(28px);
background-color: #000;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.toggle-switch:hover .toggle-slider {
box-shadow: 0 0 8px rgba(180, 255, 153, 0.3);
}
.toggle-control-group {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
}
.toggle-control-group:last-child {
margin-bottom: 0;
}
.toggle-label-content {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.toggle-description {
font-size: calc(var(--text-xs) * 0.9);
color: var(--text-secondary);
line-height: 1.4;
}
.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;
}
.PageTransition002-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
visibility: hidden;
opacity: 0;
transition: opacity 0.3s ease-in-out;
contain: strict;
isolation: isolate;
}
.PageTransition002-container.PageTransition002-active {
visibility: visible;
opacity: 1;
}
.PageTransition002-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000;
z-index: 1;
}
.PageTransition002-counter {
font-size: 8vw;
font-weight: normal;
color: #fff;
z-index: 3;
opacity: 0;
transition: opacity 0.5s ease-in-out;
}
.PageTransition002-counter.PageTransition002-visible {
opacity: 1;
}
.PageTransition002-new-page {
position: absolute;
top: -100%;
left: 15%;
width: 70%;
height: 70%;
opacity: 0;
transform: scale(0.9);
transition: all 0.8s cubic-bezier(0.25, 0.1, 0.25, 1);
z-index: 2;
overflow: hidden;
border-radius: 8px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
background-color: #252525;
}
.PageTransition002-new-page.PageTransition002-drop {
top: 15%;
opacity: 1;
}
.PageTransition002-new-page.PageTransition002-expand {
top: 0;
left: 0;
width: 100%;
height: 100%;
transform: scale(1);
border-radius: 0;
}
.preview-page-content {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: var(--text-s);
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
@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;
}
.color-row {
flex-direction: column;
align-items: stretch;
gap: 1rem;
padding: 1rem;
}
.color-picker-container {
align-self: center;
margin-bottom: 0.5rem;
}
.color-input-group {
align-items: stretch;
}
.hex-input,
.hsl-input {
width: 100%;
}
.preview-container {
height: 300px;
}
.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/transition-pages/" class="breadcrumb-item">Transition Pages</a>
<span class="breadcrumb-separator">›</span>
<span class="breadcrumb-item active">Page Transition 002</span>
</nav>
<div class="action-buttons">
<button class="action-btn primary" id="download-config" title="Copy JavaScript code (Ctrl+D)" data-protection-animation="true">
<span>⬇</span>
Copy JS
</button>
</div>
</div>
<div class="container">
<div class="page-header">
<h1 class="page-title">Page Transition 002</h1>
<p class="page-subtitle">Interactive page transitions 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 page transition effect using the controls below</li>
<li>Click <strong>Copy JS</strong> to copy the JavaScript code to clipboard</li>
<li>Go to your <strong>Template</strong> (Header/Footer) that appears on all pages</li>
<li>Click <strong>Manage</strong> → <strong>Page Settings</strong> → <strong>Custom Code</strong></li>
<li>Paste the code in <strong>Body (Footer) Scripts</strong> section</li>
<li>The cinematic page transition effect will now appear automatically when visitors navigate between pages on your website</li>
</ol>
</div>
</div>
</div>
</div>
</div>
<div class="content">
<section class="preview-section">
<div class="preview-container" id="transition-preview">
<div class="preview-content">Click here to test the transition effect</div>
<div class="preview-controls">
<button class="preview-btn" id="randomize-transition" title="Randomize (R)">🎲</button>
<div class="background-selector-wrapper">
<button class="preview-btn background-selector-btn" id="background-selector">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="12,2 2,7 12,12 22,7"/>
<polyline points="2,17 12,22 22,17"/>
<polyline points="2,12 12,17 22,12"/>
</svg>
</button>
<input type="color" id="preview-background-picker" class="hidden-color-input" value="#000000" title="Change Preview Background (B)">
</div>
</div>
<div class="PageTransition002-container" id="previewTransitionContainer">
<div class="PageTransition002-background" id="previewBackground"></div>
<div class="PageTransition002-counter" id="previewCounter">0</div>
<div class="PageTransition002-new-page" id="previewNewPage">
<div class="preview-page-content">Page Preview</div>
</div>
</div>
</div>
</section>
<section class="controls-section">
<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="toggle-control-group">
<div class="toggle-label-content">
<span class="label-text">Enable Counter Animation</span>
<span class="toggle-description">Show number progression before page transition</span>
</div>
<label class="toggle-switch">
<input type="checkbox" id="enable-counter" checked>
<span class="toggle-slider"></span>
</label>
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Counter Speed
<span class="help-tooltip" title="Speed of counter animation">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="counter-speed-value">10</span>ms</span>
<button class="reset-btn" onclick="resetParameter('counter-speed', 10)">↺</button>
</div>
</div>
<input type="range" id="counter-speed" min="5" max="30" step="1" value="10">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Counter Font Size
<span class="help-tooltip" title="Size of the counter text">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="counter-font-size-value">8</span>vw</span>
<button class="reset-btn" onclick="resetParameter('counter-font-size', 8)">↺</button>
</div>
</div>
<input type="range" id="counter-font-size" min="4" max="12" step="0.5" value="8">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Drop Animation Duration
<span class="help-tooltip" title="Duration of the page drop animation">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="drop-duration-value">0.8</span>s</span>
<button class="reset-btn" onclick="resetParameter('drop-duration', 0.8)">↺</button>
</div>
</div>
<input type="range" id="drop-duration" min="0.3" max="1.5" step="0.1" value="0.8">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Expand Animation Duration
<span class="help-tooltip" title="Duration of the page expand animation">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="expand-duration-value">0.8</span>s</span>
<button class="reset-btn" onclick="resetParameter('expand-duration', 0.8)">↺</button>
</div>
</div>
<input type="range" id="expand-duration" min="0.3" max="1.5" step="0.1" value="0.8">
</div>
</div>
</div>
<div class="card">
<div class="card-heading">
Page Window Settings
<div class="card-actions">
<button class="card-action-btn" id="reset-window" title="Reset Window Settings">↺</button>
</div>
</div>
<div class="card-content">
<div class="control-group">
<div class="control-label">
<span class="label-text">
Page Window Width
<span class="help-tooltip" title="Width of the preview page window">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="window-width-value">70</span>%</span>
<button class="reset-btn" onclick="resetParameter('window-width', 70)">↺</button>
</div>
</div>
<input type="range" id="window-width" min="50" max="90" step="5" value="70">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Page Window Height
<span class="help-tooltip" title="Height of the preview page window">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="window-height-value">70</span>%</span>
<button class="reset-btn" onclick="resetParameter('window-height', 70)">↺</button>
</div>
</div>
<input type="range" id="window-height" min="50" max="90" step="5" value="70">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Window Left Position
<span class="help-tooltip" title="Horizontal position of the page window">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="window-left-value">15</span>%</span>
<button class="reset-btn" onclick="resetParameter('window-left', 15)">↺</button>
</div>
</div>
<input type="range" id="window-left" min="5" max="25" step="1" value="15">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Window Top Position
<span class="help-tooltip" title="Vertical position of the page window">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="window-top-value">15</span>%</span>
<button class="reset-btn" onclick="resetParameter('window-top', 15)">↺</button>
</div>
</div>
<input type="range" id="window-top" min="5" max="25" step="1" value="15">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Initial Scale
<span class="help-tooltip" title="Initial scale of the page window">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="initial-scale-value">0.9</span></span>
<button class="reset-btn" onclick="resetParameter('initial-scale', 0.9)">↺</button>
</div>
</div>
<input type="range" id="initial-scale" min="0.7" max="1.0" step="0.05" value="0.9">
</div>
</div>
</div>
<div class="card">
<div class="card-heading">
Color Settings
<div class="card-actions">
<button class="card-action-btn" id="reset-colors" title="Reset Color Settings">↺</button>
</div>
</div>
<div class="card-content">
<div class="control-group">
<div class="control-label">
<span class="label-text">Background Color</span>
</div>
<div class="color-list">
<div class="color-row">
<div class="color-picker-container" style="--selected-color: #000000;">
<input type="color" id="bg-color" value="#000000">
</div>
<div class="color-input-group">
<span class="color-label">HEX</span>
<input type="text" class="color-input hex-input" id="bg-color-hex" value="#000000" placeholder="#000000">
</div>
<div class="color-input-group">
<span class="color-label">HSL</span>
<input type="text" class="color-input hsl-input" id="bg-color-hsl" placeholder="hsl(0, 0%, 0%)">
</div>
</div>
</div>
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">Counter Text Color</span>
</div>
<div class="color-list">
<div class="color-row">
<div class="color-picker-container" style="--selected-color: #ffffff;">
<input type="color" id="counter-color" value="#ffffff">
</div>
<div class="color-input-group">
<span class="color-label">HEX</span>
<input type="text" class="color-input hex-input" id="counter-color-hex" value="#ffffff" placeholder="#ffffff">
</div>
<div class="color-input-group">
<span class="color-label">HSL</span>
<input type="text" class="color-input hsl-input" id="counter-color-hsl" placeholder="hsl(0, 0%, 100%)">
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
<div class="notification" id="notification"></div>
<script>
document.addEventListener('DOMContentLoaded', function() {
let transitionConfig = {
enableCounter: true,
counterSpeed: 10,
counterFontSize: 8,
dropDuration: 0.8,
expandDuration: 0.8,
windowWidth: 70,
windowHeight: 70,
bgColor: "#000000",
counterColor: "#ffffff",
windowLeft: 15,
windowTop: 15,
initialScale: 0.9
};
const defaultConfig = { ...transitionConfig };
function updateConfig() {
updatePreviewStyles();
saveConfiguration();
}
function initializePreview() {
updateConfig();
}
function updatePreviewStyles() {
const container = document.getElementById('previewTransitionContainer');
const background = document.getElementById('previewBackground');
const counter = document.getElementById('previewCounter');
const newPage = document.getElementById('previewNewPage');
if (background) {
background.style.backgroundColor = transitionConfig.bgColor;
}
if (counter) {
counter.style.fontSize = transitionConfig.counterFontSize + 'vw';
counter.style.color = transitionConfig.counterColor;
}
if (newPage) {
newPage.style.width = transitionConfig.windowWidth + '%';
newPage.style.height = transitionConfig.windowHeight + '%';
newPage.style.left = transitionConfig.windowLeft + '%';
newPage.style.transform = `scale(${transitionConfig.initialScale})`;
newPage.style.transition = `all ${transitionConfig.dropDuration}s cubic-bezier(0.25, 0.1, 0.25, 1)`;
}
if (container) {
container.style.setProperty('--drop-duration', transitionConfig.dropDuration + 's');
container.style.setProperty('--expand-duration', transitionConfig.expandDuration + 's');
}
}
function testTransition() {
const container = document.getElementById('previewTransitionContainer');
const counter = document.getElementById('previewCounter');
const newPage = document.getElementById('previewNewPage');
const previewContainer = document.getElementById('transition-preview');
container.classList.remove('PageTransition002-active');
counter.classList.remove('PageTransition002-visible');
newPage.classList.remove('PageTransition002-drop', 'PageTransition002-expand');
counter.textContent = '0';
newPage.style.position = 'absolute';
newPage.style.top = '-100%';
newPage.style.left = transitionConfig.windowLeft + '%';
newPage.style.width = transitionConfig.windowWidth + '%';
newPage.style.height = transitionConfig.windowHeight + '%';
newPage.style.transform = `scale(${transitionConfig.initialScale})`;
newPage.style.opacity = '0';
newPage.style.transition = `all ${transitionConfig.dropDuration}s cubic-bezier(0.25, 0.1, 0.25, 1)`;
newPage.style.maxWidth = '100%';
newPage.style.maxHeight = '100%';
newPage.style.contain = 'strict';
setTimeout(() => {
container.classList.add('PageTransition002-active');
if (transitionConfig.enableCounter) {
counter.classList.add('PageTransition002-visible');
let count = 0;
const counterInterval = setInterval(() => {
if (count >= 100) {
clearInterval(counterInterval);
counter.classList.remove('PageTransition002-visible');
setTimeout(() => {
startPageAnimation();
}, 300);
} else {
count += 4;
counter.textContent = count;
}
}, transitionConfig.counterSpeed);
} else {
setTimeout(() => {
startPageAnimation();
}, 100);
}
}, 100);
function startPageAnimation() {
newPage.style.top = transitionConfig.windowTop + '%';
newPage.style.opacity = '1';
newPage.classList.add('PageTransition002-drop');
setTimeout(() => {
newPage.style.transition = `all ${transitionConfig.expandDuration}s cubic-bezier(0.25, 0.1, 0.25, 1)`;
newPage.style.top = '0%';
newPage.style.left = '0%';
newPage.style.width = '100%';
newPage.style.height = '100%';
newPage.style.transform = 'scale(1)';
newPage.style.maxWidth = '100%';
newPage.style.maxHeight = '100%';
newPage.classList.add('PageTransition002-expand');
setTimeout(() => {
container.classList.remove('PageTransition002-active');
counter.classList.remove('PageTransition002-visible');
newPage.classList.remove('PageTransition002-drop', 'PageTransition002-expand');
newPage.style.position = 'absolute';
newPage.style.top = '-100%';
newPage.style.left = transitionConfig.windowLeft + '%';
newPage.style.width = transitionConfig.windowWidth + '%';
newPage.style.height = transitionConfig.windowHeight + '%';
newPage.style.transform = `scale(${transitionConfig.initialScale})`;
newPage.style.opacity = '0';
newPage.style.transition = `all ${transitionConfig.dropDuration}s cubic-bezier(0.25, 0.1, 0.25, 1)`;
newPage.style.maxWidth = '100%';
newPage.style.maxHeight = '100%';
counter.textContent = '0';
}, transitionConfig.expandDuration * 1000);
}, transitionConfig.dropDuration * 1000);
}
}
function generateJavaScriptCode() {
return `<div class="PageTransition002-container" id="PageTransition002Container">
<div class="PageTransition002-background"></div>
<div class="PageTransition002-counter" id="PageTransition002Counter">0</div>
<div class="PageTransition002-new-page" id="PageTransition002NewPage">
<iframe id="PageTransition002Iframe" frameborder="0"></iframe>
</div>
</div>
<style>
.PageTransition002-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2147483647;
display: flex;
justify-content: center;
align-items: center;
visibility: hidden;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
.PageTransition002-container.PageTransition002-active {
visibility: visible;
opacity: 1;
}
.PageTransition002-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: ${transitionConfig.bgColor};
z-index: 1;
}
.PageTransition002-counter {
font-size: ${transitionConfig.counterFontSize}vw;
font-weight: normal;
color: ${transitionConfig.counterColor};
z-index: 3;
opacity: 0;
transition: opacity 0.5s ease-in-out;
}
.PageTransition002-counter.PageTransition002-visible {
opacity: 1;
}
.PageTransition002-new-page {
position: absolute;
top: -100%;
left: ${transitionConfig.windowLeft}%;
width: ${transitionConfig.windowWidth}%;
height: ${transitionConfig.windowHeight}%;
opacity: 0;
transform: scale(${transitionConfig.initialScale});
transition: all ${transitionConfig.dropDuration}s cubic-bezier(0.25, 0.1, 0.25, 1);
z-index: 2;
overflow: hidden;
}
.PageTransition002-new-page iframe {
width: 100%;
height: 100%;
border: none;
}
.PageTransition002-new-page.PageTransition002-drop {
top: ${transitionConfig.windowTop}%;
opacity: 1;
}
.PageTransition002-new-page.PageTransition002-expand {
top: 0;
left: 0;
width: 100%;
height: 100%;
transform: scale(1);
}
</style>
<script>
(function() {
'use strict';
const transitionContainer = document.getElementById('PageTransition002Container');
const counter = document.getElementById('PageTransition002Counter');
const newPage = document.getElementById('PageTransition002NewPage');
const iframe = document.getElementById('PageTransition002Iframe');
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
const config = {
enableCounter: ${transitionConfig.enableCounter},
counterSpeed: ${transitionConfig.counterSpeed},
dropDuration: ${transitionConfig.dropDuration * 1000},
expandDuration: ${transitionConfig.expandDuration * 1000}
};
let isTransitioning = false;
function isInternalLink(url) {
try {
const link = new URL(url, window.location.origin);
return link.origin === window.location.origin;
} catch {
return false;
}
}
async function startNavigationTransition(targetUrl) {
if (isTransitioning) return;
isTransitioning = true;
transitionContainer.classList.add('PageTransition002-active');
iframe.src = targetUrl;
let iframeLoaded = false;
const iframeLoadPromise = new Promise(resolve => {
iframe.onload = () => {
iframeLoaded = true;
resolve();
};
});
if (config.enableCounter) {
counter.classList.add('PageTransition002-visible');
for (let i = 0; i <= 100; i++) {
counter.textContent = i;
await new Promise(resolve => setTimeout(resolve, isMobile ? 5 : config.counterSpeed));
}
counter.classList.remove('PageTransition002-visible');
await Promise.race([
iframeLoadPromise,
new Promise(resolve => setTimeout(resolve, 500))
]);
await new Promise(resolve => setTimeout(resolve, 300));
} else {
await Promise.race([
iframeLoadPromise,
new Promise(resolve => setTimeout(resolve, 500))
]);
await new Promise(resolve => setTimeout(resolve, 100));
}
newPage.classList.add('PageTransition002-drop');
await new Promise(resolve => setTimeout(resolve, config.dropDuration));
newPage.classList.add('PageTransition002-expand');
await new Promise(resolve => setTimeout(resolve, config.expandDuration));
window.location.href = targetUrl;
}
document.addEventListener('click', function(e) {
const link = e.target.closest('a');
if (link && link.href && isInternalLink(link.href) && !link.target) {
e.preventDefault();
startNavigationTransition(link.href);
}
});
const originalPushState = history.pushState;
const originalReplaceState = history.replaceState;
history.pushState = function(state, title, url) {
if (url && isInternalLink(url)) {
startNavigationTransition(url);
} else {
originalPushState.apply(history, arguments);
}
};
history.replaceState = function(state, title, url) {
if (url && isInternalLink(url)) {
startNavigationTransition(url);
} else {
originalReplaceState.apply(history, arguments);
}
};
})();
<\/script>`;
}
function generateFullSectionJSON() {
return "";
}
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 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 generateRandomTransition() {
transitionConfig.counterSpeed = Math.floor(Math.random() * 25) + 5;
transitionConfig.counterFontSize = Math.round((Math.random() * 8 + 4) * 2) / 2;
transitionConfig.dropDuration = Math.round((Math.random() * 1.2 + 0.3) * 10) / 10;
transitionConfig.expandDuration = Math.round((Math.random() * 1.2 + 0.3) * 10) / 10;
transitionConfig.windowWidth = Math.floor(Math.random() * 8) * 5 + 50;
transitionConfig.windowHeight = Math.floor(Math.random() * 8) * 5 + 50;
transitionConfig.windowLeft = Math.floor(Math.random() * 20) + 5;
transitionConfig.windowTop = Math.floor(Math.random() * 20) + 5;
transitionConfig.initialScale = Math.round((Math.random() * 0.3 + 0.7) * 20) / 20;
transitionConfig.bgColor = generateRandomColor();
transitionConfig.counterColor = generateRandomColor();
updateAllInputs();
updateConfig();
showNotification('Random transition generated!');
}
function generateRandomColor() {
return '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0');
}
function updateAllInputs() {
document.getElementById('enable-counter').checked = transitionConfig.enableCounter;
document.getElementById('counter-speed').value = transitionConfig.counterSpeed;
document.getElementById('counter-font-size').value = transitionConfig.counterFontSize;
document.getElementById('drop-duration').value = transitionConfig.dropDuration;
document.getElementById('expand-duration').value = transitionConfig.expandDuration;
document.getElementById('window-width').value = transitionConfig.windowWidth;
document.getElementById('window-height').value = transitionConfig.windowHeight;
document.getElementById('window-left').value = transitionConfig.windowLeft;
document.getElementById('window-top').value = transitionConfig.windowTop;
document.getElementById('initial-scale').value = transitionConfig.initialScale;
document.getElementById('counter-speed-value').textContent = transitionConfig.counterSpeed;
document.getElementById('counter-font-size-value').textContent = transitionConfig.counterFontSize;
document.getElementById('drop-duration-value').textContent = transitionConfig.dropDuration;
document.getElementById('expand-duration-value').textContent = transitionConfig.expandDuration;
document.getElementById('window-width-value').textContent = transitionConfig.windowWidth;
document.getElementById('window-height-value').textContent = transitionConfig.windowHeight;
document.getElementById('window-left-value').textContent = transitionConfig.windowLeft;
document.getElementById('window-top-value').textContent = transitionConfig.windowTop;
document.getElementById('initial-scale-value').textContent = transitionConfig.initialScale;
updateColorInputs('bg-color', transitionConfig.bgColor);
updateColorInputs('counter-color', transitionConfig.counterColor);
}
function updateColorInputs(colorId, color) {
const colorInput = document.getElementById(colorId);
const hexInput = document.getElementById(`${colorId}-hex`);
const hslInput = document.getElementById(`${colorId}-hsl`);
if (colorInput && hexInput && hslInput) {
colorInput.value = color;
hexInput.value = color;
hslInput.value = `hsl(${hexToHsl(color).h}, ${hexToHsl(color).s}%, ${hexToHsl(color).l}%)`;
hexInput.classList.remove('invalid');
hslInput.classList.remove('invalid');
const colorPickerContainer = colorInput.closest('.color-row').querySelector('.color-picker-container');
if (colorPickerContainer) {
colorPickerContainer.style.setProperty('--selected-color', color);
}
}
}
function hexToHsl(hex) {
const r = parseInt(hex.slice(1, 3), 16) / 255;
const g = parseInt(hex.slice(3, 5), 16) / 255;
const b = parseInt(hex.slice(5, 7), 16) / 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0;
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return {
h: Math.round(h * 360),
s: Math.round(s * 100),
l: Math.round(l * 100)
};
}
function hslToHex(hsl) {
const match = hsl.match(/hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/);
if (!match) return null;
let h = parseInt(match[1]) / 360;
let s = parseInt(match[2]) / 100;
let l = parseInt(match[3]) / 100;
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
let r, g, b;
if (s === 0) {
r = g = b = l;
} else {
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
const toHex = (c) => {
const hex = Math.round(c * 255).toString(16);
return hex.length === 1 ? '0' + hex : hex;
};
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
function isValidHex(hex) {
return /^#[0-9A-F]{6}$/i.test(hex);
}
function isValidHsl(hsl) {
return /^hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*\)$/i.test(hsl);
}
function formatHex(value) {
let hex = value.replace(/[^0-9A-Fa-f#]/g, '');
if (!hex.startsWith('#')) {
hex = '#' + hex;
}
if (hex.length > 7) {
hex = hex.substring(0, 7);
}
return hex.toUpperCase();
}
function formatHsl(value) {
const cleanValue = value.replace(/[^\d,\s]/g, '');
const numbers = cleanValue.match(/\d+/g);
if (!numbers || numbers.length < 3) {
const partialMatch = value.match(/(\d+)/g);
if (partialMatch && partialMatch.length >= 1) {
const h = Math.min(360, Math.max(0, parseInt(partialMatch[0]) || 0));
const s = Math.min(100, Math.max(0, parseInt(partialMatch[1]) || 50));
const l = Math.min(100, Math.max(0, parseInt(partialMatch[2]) || 50));
return `hsl(${h}, ${s}%, ${l}%)`;
}
return value;
}
let h = Math.min(360, Math.max(0, parseInt(numbers[0])));
let s = Math.min(100, Math.max(0, parseInt(numbers[1])));
let l = Math.min(100, Math.max(0, parseInt(numbers[2])));
return `hsl(${h}, ${s}%, ${l}%)`;
}
window.resetParameter = function(parameterId, defaultValue) {
const element = document.getElementById(parameterId);
if (element) {
element.value = defaultValue;
const valueElement = document.getElementById(`${parameterId}-value`);
if (valueElement) {
valueElement.textContent = defaultValue;
}
switch (parameterId) {
case 'counter-speed':
transitionConfig.counterSpeed = defaultValue;
break;
case 'counter-font-size':
transitionConfig.counterFontSize = defaultValue;
break;
case 'drop-duration':
transitionConfig.dropDuration = defaultValue;
break;
case 'expand-duration':
transitionConfig.expandDuration = defaultValue;
break;
case 'window-width':
transitionConfig.windowWidth = defaultValue;
break;
case 'window-height':
transitionConfig.windowHeight = defaultValue;
break;
case 'window-left':
transitionConfig.windowLeft = defaultValue;
break;
case 'window-top':
transitionConfig.windowTop = defaultValue;
break;
case 'initial-scale':
transitionConfig.initialScale = defaultValue;
break;
}
updateConfig();
showNotification(`${parameterId.replace(/-/g, ' ')} reset to default`);
}
};
function setupColorInputHandlers(colorId, configProperty) {
const colorInput = document.getElementById(colorId);
const hexInput = document.getElementById(`${colorId}-hex`);
const hslInput = document.getElementById(`${colorId}-hsl`);
if (!colorInput || !hexInput || !hslInput) return;
hslInput.value = `hsl(${hexToHsl(colorInput.value).h}, ${hexToHsl(colorInput.value).s}%, ${hexToHsl(colorInput.value).l}%)`;
colorInput.addEventListener('input', () => {
const color = colorInput.value;
hexInput.value = color;
hslInput.value = `hsl(${hexToHsl(color).h}, ${hexToHsl(color).s}%, ${hexToHsl(color).l}%)`;
hexInput.classList.remove('invalid');
hslInput.classList.remove('invalid');
transitionConfig[configProperty] = color;
const colorPickerContainer = colorInput.closest('.color-row').querySelector('.color-picker-container');
colorPickerContainer.style.setProperty('--selected-color', color);
updateConfig();
});
hexInput.addEventListener('input', (e) => {
let hex = e.target.value;
hex = formatHex(hex);
e.target.value = hex;
if (isValidHex(hex)) {
colorInput.value = hex;
hslInput.value = `hsl(${hexToHsl(hex).h}, ${hexToHsl(hex).s}%, ${hexToHsl(hex).l}%)`;
transitionConfig[configProperty] = hex;
e.target.classList.remove('invalid');
hslInput.classList.remove('invalid');
const colorPickerContainer = colorInput.closest('.color-row').querySelector('.color-picker-container');
colorPickerContainer.style.setProperty('--selected-color', hex);
updateConfig();
} else {
e.target.classList.add('invalid');
}
});
hexInput.addEventListener('blur', (e) => {
if (!isValidHex(e.target.value)) {
e.target.value = colorInput.value;
e.target.classList.remove('invalid');
}
});
hslInput.addEventListener('input', (e) => {
let hsl = e.target.value;
if (isValidHsl(hsl)) {
const hex = hslToHex(hsl);
if (hex) {
colorInput.value = hex;
hexInput.value = hex;
transitionConfig[configProperty] = hex;
e.target.classList.remove('invalid');
hexInput.classList.remove('invalid');
const colorPickerContainer = colorInput.closest('.color-row').querySelector('.color-picker-container');
colorPickerContainer.style.setProperty('--selected-color', hex);
updateConfig();
return;
}
}
e.target.classList.add('invalid');
});
hslInput.addEventListener('blur', (e) => {
let hsl = e.target.value;
if (!isValidHsl(hsl) && hsl.trim()) {
const formatted = formatHsl(hsl);
if (isValidHsl(formatted)) {
e.target.value = formatted;
const hex = hslToHex(formatted);
if (hex) {
colorInput.value = hex;
hexInput.value = hex;
transitionConfig[configProperty] = hex;
e.target.classList.remove('invalid');
hexInput.classList.remove('invalid');
updateConfig();
return;
}
}
}
if (!isValidHsl(e.target.value)) {
e.target.value = `hsl(${hexToHsl(colorInput.value).h}, ${hexToHsl(colorInput.value).s}%, ${hexToHsl(colorInput.value).l}%)`;
e.target.classList.remove('invalid');
}
});
}
function saveConfiguration() {
try {
localStorage.setItem('bricksfusion-transition002-config', JSON.stringify(transitionConfig));
} catch (e) {
}
}
function loadConfiguration() {
try {
const saved = localStorage.getItem('bricksfusion-transition002-config');
if (saved) {
const savedConfig = JSON.parse(saved);
Object.assign(transitionConfig, savedConfig);
updateAllInputs();
updateConfig();
}
} catch (e) {
}
}
function initializeUI() {
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('download-config').addEventListener('click', () => {
copyJsToClipboard();
});
document.getElementById('randomize-transition').addEventListener('click', () => {
generateRandomTransition();
});
const backgroundPicker = document.getElementById('preview-background-picker');
const previewContainer = document.getElementById('transition-preview');
backgroundPicker.addEventListener('input', (e) => {
const selectedColor = e.target.value;
previewContainer.style.backgroundColor = selectedColor;
showNotification(`Preview background changed to ${selectedColor}`);
});
previewContainer.style.backgroundColor = '#000000';
previewContainer.addEventListener('click', testTransition);
document.getElementById('reset-animation').addEventListener('click', () => {
transitionConfig.enableCounter = defaultConfig.enableCounter;
transitionConfig.counterSpeed = defaultConfig.counterSpeed;
transitionConfig.counterFontSize = defaultConfig.counterFontSize;
transitionConfig.dropDuration = defaultConfig.dropDuration;
transitionConfig.expandDuration = defaultConfig.expandDuration;
document.getElementById('enable-counter').checked = defaultConfig.enableCounter;
document.getElementById('counter-speed').value = defaultConfig.counterSpeed;
document.getElementById('counter-font-size').value = defaultConfig.counterFontSize;
document.getElementById('drop-duration').value = defaultConfig.dropDuration;
document.getElementById('expand-duration').value = defaultConfig.expandDuration;
document.getElementById('counter-speed-value').textContent = defaultConfig.counterSpeed;
document.getElementById('counter-font-size-value').textContent = defaultConfig.counterFontSize;
document.getElementById('drop-duration-value').textContent = defaultConfig.dropDuration;
document.getElementById('expand-duration-value').textContent = defaultConfig.expandDuration;
updateConfig();
showNotification('Animation settings reset');
});
document.getElementById('reset-window').addEventListener('click', () => {
transitionConfig.windowWidth = defaultConfig.windowWidth;
transitionConfig.windowHeight = defaultConfig.windowHeight;
transitionConfig.windowLeft = defaultConfig.windowLeft;
transitionConfig.windowTop = defaultConfig.windowTop;
transitionConfig.initialScale = defaultConfig.initialScale;
document.getElementById('window-width').value = defaultConfig.windowWidth;
document.getElementById('window-height').value = defaultConfig.windowHeight;
document.getElementById('window-left').value = defaultConfig.windowLeft;
document.getElementById('window-top').value = defaultConfig.windowTop;
document.getElementById('initial-scale').value = defaultConfig.initialScale;
document.getElementById('window-width-value').textContent = defaultConfig.windowWidth;
document.getElementById('window-height-value').textContent = defaultConfig.windowHeight;
document.getElementById('window-left-value').textContent = defaultConfig.windowLeft;
document.getElementById('window-top-value').textContent = defaultConfig.windowTop;
document.getElementById('initial-scale-value').textContent = defaultConfig.initialScale;
updateConfig();
showNotification('Window settings reset');
});
document.getElementById('reset-colors').addEventListener('click', () => {
transitionConfig.bgColor = defaultConfig.bgColor;
transitionConfig.counterColor = defaultConfig.counterColor;
updateColorInputs('bg-color', defaultConfig.bgColor);
updateColorInputs('counter-color', defaultConfig.counterColor);
updateConfig();
showNotification('Colors reset to default');
});
document.getElementById('enable-counter').addEventListener('change', function() {
transitionConfig.enableCounter = this.checked;
updateConfig();
});
const rangeInputs = document.querySelectorAll('input[type="range"]');
rangeInputs.forEach(input => {
const valueElement = document.getElementById(`${input.id}-value`);
if (valueElement) {
valueElement.textContent = input.value;
}
input.addEventListener('input', () => {
if (valueElement) {
valueElement.textContent = input.value;
}
switch (input.id) {
case 'counter-speed':
transitionConfig.counterSpeed = parseInt(input.value);
break;
case 'counter-font-size':
transitionConfig.counterFontSize = parseFloat(input.value);
break;
case 'drop-duration':
transitionConfig.dropDuration = parseFloat(input.value);
break;
case 'expand-duration':
transitionConfig.expandDuration = parseFloat(input.value);
break;
case 'window-width':
transitionConfig.windowWidth = parseInt(input.value);
break;
case 'window-height':
transitionConfig.windowHeight = parseInt(input.value);
break;
case 'window-left':
transitionConfig.windowLeft = parseInt(input.value);
break;
case 'window-top':
transitionConfig.windowTop = parseInt(input.value);
break;
case 'initial-scale':
transitionConfig.initialScale = parseFloat(input.value);
break;
}
updateConfig();
});
});
setupColorInputHandlers('bg-color', 'bgColor');
setupColorInputHandlers('counter-color', 'counterColor');
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;
}
} else {
switch (e.key.toLowerCase()) {
case 'r':
generateRandomTransition();
break;
case 'b':
document.getElementById('preview-background-picker').click();
break;
}
}
});
loadConfiguration();
initializePreview();
setTimeout(() => {
showNotification('BricksFusion Page Transition 002 Configurator loaded!');
}, 500);
}
initializeUI();
});
</script>
</body>
</html>Transition 002
Cinematic page transition featuring a counter animation followed by a dramatic drop-and-expand effect. The new page window falls from above, positions itself in the viewport, then smoothly expands to full screen. Configure timing, positioning, colors, and counter visibility directly in Bricks Builder. Perfect for creating engaging, movie-like navigation experiences.
Cinematic Transition
Click anywhere to preview the drop and expand effect.
Animation
Display animated counter from 0 to 100 before page transition begins. Counter creates anticipation and masks loading time. Disable for instant transitions without countdown. Counter fades in and out smoothly with configurable timing.
Default: On (true)
Interval between counter increments in milliseconds. Lower values create faster counting. Higher values produce slower, more deliberate progression. Affects total counter duration when enabled. Balance speed with user patience.
Default: 10ms (Range: 5-30ms)
Size of counter text relative to viewport width. Smaller values create subtle counters. Larger values produce bold, prominent displays. Uses viewport units for consistent sizing across devices. Consider mobile readability.
Default: 8vw (Range: 4-12vw)
Duration of page window drop animation from top to center position. Shorter creates snappy, quick drops. Longer produces smooth, cinematic motion. First phase of two-part transition sequence. Coordinate with expand duration for cohesive effect.
Default: 0.8s (Range: 0.3-1.5s)
Duration of page window expansion from centered position to full screen. Shorter creates rapid fills. Longer produces gradual, smooth expansions. Second phase of transition sequence. Scales window while removing border radius for seamless result.
Default: 0.8s (Range: 0.3-1.5s)
Page Window
Width of page preview window at drop position before expansion. Narrower creates compact, focused previews. Wider produces prominent, screen-filling windows. Automatically expands to 100% during final phase. Consider aspect ratio with height setting.
Default: 70% (Range: 50-90%)
Height of page preview window at drop position before expansion. Shorter creates letterbox effect. Taller produces vertical emphasis. Works with width to determine initial window aspect ratio. Expands to full viewport during transition completion.
Default: 70% (Range: 50-90%)
Horizontal position of window when dropped to center. Lower values shift left. Higher values shift right. Combined with width determines horizontal centering. Resets to 0% during expansion phase for full-screen coverage.
Default: 15% (Range: 5-25%)
Vertical position where window stops during drop animation. Lower values position higher on screen. Higher values drop window lower. Controls final drop destination before expansion begins. Animates from -100% (off-screen top) to this value.
Default: 15% (Range: 5-25%)
Starting scale of window before and during drop. Values below 1 create zoom-in effect during expansion. Value of 1 maintains size. Combines with scale(1) at end for smooth growth. Adds depth and dimension to transition.
Default: 0.9 (Range: 0.7-1.0)
Colors
Color of full-screen overlay background during entire transition. Provides base layer behind counter and page window. Choose colors matching brand identity or creating desired mood. Dark colors common for professional, cinematic feel. High contrast with counter color recommended.
Default: Black (#000000)
Text color of animated counter display. Only visible when counter is enabled. Ensure strong contrast with background color for readability. Light colors work well on dark backgrounds. Consider accessibility guidelines for sufficient contrast ratio.
Default: White (#ffffff)
Performance & Usage
This transition uses CSS transforms and cubic-bezier easing for smooth GPU-accelerated animations. Features two-phase animation sequence: drop then expand. Automatically loads new page in iframe during counter animation to minimize wait time. Intercepts all internal link clicks for consistent site-wide transitions. Includes mobile detection for optimized counter speed. Lightweight implementation with minimal performance impact. Add to header or footer template for global availability. Only one transition element needed per site.
