Building clarity through thoughtful user experiences
█████████████████████████████████
Add these to your <head> or before closing </body> tag:
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/ScrollTrigger.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/ScrambleTextPlugin.min.js"></script>[data-scramble-text] {
position: sticky;
top: 50%;
transform: translateY(-50%);
z-index: 10;
pointer-events: none;
}
.scramble-container {
position: relative;
width: 100%;
}
.scramble-section {
height: 100vh;
width: 100%;
position: relative;
}
.scramble-text-wrapper {
position: absolute;
inset: 0;
z-index: 10;
display: flex;
align-items: center;
padding: 0 4vw;
pointer-events: none;
}This version changes text as you scroll through different sections:
gsap.registerPlugin(ScrollTrigger, ScrambleTextPlugin);
document.addEventListener("DOMContentLoaded", () => {
// Multi-section scroll scramble
document.querySelectorAll("[data-scramble-container]").forEach((container) => {
const textElement = container.querySelector("[data-scramble-text]");
if (!textElement) return;
const texts = JSON.parse(container.dataset.scrambleTexts || "[]");
const chars = container.dataset.scrambleChars || "!<>-_\\/[]{}—=+*^?#________";
const duration = parseFloat(container.dataset.scrambleDuration) || 0.5;
const speed = parseFloat(container.dataset.scrambleSpeed) || 0.1;
let currentIndex = 0;
const scrambleTo = (newIndex) => {
if (newIndex === currentIndex || !texts[newIndex]) return;
currentIndex = newIndex;
gsap.to(textElement, {
duration: duration,
scrambleText: {
text: texts[newIndex],
chars: chars,
revealDelay: 0.1,
speed: speed,
},
});
};
// Create triggers for each section
container.querySelectorAll("[data-scramble-trigger]").forEach((section) => {
const index = parseInt(section.dataset.scrambleTrigger);
ScrollTrigger.create({
trigger: section,
start: "top 50%",
onEnter: () => scrambleTo(index),
onLeaveBack: () => scrambleTo(Math.max(0, index - 1)),
});
});
});
});This version scrambles text once when the element enters the viewport:
// Single element scramble on scroll enter
document.querySelectorAll("[data-scramble-single]").forEach((element) => {
const finalText = element.dataset.scrambleFinal || element.textContent;
const chars = element.dataset.scrambleChars || "!<>-_\\/[]{}—=+*^?#";
const duration = parseFloat(element.dataset.scrambleDuration) || 0.5;
ScrollTrigger.create({
trigger: element,
start: "top 80%",
once: true,
onEnter: () => {
gsap.to(element, {
duration: duration,
scrambleText: {
text: finalText,
chars: chars,
revealDelay: 0.1,
speed: 0.1,
},
});
},
});
});<!-- Container with text array -->
<div
data-scramble-container
data-scramble-texts='["First text", "Second text", "Third text"]'
data-scramble-chars="▙▚▞▝▀▖▜▛▟"
data-scramble-duration="0.5"
>
<!-- Sticky text element -->
<div class="scramble-text-wrapper">
<p data-scramble-text>First text</p>
</div>
<!-- Trigger sections -->
<section data-scramble-trigger="0">...</section>
<section data-scramble-trigger="1">...</section>
<section data-scramble-trigger="2">...</section>
</div><!-- Scrambles once when scrolled into view -->
<h2
data-scramble-single
data-scramble-final="Your final revealed text"
data-scramble-chars="!@#$%^&*"
data-scramble-duration="1"
>
████████████████████████
</h2>| Attribute | Default | Description |
|---|---|---|
data-scramble-container | required | Wrapper for multi-section scramble |
data-scramble-texts | [] | JSON array of texts to cycle through |
data-scramble-text | required | The element that displays scrambling text |
data-scramble-trigger | required | Index of text to show (0, 1, 2...) |
data-scramble-single | - | Enables single-element scramble |
data-scramble-final | element text | Final text to reveal |
data-scramble-chars | !<>-_\\/[]{}—=+*^?# | Characters used during scramble |
data-scramble-duration | 0.5 | Animation duration in seconds |
data-scramble-speed | 0.1 | Speed of character reveal |
Steps for Webstudio:
1. Add GSAP scripts in Project Settings → Custom Code → Head:
- https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/gsap.min.js
- https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/ScrollTrigger.min.js
- https://cdn.jsdelivr.net/npm/gsap@3.14.1/dist/ScrambleTextPlugin.min.js
2. Create your HTML structure with Box elements
3. Add data attributes via Settings panel:
- Select the container Box → Settings → Add attribute
- Name: data-scramble-container
- Value: (leave empty)
4. For data-scramble-texts, add as attribute:
- Name: data-scramble-texts
- Value: ["Text 1", "Text 2", "Text 3"]
5. Add the JavaScript in Custom Code embed or Footer/* Blocks/Unicode */
"▙ ▚ ▞ ▝ ▀ ▖ ▜ ▛ ▟"
/* Matrix-style */
"!<>-_\\/[]{}—=+*^?#"
/* Simple symbols */
"!@#$%^&*()"
/* Letters */
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
/* Numbers */
"0123456789"
/* Mixed */
"▙▚▞akiedzek▝▀▖▜▛▟"