Glyph transition
A page transition in glyphs, between real pages.
Documentation
-
Copy to Webflow
Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: Webflow removes any font your site has not installed. -
Add custom CSS
Custom CSS in WebflowThis CSS already ships inside the Webflow embed, so a pasted section needs nothing added. Paste it yourself, in the page or the site custom code, only if the effect runs on several pages. The tutorial explains where.
See the tutorialThe code has to be on every page the transition joins. For no flash on arrival, move it out of the Embed into the site custom code, the CSS and the script both in the head: the next page is then covered from its first paint. -
Add custom JS
Custom JavaScript in WebflowThis script already ships inside the Webflow embed, settings block included. You paste it yourself, before the closing body tag of the page or the site custom code, only when the effect has to run on several pages, and the tutorial says how to choose.
See the tutorial -
Tune it
How to add a custom attribute in WebflowA custom attribute is a pair, a name and a value, typed in the Settings panel of the element you selected, under Custom attributes. The name is what the script looks for, the value is what it reads. The tutorial shows the panel.
See the tutorialCustom attributesSelect the section on the canvas and open the Settings panel. Under Custom attributes, add a pair: the name on the left, the value on the right.Custom attribute What it does data-glyph-transition Marks the element whose links are taken: a section, a menu, or the Body for every link of the page. It takes no value: leave the value field empty. The settings go on the same element. Without it on any element of the page, the embed marks the Body. data-glyph-transition-name On a link: the name written in the middle of the cover, in place of the words of the link. Without it the link writes its own words, and a link with no words the last part of its address. [ Optional ] data-glyph-transition-skip On a link, or on any block: the links inside are left to the browser, with no transition. It takes no value. [ Optional ] data-glyph-transition-state Written by the engine on the marked element: idle at rest, leaving while the glyphs cover the page, covered until the browser changes page, arriving while they drain, frozen for a held picture, still under reduced motion. Never written by hand. [ Optional ] data-glyph-transition-cover Written by the engine on the html element of a page reached through the glyphs, for the moment before the canvas is there: the stylesheet paints it as a flat screen of the cover colour. Never written by hand. [ Optional ] SettingsEvery setting is a custom attribute too, added the same way and on the same section. An attribute always wins over the defaults written in the code.Attribute Default What it is data-glyph-transition-background #15100c Colour of the cover, the solid a cell turns into and the screen the next page starts under. Options: any plain CSS colour, a hex or an rgb(); white for a light cover, with a dark color. data-glyph-transition-color #f4ece0 Colour of the glyphs and of the name written in the middle; a turning cell is lifted a little towards it. Options: any plain CSS colour that reads on background. data-glyph-transition-accent #ffab1a Colour of the few glyphs that light up as they turn and of the dot before the name. Options: any plain CSS colour; the same value as color for a pass in two colours only. data-glyph-transition-glyphs &!1@Y0?#:Z+=E The characters the cells shuffle through, written one after the other with no separator. data-glyph-transition-cell clamp(18px, 1.7vw, 24px) Side of one cell of the grid, any CSS unit; the glyph is 0.62 times that. data-glyph-transition-cover 0.66 Time the glyphs take to cover the page, from the click to the last cell, in seconds. data-glyph-transition-hold 0.3 Time the page stays covered before the browser is sent on, in seconds; the name finishes writing during it. data-glyph-transition-reveal 0.86 Time the glyphs take to drain away on the page reached, in seconds. data-glyph-transition-turn 0.3 Time one cell takes to turn, solid and glyph, in seconds. data-glyph-transition-grain 0.28 Share of chance in the order of the cells, 0 to 1; the rest is the distance to the pointer. data-glyph-transition-hot 0.06 Share of the cells whose glyph is lit in the accent while it turns, 0 to 1. data-glyph-transition-keep 0.14 Share of the cells that keep a dim glyph once the page is covered, 0 to 1, flickering until the page changes. data-glyph-transition-label true Whether the name of the page being reached is written in the middle. Options: true writes it; false leaves the cover bare. data-glyph-transition-label-size clamp(11px, 0.9vw, 13px) Size of the name, any CSS unit. data-glyph-transition-links a[href] CSS selector of the links the transition takes, among those inside the marked element. Options: a[href] takes every link; a narrower selector, nav a for one, takes only those.
Two files, no build step.
It runs in the browser only. Load it with a script tag in plain HTML, in a
client-side script in Astro, never in the frontmatter. In React, call
GlyphTransition.mount(ref.current) in useEffect and
destroy() in its cleanup.
-
Tune it, either way
Per element with an attribute, or once for the whole site by editingDEFAULTSat the top of the file.Attribute Default What it is Lower Higher data-glyph-transition-background #15100c Colour of the cover, the solid a cell turns into and the screen the next page starts under. Options: any plain CSS colour, a hex or an rgb(); white for a light cover, with a dark color. data-glyph-transition-color #f4ece0 Colour of the glyphs and of the name written in the middle; a turning cell is lifted a little towards it. Options: any plain CSS colour that reads on background. data-glyph-transition-accent #ffab1a Colour of the few glyphs that light up as they turn and of the dot before the name. Options: any plain CSS colour; the same value as color for a pass in two colours only. data-glyph-transition-glyphs &!1@Y0?#:Z+=E The characters the cells shuffle through, written one after the other with no separator. A short set, 01 or +, reads as a pattern A long set reads as noise; letters make it look like text data-glyph-transition-cell clamp(18px, 1.7vw, 24px) Side of one cell of the grid, any CSS unit; the glyph is 0.62 times that. A fine grain, more cells to draw, a denser screen Chunky blocks, large glyphs, a coarser front data-glyph-transition-cover 0.66 Time the glyphs take to cover the page, from the click to the last cell, in seconds. A snap; under turn every cell turns at once A slow tide, which makes the site feel slow on every click data-glyph-transition-hold 0.3 Time the page stays covered before the browser is sent on, in seconds; the name finishes writing during it. At 0 the page changes as the last cell lands, the name may still be writing A pause on the name before every page data-glyph-transition-reveal 0.86 Time the glyphs take to drain away on the page reached, in seconds. The page is simply there A long uncovering that keeps the content from the reader data-glyph-transition-turn 0.3 Time one cell takes to turn, solid and glyph, in seconds. A hard front, cells switching like pixels A wide soft front, half the screen turning at once data-glyph-transition-grain 0.28 Share of chance in the order of the cells, 0 to 1; the rest is the distance to the pointer. At 0 a clean circle growing from the click At 1 no direction at all, cells turning anywhere data-glyph-transition-hot 0.06 Share of the cells whose glyph is lit in the accent while it turns, 0 to 1. At 0 no accent in the grid, only the dot Past 0.3 the cover reads as a field of the accent colour data-glyph-transition-keep 0.14 Share of the cells that keep a dim glyph once the page is covered, 0 to 1, flickering until the page changes. At 0 a flat screen under the name Past 0.4 the name is hard to read in the noise data-glyph-transition-label true Whether the name of the page being reached is written in the middle. Options: true writes it; false leaves the cover bare. data-glyph-transition-label-size clamp(11px, 0.9vw, 13px) Size of the name, any CSS unit. A caption, the quiet mono label of the preview A title in the middle of the cover data-glyph-transition-links a[href] CSS selector of the links the transition takes, among those inside the marked element. Options: a[href] takes every link; a narrower selector, nav a for one, takes only those. -
Drive it from JavaScript
When a page change comes from your own code, a form sent or a card clicked, or when something on the page should start as the glyphs drain.const element = document.querySelector('[data-glyph-transition]'); element.addEventListener('glyph-transition:covered', (e) => { console.log(e.detail); }); const pass = GlyphTransition.mount(document.body); // the element auto() mounted, or a new one pass.leave('/order-desk', { name: 'Order desk' }); // covers, writes the name, then goes there pass.play({ name: 'Sorted' }); // the same pass with no page change // When the links go back to the browser: pass.destroy(); // removes the canvas and the listeners
-
Fit it to your page
- Structure: one element marked
data-glyph-transition, and every link inside it to another page of the same site is taken. Put it on<body>for the whole page, or on a menu for its links only. The effect reads no class and no child, and adds one canvas to the body while a pass is on screen,glyph-transition-layer, removed when the pass is over. - Both pages load the two files. The page being left covers itself and writes the pass; the page reached reads it and drains the glyphs. A page that does not load the script is reached with a plain navigation, and nothing is left covered.
- **Load them in the
<head>**, the stylesheet first, the script withoutdefer: the script reads the pass as it runs and marks<html>, and the stylesheet paints that mark as a flat screen of the cover colour, so the page reached never flashes before the glyphs take it. - Which links are taken: a plain left click, or Enter, on a link to another page of the same origin. Left to the browser: another site,
target="_blank",download, a file that is not a page (a PDF, a picture), an anchor of the page itself, a click with a modifier key, and any link inside an element markeddata-glyph-transition-skip. Thelinkssetting narrows it further with a selector. - The name written is the words of the link, in capitals, 28 characters at most.
data-glyph-transition-name="Order desk"on the link gives another one, which a link made of a picture or of a long sentence needs. A link with neither writes the last part of its address. - One setting for every page, without opening the file: declare
window.GlyphTransitionSettings = { background: '#f4ece0', color: '#15100c' }in a script placed beforeglyph-transition.js. The three levels, least specific first, areDEFAULTS, then that object, then adata-glyph-transition-*attribute on the marked element (data-glyph-transition-cover="0.9"). - The typeface of the glyphs is the canvas's own: the stylesheet sets
.glyph-transition-layerin Geist Mono at weight 500, inside:where(), so one rule of the page on that class changes it. A typeface the page has not loaded falls back to the next one of the stack. - What the script writes:
data-glyph-transition-stateon the marked element,idleat rest,leavingwhile the glyphs cover the page,covereduntil the browser changes page,arrivingwhile they drain,frozenfor a held picture,stillunder reduced motion; anddata-glyph-transition-coveron<html>, with the custom property--glyph-transition-cover, for the moment before the canvas is there. Nothing else: no inline size, no class. - Events, on the marked element, all bubbling:
glyph-transition:leaveas a taken link is clicked, with{ url, name }, andpreventDefault()on it leaves the click to the browser;glyph-transition:coveredjust before the browser is sent on;glyph-transition:arriveon the page reached as the glyphs start to drain, with{ name };glyph-transition:doneonce the canvas is gone. - **From JavaScript, beyond
mount,autoanddestroy**: the api carrieselement,settings,state(),leave(url, { x, y, name })which plays the pass and goes to an address as a click would,play({ x, y, name })which covers and drains in place with no page change, andfreeze()andunfreeze(), which hold the cover partway as a still picture, for a thumbnail. - **
destroy()leaves the page as it was**: the canvas removed, the listeners gone, the state attribute taken off. The links go back to the browser. - Touch and keyboard: a tap spreads the glyphs from the finger. Enter on a focused link carries no point, so the glyphs spread from the middle of the link.
- Back and forward: a page the browser kept in memory comes back as it was left, covered, and drains from the middle. A page it loads again arrives plain, since the pass was already used.
- **
prefers-reduced-motion**: nothing is taken, the links navigate as they always did, and a pass written by the page before is dropped. The state readsstill, and turning the preference off brings the transition back without a reload. - The words of the markup are the preview's, and they ship as they are. Put the user's own words in their place whenever they want, and point the links at their own pages.
- On Webflow, add the fonts first. Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: the paste names them, and the Designer drops a font the site does not have.
- On Webflow, the code goes on every page. The Embed runs on the page it is pasted on. Paste it on each page the transition joins, turn the pasted block into a Component, or move its code to the site custom code, the
<style>and the scripts in the head: that last place also covers the page reached from its first paint.
- Structure: one element marked
-
Avoid the pitfalls
- A script loaded late lets the page flash. With the script at the end of the body, or deferred, the page reached may paint once before it is covered. The transition still plays; the flash is the cost. Put the two files in the head.
- The first element mounted takes the arrival, within a moment of DOM ready. A pass that no element took 50 ms after the DOM is ready is dropped and the page shown. A framework that mounts later, after its own hydration, arrives plain.
- **Settings handed to
mount()after the page loaded are dropped.**auto()mounts on DOM ready, andmount()on an element that already carries the effect returns the existing one. A page-wide block goes inwindow.GlyphTransitionSettings, whichauto()reads itself. - **The colours go to a canvas, which cannot parse
color-mix()or a custom property.** A colour written that way falls back to the default. Give plain colours, a hex or anrgb(). - The cover of the first paint takes the colour of the page before. The page being left hands its
backgroundin the pass. Two pages with two cover colours change colour as the canvas takes over; keep one colour for the site, in the settings block. - A router has nothing to take. In a single page app the links never reload the page. Mark the router's links
data-glyph-transition-skipand callplay()around the route change, or use the router's own transition. - The canvas sits over everything, at the top of the stacking order (
z-index: 2147483001), and takes the pointer while a pass is on screen, so nothing is clicked twice. A cookie banner or a chat bubble is covered with the rest. - A link that downloads through a redirect looks like a page. The browser never leaves, and the cover is given back after eight seconds. Mark such a link
data-glyph-transition-skip, or give itdownload. - sessionStorage blocked (some private modes, an embedded frame with storage partitioned off): the page being left still covers itself, the page reached arrives plain.
One click on Copy the AI prompt copies everything an assistant needs to build this effect: the complete code, the markup, the dependency, every setting and every pitfall.
What it does
Glyph transition is a page transition for Webflow and vanilla JavaScript, with no library. Also called ASCII page transition, glyph page transition or character grid page transition.
A page transition in glyphs, between real pages. A click on a link to another page of the site covers the window with a grid of square cells spreading from the pointer: each cell turns solid while a mono glyph flickers in it, a few of them lit in the accent, and the front is broken by a grain fixed per cell so it never reads as a clean circle. Once the middle of the screen is covered, the name of the page being reached writes itself there, character by character through shuffled glyphs, after a dot in the accent. The browser then goes to the next page for real, and on arrival the same grid drains away from where the hand was, the name fading as the page comes back. There is no router and no library: the pass between the two pages, where the pointer was, the name and the colour of the cover, is kept in sessionStorage for the time of the navigation, and a page reached through the glyphs is covered from its first paint. It works wherever links lead to real pages, a Webflow site for one. Links to another site, to a new tab, to a file or to an anchor of the page are left to the browser. Under reduced motion nothing is taken: the links navigate as they always did.
Updated
Questions
Paste the component on each page the transition joins, or move its code to the site custom code with the <style> and the scripts in the head, because an Embed only runs on the page it is pasted on. Then put the custom attribute data-glyph-transition on the Body, or on a menu for its links only: every link inside it to another page of the same site is taken. Settings are more attributes on that element, for instance data-glyph-transition-cover="0.9".
No. The browser goes to the next page for real, and the pass between the two pages (where the pointer was, the name and the cover colour) is kept in sessionStorage for the time of the navigation. The glyphs are drawn on one canvas, added to the body while a pass is on screen and removed when it is over.
Three settings, in seconds: data-glyph-transition-cover is the time the glyphs take to cover the page (0.66 by default), data-glyph-transition-hold the time the page stays covered (0.3), and data-glyph-transition-reveal the time they drain away on the page reached (0.86). Lower values give a snap, and a high cover makes the site feel slow on every click.
The script runs too late on the page reached. Load the two files in the <head>, the stylesheet first and the script without defer: the script reads the pass as it runs and marks <html>, and the stylesheet paints that mark as a flat screen of the cover colour. With the script at the end of the body the transition still plays, and the flash is the cost.
Yes. The name written is the words of the link in capitals, 28 characters at most, and data-glyph-transition-name="Order desk" on the link gives another one. A link inside an element marked data-glyph-transition-skip is left to the browser, as are links to another site, target="_blank", downloads, files and anchors of the page itself.