Stack and method
How we build.
The stack changes. The standards don’t.
The architecture of this site
This isn’t a list of technologies added for volume: it’s the stack the page you are reading is built with, and what each part actually does.
-
Presentation
What reaches the browser.
- Tailwind CSS
- Vite
- GSAP
- JavaScript
-
Templating
Where data becomes markup, with no logic.
- Twig
- Timber
-
Content
The backoffice and the editorial structure.
- WordPress
- ACF Pro
- Rank Math
-
Runtime
What runs on the server.
- PHP 8.2
- MySQL
- Composer
-
Delivery
How code reaches production.
- Git
- GitHub
- WP-CLI
- Staging
- CI/CD
- WordPress
-
CMS and editorial backend.
Your agency’s team already knows it. Used as a content system, not as a markup generator.
- Timber
-
A layer between WordPress logic and templates.
It separates data preparation from presentation: PHP doesn’t print HTML and templates don’t run queries.
- Twig
-
Clean, componentised templates.
Automatic escaping, syntax readable even by people who don’t write PHP, reusable components without pointless abstraction.
- ACF Pro
-
Structured content and backoffice.
Every piece of content is editable from the dashboard, while layout stays owned by the theme. Field groups versioned as Local JSON.
- Tailwind CSS
-
A CSS system with explicit design tokens.
CSS-first configuration: tokens live in the CSS, next to the rules that use them. No separate config file.
- Vite
-
Build and asset pipeline.
Cache busting from the manifest, HMR in development, short and readable configuration.
- GSAP
-
Entrance animation and micro-interactions.
Loaded in a separate chunk after first paint, and only if there is something on the page to animate. Never on the LCP element.
How we write code
-
01
Componentisation
A component is extracted when repetition is real, not in anticipation of it. Templates stay small and readable: past eighty lines, they get split.
The working rule is a single one: templates hold no logic, PHP holds no HTML. -
02
Semantic HTML
header, nav, main, section, footer, real lists, buttons for actions and links for navigation. One h1 per page and no skipped heading levels.
Anyone opening DevTools should find markup that reads without effort. -
03
Accessibility
Not a final phase. Skip link, always-visible focus, AA contrast, adequate touch targets, reduced motion respected, forms with real labels and announced errors.
The site stays keyboard-navigable and readable with JavaScript disabled. -
04
Performance
The first visible element is text: no image and no library between the reader and the first word.
Initial JavaScript has a declared budget, enforced in CI: if a change exceeds it, the build fails. -
05
Security
Sanitise on input, escape on output, a nonce on every action, a capability check on every privileged operation.
No credentials in the repository, no core modifications, no file editor enabled in production. -
06
Git and environments
Three separate environments with distinct databases. Code moves up from local to staging to production; the database only ever moves the other way.
Only what was approved in review reaches production, through a deliberate deploy.
No unnecessary dependencies.
The principle isn’t zero dependencies: it’s no dependency without a reason. Below is the full list of what this site loads, with real weights, and what we evaluated and chose not to use.
| Dipendenza | Peso | Perché |
|---|---|---|
| Timber + Twig | server side | Separation between logic and presentation. No impact on page weight. |
| ACF Pro | server side | Structured content and backoffice. No assets loaded on the frontend. |
| Rank Math | server side | Metadata, sitemap and schema. Unused modules are disabled in code, not from the dashboard. |
| Tailwind CSS | 8.8 KB gzip | Only the classes actually used end up in the compiled CSS. A single file, hashed in its name: long cache, no accidental invalidation. |
| Theme JavaScript | 1.7 KB gzip | Mobile menu with focus trap and header state. Nothing else in the initial bundle. |
| GSAP | 28.7 KB gzip, deferred | Loaded in a separate chunk after first paint, only if there is something to animate and only if the visitor hasn’t asked for reduced motion. It never enters the critical path. It runs the transitions; deciding when to run them is IntersectionObserver’s job, and that is native. |
| Geist + Geist Mono | 52 KB | Sans and mono drawn together: same proportions, same terminals. The monospace isn’t a foreign face borrowed to look technical — it is the same voice in another register. |
Evaluated and not used
-
GSAP ScrollTrigger
Adopted to tie the code-card animation to scroll progress, then removed. That tie produced half-states: stopping mid-way left two overlapping fragments, neither of them readable. With discrete transitions — cross a threshold, run an animation that always lands — the requirement disappeared, and eleven KB gzip with it. Scroll comes to rest on a stage through native CSS scroll-snap, which is the browser’s job and costs nothing.
-
Alpine.js
It was there for the mobile menu and the FAQ. The FAQ uses native details and summary; the menu is sixty lines of JavaScript. Fifteen KB for two components doesn’t hold up.
-
Multilingual plugins
WPML, Polylang and similar add tables, queries and a routing layer. Here the English pages are children of an en page: permalinks are native, without a single rewrite rule written by us.
-
Page builders
On this site layout is the theme’s responsibility. Editors change content, they don’t recompose pages.
-
Form plugins
Contact and applications are handled in the theme with nonces, honeypot, rate limiting and file validation. Less code loaded and more control over what happens to the data.
-
jQuery
Removed from the frontend. Not a single line of this site’s code needs it.
-
theme.json global styles
About seven KB of inline CSS generated for the block editor, never applied by a Twig frontend. Disabled.
Built the way we build for our partners.
This site is built with the same method we use on our partners’ projects. The figures below are the real ones, measured on the production build.
-
Homepage HTML
5.9 KB gzip
-
Total CSS
8.8 KB gzip
-
Initial JavaScript
1.7 KB gzip
-
Render-blocking requests
2
-
Active plugins
2
-
Page builders
0