What it is
A complete site for a design studio: selected work, capabilities, a single price, client results, articles, an FAQ and a closing call. One page, one HTML file, written by hand — no dependency, no build step, no CDN.
What makes this template is what it refuses to do. The original ships a 1920 × 1080 background video in two formats — 12 MB of MP4 and 36 MB of WebM, 48 MB in all, for a block measuring 1220 × 612. Here it is a still photograph with a 34-second CSS drift. The whole folder now weighs a fraction of that one file. Every other choice in the page follows the same rule: keep the intent, drop the cost.
The design comes from a Webflow template for a design studio of which
not one image remains: the photographs were regenerated for
this template. Every line of code was rewritten — jQuery, GSAP and its
SplitText plugin, the proprietary IX2 animation engine, the minified CSS,
and the inline style="opacity:0" on every animated block, which
a strict security policy blocks, leaving a blank page.
That is the point: this template is not here to be admired, it is here to be read, broken and put back together.
What you change first
The colours — there is no accent, and that’s deliberate
The original has no brand colour at all: black, white and five greys. Every bit of colour on the page comes from the photographs. That is a decision, not an oversight, and it is kept — adding a brand hue would break the design while thinking it was dressing it.
--ink: #0A0A0A; /* headings — 19.3:1 on white */
--body: #3D3D3D; /* running text — 10.4:1 */
--muted: #6E6E6E; /* secondary text — 5.3:1 */
--faint: #9B9B9B; /* 2.7:1 — labels only, never alone */
--surface: #F2F2F2; /* cards */
The shift happens where the colour actually is: the original’s photographs
pull cold blue — sky, cyan shadows — and Brightfold’s pull amber and sand,
at equivalent lightness and contrast. #9B9B9B sits below the
4.5:1 threshold, so it is used for 14 px labels that always come with
another cue, never to carry information on its own.
The name
Search for “Brightfold” in index.html: the header, the hero,
the about block, the reviews, the footer, the <title> and
the description. No CSS class contains the brand — a find-and-replace cannot
break anything. The logo is a six-line SVG in the header.
The sizes
The type scale is declared once, then re-declared at each breakpoint and
nowhere else: change --h1-size and the whole page follows. No
heading carries its own media query.
The animations, and how they’re built
The original’s settings were not guessed, they were read: a Webflow export
keeps durations, curves, delays and triggers in its animation store, at
ix2.store.getState().ixData. 219 events are declared there,
which deduplicate down to 51 distinct effects — the editor creates one event
per collection item.
| Effect | Original settings | How |
|---|---|---|
| Reveal on scroll (121 blocks) | opacity 0 → 1 and y 100 px → 0, 1000 ms, outQuart, delays of 300 to 700 ms, fired on the first visible pixel | same duration, same curve (cubic-bezier(.25,1,.5,1)), delays cut to 0/90/180/270 ms, fired at 15 % from the bottom of the screen |
| Project image parallax (6 cards) | a 635 px image inside a 541 px frame, sliding through those 94 px, smoothing 96 | kept exactly — the script writes the position as you scroll |
| Retracting header | y 0 ↔ −100 %, 500 ms, by scroll direction | same, with a 200 px threshold and a 6 px dead band |
| Logo rails (3) | x 0 → −100 % over 20 s, looping | list doubled and translated by −50 % over 40 s: same speed, and the loop has no seam |
| Accordions (capabilities, FAQ) | Webflow tabs, size and rotation over 500 ms ease | native <details name>, height animated over 500 ms |
| Constellation (closing call) | 9 thumbnails going from scale 1 to 0 over 500 ms inOutQuint, looping | a 14 s CSS animation, the 9 thumbnails offset by 1.5 s |
| Full-screen menu | y −100 % → 0 over 700 ms outExpo | same (cubic-bezier(.16,1,.3,1)) |
| Card hover | scale 1.135 over 400 ms | scale 1.04 over 600 ms: at 1.135 on a 600 px image the reframing shows |
| Filling text (values) | GSAP SplitText, letter by letter, 310–760 ms, power1.out | word by word, driven by scroll position rather than by a duration |
Two of the original’s settings are corrected on purpose. Its reveals fire on the first visible pixel and then wait up to 700 ms before a 1 s animation: that is 1.7 s between the moment a block enters the screen and the moment it is readable. And its threshold is expressed as a share of the element — which leaves any block taller than the screen hidden for ever. Here the margin is measured on the viewport, and a safety net reveals whatever is left when the bottom of the page is reached.
What you should know
No dependency, no build, no CDN, no external request. Measured: 35 requests on load, all local.
Without JavaScript, nothing is hidden. Every hidden state is
written under html.js, and enhance.js is the only
thing that sets that class. Scripts removed: 27 headings visible, 0
transparent blocks, 0 displaced blocks, the 15 accordions open and the 3
rails show their logos.
The native thing first. <details name>
for both accordions — they open without script, answer the keyboard, and can
be found by the browser’s find-on-page.
One font, not two. The original loads “Inter Display”, which
is the same drawing at a different optical size; here the variable
opsz axis does that job from a single file.
Under a strict security policy
(script-src 'self'; style-src 'self'): zero violations, counted
by serving the folder with the site’s real header. No inline style, no inline
script, no onclick. Reveals use
IntersectionObserver, never animation-timeline —
that one only exists in Chrome.
Accessibility: skip link, aria-expanded on the
menu, focus kept inside the open panel, Esc closes, decorations
in aria-hidden, a single focus ring, and
prefers-reduced-motion that applies the end states —
delays included.
What isn’t perfect
The hero video became an image. 48 MB for one block, a thousand times the weight of everything else in the folder, and the only media that still raised a licence question. It is replaced by a still photograph with a slow 34 s drift. Side by side with the original, the difference shows.
Capabilities stay folded on mobile. The original unfolds its ten entries below 767 px: the section is then 4,910 px tall, and 6,411 px below 480 px. Here the accordion stays closed and the section is 1,348 px — a measured −73 %, and a deliberate one. Ten open panels is five screens of scrolling for a list of services.
Reviews go to two columns below 767 px where the original stacks them: −31 % in height. Three portrait cards across the full width of a phone is 2,500 px for three figures.
The pointer and scroll parallaxes are not reproduced. The original has four, with smoothing of 95 to 96 — that is, a movement that chases the cursor a long way behind. On a page with no other continuous motion, they mostly show up when reading the code.
Total height at 1440 px: +0.2 % — 11,413 px against 11,391. Section by section: work +0 %, about 0 %, reviews +0 %, FAQ +1 %, footer 0 %, hero +2 %, pricing +4 %, founder +5 %. The only two gaps beyond 5 % are the two choices described above. On a phone the gap reverses: 14,421 px at 479 px wide against 20,176 for the original, −28 %, almost all of it the folded capabilities.
The original’s typos are fixed — “Project Inquary”, “Parnarship”, “Demund of Service”, “Password Proteced”, “100+ Worldwide Client”, and two headings whose syntax did not hold. One FAQ answer that repeated the first one word for word was rewritten.
Links to other pages became anchors. The original points at
/blog, /contact, /work, legal pages
and a changelog. This template is one page: everything points at a section
that exists rather than at a 404.
It’s waiting for you in the library.
Brightfold comes with the subscription, alongside the rest of the library and the full course.
Immediate access · No commitment · Cancel in one click