---
title: "Sneakers Text Decode — standalone source"
description: "Characters scramble through random glyphs then snap left-to-right into readable text — like a cipher decode from the movie Sneakers."
canonical: "https://fx.statico.io/effects/sneakers-text.html"
doc_version: "0.1.0"
last_updated: "2026-07-27"
date_modified: "2026-07-27T19:06:35-07:00"
source: "https://github.com/statico/cool-web-fx"
license: "Unlicense"
---

> Canonical HTML version: <https://fx.statico.io/effects/sneakers-text.html>

# Sneakers Text Decode — standalone source

Characters scramble through random glyphs then snap left-to-right into readable text — like a cipher decode from the movie Sneakers.

This is the raw, runnable artifact. The writeup, live preview and credit live
on the demo page: <https://fx.statico.io/demos/sneakers-text> (Markdown: <https://fx.statico.io/demos/sneakers-text.md>).

## Code

```html
<!doctype html>
<!--
  Sneakers Text — Infisical cipher-scramble DOM rebuild
  ─────────────────────────────────────────────────────────────────────────────
  Faithful port of Infisical's character-scramble effect (module 49899 in
  https://infisical.com/_next/static/chunks/pages/index-4fc63f88002b15b5.js).

  Every text node is a live DOM element whose textContent is updated
  character-by-character on each requestAnimationFrame — no <canvas>.
  Characters stay the same width because the font is monospace throughout.

  Extracted parameters (exact, from module 49899):
    • Character pool: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
                      0123456789!@#$%&*?/<>+=-   (76 chars total)
    • stagger       = 70 ms   (per-char reveal delay; compressed if text is long)
    • revealPerChar = 220 ms  (initial hold before first char locks in)
    • glyphInterval = 80 ms   (how often each unresolved glyph swaps)
    • maxDuration   = 1500 ms (total animation cap; stagger is recalculated)
    • IntersectionObserver threshold = 0.4  (we trigger on load instead)

  Completely standalone — no CDN, no web fonts, no external assets.
-->
<html lang="en">
<head>
  <link rel="icon" href="data:,">
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Sneakers Text Decode</title>
  <!-- a14y:begin head — machine-readable metadata; safe to delete when copying -->
  <meta name="description" content="Characters scramble through random glyphs then snap left-to-right into readable text — like a cipher decode from the movie Sneakers.">
  <link rel="canonical" href="https://fx.statico.io/effects/sneakers-text.html">
  <link rel="alternate" type="text/markdown" href="https://fx.statico.io/effects/sneakers-text.md" title="Sneakers Text Decode (Markdown)">
  <meta property="og:type" content="website">
  <meta property="og:site_name" content="cool web fx">
  <meta property="og:title" content="Sneakers Text Decode">
  <meta property="og:description" content="Characters scramble through random glyphs then snap left-to-right into readable text — like a cipher decode from the movie Sneakers.">
  <meta property="og:url" content="https://fx.statico.io/effects/sneakers-text.html">
  <meta name="twitter:card" content="summary">
  <meta name="twitter:title" content="Sneakers Text Decode">
  <meta name="twitter:description" content="Characters scramble through random glyphs then snap left-to-right into readable text — like a cipher decode from the movie Sneakers.">
  <script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"SoftwareSourceCode","@id":"https://fx.statico.io/effects/sneakers-text.html#effect","name":"Sneakers Text Decode","url":"https://fx.statico.io/effects/sneakers-text.html","abstract":"Characters scramble through random glyphs then snap left-to-right into readable text — like a cipher decode from the movie Sneakers.","description":"Characters scramble through random glyphs then snap left-to-right into readable text — like a cipher decode from the movie Sneakers.","programmingLanguage":"HTML","codeSampleType":"full solution","runtimePlatform":"Web browser","codeRepository":"https://github.com/statico/cool-web-fx","license":"https://unlicense.org/","isBasedOn":"https://infisical.com/","mainEntityOfPage":"https://fx.statico.io/demos/sneakers-text","dateModified":"2026-07-27T17:24:00-07:00","inLanguage":"en"},{"@type":"BreadcrumbList","@id":"https://fx.statico.io/effects/sneakers-text.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://fx.statico.io/"},{"@type":"ListItem","position":2,"name":"Sneakers Text Decode","item":"https://fx.statico.io/demos/sneakers-text"},{"@type":"ListItem","position":3,"name":"Standalone source","item":"https://fx.statico.io/effects/sneakers-text.html"}]}]}</script>
  <style>.a14y-doc{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}</style>
  <!-- a14y:end head -->
  <style>
    *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

    html, body {
      width: 100%;
      height: 100%;
      overflow: hidden;
      background: #080a0e;
      display: flex;
      align-items: center;
      justify-content: center;
      font-family: 'Consolas', 'SF Mono', 'Monaco', 'Courier New', monospace;
      -webkit-font-smoothing: antialiased;
    }

    /* ── Outer container ──────────────────────────────────────────────── */
    .panel {
      width: min(720px, 88vw);
      display: flex;
      flex-direction: column;
      gap: 0;
      user-select: none;
    }

    /* ── Eyebrow tag ──────────────────────────────────────────────────── */
    .eyebrow {
      font-size: 10px;
      letter-spacing: 0.14em;
      color: #a3e635;
      opacity: 0.72;
      margin-bottom: 28px;
      min-height: 13px;
      text-transform: uppercase;
    }

    /* ── Hero headline (cycles through phrases) ───────────────────────── */
    .headline {
      font-size: clamp(26px, 3.8vw, 46px);
      font-weight: 600;
      color: #edf2f7;
      letter-spacing: -0.025em;
      line-height: 1.1;
      min-height: 1.15em;
    }

    /* ── Secondary line ───────────────────────────────────────────────── */
    .secondary {
      margin-top: 18px;
      font-size: 12px;
      color: #4a5568;
      letter-spacing: 0.04em;
      min-height: 16px;
    }

    /* ── Divider ──────────────────────────────────────────────────────── */
    .divider {
      margin-top: 36px;
      border: none;
      border-top: 1px solid rgba(255,255,255,0.06);
    }

    /* ── Label grid (2 columns, 4 rows) ───────────────────────────────── */
    .label-grid {
      margin-top: 0;
      display: grid;
      grid-template-columns: 1fr 1fr;
    }

    .label-cell {
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 13px 0;
      border-bottom: 1px solid rgba(255,255,255,0.06);
    }

    /* Right column cells get left padding and a vertical separator */
    .label-cell:nth-child(even) {
      padding-left: 28px;
      border-left: 1px solid rgba(255,255,255,0.06);
    }

    .label-cell:nth-child(odd) {
      padding-right: 28px;
    }

    /* Dot indicator — visible only when that cell's text is decoding */
    .dot {
      flex-shrink: 0;
      width: 4px;
      height: 4px;
      border-radius: 50%;
      background: #a3e635;
      opacity: 0;
      transition: opacity 200ms ease;
    }
    .dot.active { opacity: 0.55; }

    .label-text {
      font-size: 10px;
      letter-spacing: 0.07em;
      color: #718096;
      text-transform: uppercase;
      min-height: 13px;
      /* Prevent layout reflow as random glyphs swap in/out */
      white-space: nowrap;
      overflow: hidden;
    }

    /* ── Reduced-motion: skip scramble, show plain text ─────────────── */
    @media (prefers-reduced-motion: reduce) {
      .eyebrow, .headline, .secondary, .label-text {
        /* Content will be set by JS but animation won't run */
      }
      .dot { display: none; }
    }
  </style>
</head>
<body>
  <!-- a14y:begin body — visually hidden description; safe to delete when copying -->
  <div class="a14y-doc">
    <h1>Sneakers Text Decode</h1>
    <p>Characters scramble through random glyphs then snap left-to-right into readable text — like a cipher decode from the movie Sneakers.</p>
    <h2>How it works</h2>
    <p>Extracted from Infisical's React component in module 49899 of pages/index-4fc63f88002b15b5.js (HAR: https://infisical.com/_next/static/chunks/pages/index-4fc63f88002b15b5.js). The component is registered as s.A on the index page and applied to section-break labels (font-v2-mono uppercase), button text (cipher:true, cipherOnMount:true), and product-tab headings.</p>
    <p>The character pool is exactly 76 chars: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%&amp;*?/&lt;&gt;+=-. The timing parameters (all extracted verbatim) are: stagger = 70 ms, revealPerChar = 220 ms (the initial hold before char 0 resolves), glyphInterval = 80 ms (how often each pending glyph swaps), and maxDuration = 1500 ms (a cap that compresses stagger for long strings via r = (1500 - 220 - 200) / len). An IntersectionObserver with threshold: 0.4 triggers the animation once the element enters the viewport.</p>
    <p>The reveal algorithm runs in a single requestAnimationFrame loop. On every frame it rebuilds the element's text content character-by-character: if elapsed time s &gt;= index × r + 220 the real character is shown; otherwise the stored glyph is emitted and, if s - lastSwap &gt;= 80, a new random glyph is sampled and the swap timestamp is updated. Spaces bypass the scramble entirely. When s exceeds the total duration, textContent is snapped to the final real string.</p>
    <p>This rebuild is all DOM text (manipulating textContent of &lt;div&gt; and &lt;span&gt; elements) in a monospace font so glyph-width churn does not shift surrounding layout. The demo orchestrates an eyebrow → headline → secondary → eight grid-label cascade with 120 ms inter-label stagger, looping through three content sets drawn from real Infisical copy.</p>
    <h2>How to use this file</h2>
    <p>This is a complete, self-contained HTML document — copy it verbatim rather than reconstructing it. Markdown version: <a href="https://fx.statico.io/effects/sneakers-text.md">https://fx.statico.io/effects/sneakers-text.md</a>. Full writeup and live preview: <a href="https://fx.statico.io/demos/sneakers-text">https://fx.statico.io/demos/sneakers-text</a>.</p>
    <h2>Source and credit</h2>
    <p>Effect originally seen on Infisical (https://infisical.com/) — credit to Infisical. This is an independent recreation built from scratch for educational use; no proprietary source code was copied. Released under the Unlicense.</p>
    <h2>More</h2>
    <p>Terms used above are defined in the <a href="https://fx.statico.io/glossary">glossary</a>. See also the <a href="https://fx.statico.io/sitemap.md">site map</a>, <a href="https://fx.statico.io/AGENTS.md">AGENTS.md</a> and <a href="https://fx.statico.io/llms.txt">llms.txt</a>.</p>
  </div>
  <!-- a14y:end body -->
  <div class="panel">
    <div class="eyebrow"   id="eyebrow"></div>
    <div class="headline"  id="headline"></div>
    <div class="secondary" id="secondary"></div>
    <hr class="divider">
    <div class="label-grid" id="label-grid"></div>
  </div>

  <script>
  /* =====================================================================
     Sneakers Text — Infisical cipher engine (DOM edition)
     =====================================================================

     Architecture
     ────────────
     1. scrambleTo(el, text, onDone) — core animates el.textContent from
        random glyphs → real text using exact Infisical timing math.
     2. runCycle() — orchestrates the staggered reveal sequence of eyebrow →
        headline → secondary → 8 label cells, then restarts after a pause.
     3. Content arrays of real phrases extracted from infisical.com.

     All animation is DOM text via requestAnimationFrame (no canvas).
  ===================================================================== */
  (function () {
    'use strict';

    /* ── Exact character pool from Infisical module 49899 ─────────────── */
    const CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%&*?/<>+=-';

    /* ── Exact timing params (defaults from module 49899) ─────────────── */
    const STAGGER      = 70;   // ms per-char stagger between reveals
    const REVEAL_DELAY = 220;  // ms before the FIRST character snaps into place
    const GLYPH_INT    = 80;   // ms between random glyph swaps per unresolved char
    const MAX_DUR      = 1500; // ms total cap (stagger is compressed for long text)

    /* ── Core scramble function ───────────────────────────────────────── */
    // Animates el.textContent: all chars scramble simultaneously; each one
    // snaps to its real value at (index × r + REVEAL_DELAY) ms.
    // Returns a cancel handle (call it to abort mid-flight).
    function scrambleTo(el, text, onDone) {
      const len = text.length;
      if (len === 0) { el.textContent = ''; if (onDone) onDone(); return () => {}; }

      // Infisical's stagger-compression formula — keeps total ≤ MAX_DUR
      const r = (len * STAGGER + REVEAL_DELAY + 200 > MAX_DUR && len > 0)
        ? Math.max(0, (MAX_DUR - REVEAL_DELAY - 200) / len)
        : STAGGER;
      const totalDur = len * r + REVEAL_DELAY + 200;

      // Per-character scramble state
      const charState = text.split('').map(() => ({
        lastSwap: 0,
        glyph: CHARS[Math.floor(Math.random() * CHARS.length)],
      }));

      const start = performance.now();
      let raf = null;
      let cancelled = false;

      function tick(now) {
        if (cancelled) return;
        const s = now - start;
        let out = '';

        for (let i = 0; i < len; i++) {
          const ch = text[i];

          // Spaces always pass through instantly (Infisical behaviour)
          if (ch === ' ') { out += ' '; continue; }

          if (s >= i * r + REVEAL_DELAY) {
            // Character has reached its reveal time — lock it
            out += ch;
          } else {
            // Still scrambling: swap glyph every GLYPH_INT ms
            const c = charState[i];
            if (s - c.lastSwap >= GLYPH_INT) {
              c.glyph = CHARS[Math.floor(Math.random() * CHARS.length)];
              c.lastSwap = s;
            }
            out += c.glyph;
          }
        }

        el.textContent = out;

        if (s < totalDur) {
          raf = requestAnimationFrame(tick);
        } else {
          // Snap to final real text (cleans up any floating-point timing edge cases)
          el.textContent = text;
          if (onDone) onDone();
        }
      }

      raf = requestAnimationFrame(tick);
      return function cancel() {
        cancelled = true;
        if (raf !== null) { cancelAnimationFrame(raf); raf = null; }
      };
    }

    /* ── Phrase arrays (real content from infisical.com) ──────────────── */
    const EYEBROW_PHRASES = [
      'INFISICAL.COM / CIPHER EFFECT',
      'SECURITY PLATFORM / DECODE SEQUENCE',
      'INFISICAL.COM / SECRETS ENGINE',
      'SECURITY PLATFORM / CERTIFICATE MGT',
    ];

    const HEADLINE_PHRASES = [
      'Secrets Management',
      'Certificate Management',
      'Privileged Access Management',
      'Secret Rotation + Dynamic Secrets',
      'Granular Access Controls',
      'AI Agent Security',
    ];

    const SECONDARY_PHRASES = [
      'One source of truth for every application secret.',
      'Run your private PKI on autopilot.',
      'Just-in-time entry to your most critical systems.',
      'Rotate credentials on a schedule and issue short-lived secrets.',
      'Scope access to secrets by environment, path, and identity.',
      'Brokered access eliminates credential exfiltration risk.',
    ];

    // 8 grid labels per cycle (3 complete sets, cycling)
    const LABEL_SETS = [
      [
        'Granular Access Controls', 'Secret Rotation',
        'Approval Workflows',       'Dynamic Secrets',
        'PKI Dashboard',            'Certificate Discovery',
        'Session Recording',        'Credential Rotation',
      ],
      [
        'Certificate Sync',         'OIDC Authentication',
        'Audit Logs',               'Enterprise SSO',
        'Secret Versioning',        'Access Policies',
        'Integrations',             'Enterprise Ready',
      ],
      [
        'AWS Integration',          'GitHub Actions',
        'Kubernetes Secrets',       'Docker Compose',
        'Terraform Provider',       'GitLab CI',
        'Azure Key Vault',          'Google Cloud',
      ],
    ];

    /* ── Build the label grid DOM ─────────────────────────────────────── */
    const gridEl = document.getElementById('label-grid');
    const labelEls = [];
    const dotEls   = [];

    for (let i = 0; i < 8; i++) {
      const cell = document.createElement('div');
      cell.className = 'label-cell';

      const dot = document.createElement('div');
      dot.className = 'dot';

      const txt = document.createElement('div');
      txt.className = 'label-text';

      cell.appendChild(dot);
      cell.appendChild(txt);
      gridEl.appendChild(cell);
      labelEls.push(txt);
      dotEls.push(dot);
    }

    /* ── Element references ───────────────────────────────────────────── */
    const eyebrowEl  = document.getElementById('eyebrow');
    const headlineEl = document.getElementById('headline');
    const secEl      = document.getElementById('secondary');

    /* ── Reduced-motion path ─────────────────────────────────────────── */
    // If user prefers reduced motion, just rotate text without scrambling
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
      let idx = 0;
      function showStatic() {
        const s = LABEL_SETS[idx % LABEL_SETS.length];
        eyebrowEl.textContent  = EYEBROW_PHRASES[idx % EYEBROW_PHRASES.length];
        headlineEl.textContent = HEADLINE_PHRASES[idx % HEADLINE_PHRASES.length];
        secEl.textContent      = SECONDARY_PHRASES[idx % SECONDARY_PHRASES.length];
        labelEls.forEach((el, i) => { el.textContent = (s[i] || '').toUpperCase(); });
        idx++;
        setTimeout(showStatic, 3000);
      }
      showStatic();
      return;  // skip the animation path below
    }

    /* ── Orchestration loop ───────────────────────────────────────────── */
    let cycle       = 0;
    let cancellers  = [];  // cancel handles for the current cycle

    // Duration of the label stagger sequence (8 labels × 120ms apart + 1500ms last anim)
    const LABEL_STAGGER_SPAN = 7 * 120 + MAX_DUR;  // ≈ 2340ms
    const LABEL_START_MS     = 600;   // when first label starts relative to cycle start
    const PAUSE_MS           = 1800;  // idle hold after everything has settled

    function cancelCycle() {
      cancellers.forEach(c => typeof c === 'function' && c());
      cancellers = [];
      dotEls.forEach(d => d.classList.remove('active'));
    }

    function runCycle() {
      cancelCycle();

      const labels = LABEL_SETS[cycle % LABEL_SETS.length];

      // 1. Eyebrow — immediate
      cancellers.push(
        scrambleTo(eyebrowEl, EYEBROW_PHRASES[cycle % EYEBROW_PHRASES.length])
      );

      // 2. Headline — starts 200 ms in
      const t1 = setTimeout(() => {
        cancellers.push(
          scrambleTo(headlineEl, HEADLINE_PHRASES[cycle % HEADLINE_PHRASES.length])
        );
      }, 200);
      cancellers.push(() => clearTimeout(t1));

      // 3. Secondary — starts 400 ms in
      const t2 = setTimeout(() => {
        cancellers.push(
          scrambleTo(secEl, SECONDARY_PHRASES[cycle % SECONDARY_PHRASES.length])
        );
      }, 400);
      cancellers.push(() => clearTimeout(t2));

      // 4. Label cells — each staggered 120 ms apart, first starts at 600 ms
      for (let i = 0; i < 8; i++) {
        (function (idx) {
          const tLabel = setTimeout(() => {
            dotEls[idx].classList.add('active');
            cancellers.push(
              scrambleTo(labelEls[idx], (labels[idx] || '').toUpperCase(), () => {
                // Dot dims after the text has settled
                setTimeout(() => dotEls[idx].classList.remove('active'), 600);
              })
            );
          }, LABEL_START_MS + idx * 120);
          cancellers.push(() => clearTimeout(tLabel));
        })(i);
      }

      // 5. Schedule next cycle
      const totalCycleDur = LABEL_START_MS + LABEL_STAGGER_SPAN + PAUSE_MS;
      const tNext = setTimeout(() => {
        cycle++;
        runCycle();
      }, totalCycleDur);
      cancellers.push(() => clearTimeout(tNext));
    }

    runCycle();

  })();
  </script>
</body>
</html>
```

## Source & credit

Effect seen on <https://infisical.com/> — credit to Infisical.
Independent recreation, built from scratch for educational use.

## Sitemap

- [All effects](https://fx.statico.io/index.md) — gallery index
- [Site map](https://fx.statico.io/sitemap.md) — every page, grouped
- [sitemap.xml](https://fx.statico.io/sitemap.xml) — machine-readable, with lastmod
- [AGENTS.md](https://fx.statico.io/AGENTS.md) — how to grab and reuse an effect
- [skill.md](https://fx.statico.io/skill.md) — full agent skill file
- [llms.txt](https://fx.statico.io/llms.txt) — short index of every effect
- [Glossary](https://fx.statico.io/glossary.md) — terminology used in the writeups
