<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>
George Brook – Front End Developer | CV & Portfolio
</title>
<meta name="description" content="Explore the CV of George Brook, a Front End developer specializing in accessible, performant, and user-focused web experiences.">
<link rel="canonical" href="https://yourdomain.com/">
<meta property="og:title" content="George Brook – Front End Developer | CV & Portfolio">
<meta property="og:description" content="Explore the CV of George Brook, a Front End developer specializing in accessible, performant, and user-focused web experiences.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://yourdomain.com/">
<meta property="og:image" content="https://yourdomain.com/og-image.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="George Brook – Front End Developer | CV & Portfolio">
<meta name="twitter:description" content="Explore the CV of George Brook, a Front End developer specializing in accessible, performant, and user-focused web experiences.">
<meta name="twitter:image" content="https://yourdomain.com/og-image.jpg">
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#121212" media="(prefers-color-scheme: dark)">
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="manifest" href="/site.webmanifest">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Chivo+Mono:ital,wght@0,100..900;1,100..900&family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
</head>
<body>
<canvas class="background-noise">
</canvas>
<button id="random-color-btn" class="color-toggle fun-button" aria-label="Randomise font">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" stroke-dasharray="28" stroke-dashoffset="28" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3c0 0 7 6 7 12c0 2 -1 6 -7 6M12 3c0 0 -7 6 -7 12c0 2 1 6 7 6">
<animate attributeName="stroke-dashoffset" dur="3s" values="28;0;28;" repeatCount="indefinite">
</animate>
</path>
<path fill="currentColor" fill-opacity="0" d="M12 3C12 3 15.27 5.81 17.34 9.5L6 18.41C5.21 17.24 5 15.91 5 15C5 9 12 3 12 3Z">
<animate attributeName="fill-opacity" dur="3s" values="0;0.3;0" repeatCount="indefinite">
</animate>
</path>
</svg>
</button>
<label class="theme-toggle fun-button" for="themeToggle" aria-label="Toggle dark mode">
<input type="checkbox" id="themeToggle">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none" stroke="currentColor" stroke-dasharray="4" stroke-dashoffset="4" stroke-linecap="round" stroke-linejoin="round" stroke-width="1">
<path d="M13 4h1.5M13 4h-1.5M13 4v1.5M13 4v-1.5">
<animate id="lineMdMoonRisingFilledAltLoop0" fill="freeze" attributeName="stroke-dashoffset" begin="0.7s;lineMdMoonRisingFilledAltLoop0.begin+6s" dur="0.4s" values="4;0">
</animate>
<animate fill="freeze" attributeName="stroke-dashoffset" begin="lineMdMoonRisingFilledAltLoop0.begin+2s;lineMdMoonRisingFilledAltLoop0.begin+4s" dur="0.4s" values="4;0">
</animate>
<animate fill="freeze" attributeName="stroke-dashoffset" begin="lineMdMoonRisingFilledAltLoop0.begin+1.2s;lineMdMoonRisingFilledAltLoop0.begin+3.2s;lineMdMoonRisingFilledAltLoop0.begin+5.2s" dur="0.4s" values="0;4">
</animate>
<set fill="freeze" attributeName="d" begin="lineMdMoonRisingFilledAltLoop0.begin+1.8s" to="M12 5h1.5M12 5h-1.5M12 5v1.5M12 5v-1.5">
</set>
<set fill="freeze" attributeName="d" begin="lineMdMoonRisingFilledAltLoop0.begin+3.8s" to="M12 4h1.5M12 4h-1.5M12 4v1.5M12 4v-1.5">
</set>
<set fill="freeze" attributeName="d" begin="lineMdMoonRisingFilledAltLoop0.begin+5.8s" to="M13 4h1.5M13 4h-1.5M13 4v1.5M13 4v-1.5">
</set>
</path>
<path d="M19 11h1.5M19 11h-1.5M19 11v1.5M19 11v-1.5">
<animate id="lineMdMoonRisingFilledAltLoop1" fill="freeze" attributeName="stroke-dashoffset" begin="1.1s;lineMdMoonRisingFilledAltLoop1.begin+6s" dur="0.4s" values="4;0">
</animate>
<animate fill="freeze" attributeName="stroke-dashoffset" begin="lineMdMoonRisingFilledAltLoop1.begin+2s;lineMdMoonRisingFilledAltLoop1.begin+4s" dur="0.4s" values="4;0">
</animate>
<animate fill="freeze" attributeName="stroke-dashoffset" begin="lineMdMoonRisingFilledAltLoop1.begin+1.2s;lineMdMoonRisingFilledAltLoop1.begin+3.2s;lineMdMoonRisingFilledAltLoop1.begin+5.2s" dur="0.4s" values="0;4">
</animate>
<set fill="freeze" attributeName="d" begin="lineMdMoonRisingFilledAltLoop1.begin+1.8s" to="M17 11h1.5M17 11h-1.5M17 11v1.5M17 11v-1.5">
</set>
<set fill="freeze" attributeName="d" begin="lineMdMoonRisingFilledAltLoop1.begin+3.8s" to="M18 12h1.5M18 12h-1.5M18 12v1.5M18 12v-1.5">
</set>
<set fill="freeze" attributeName="d" begin="lineMdMoonRisingFilledAltLoop1.begin+5.8s" to="M19 11h1.5M19 11h-1.5M19 11v1.5M19 11v-1.5">
</set>
</path>
<path d="M19 4h1.5M19 4h-1.5M19 4v1.5M19 4v-1.5">
<animate id="lineMdMoonRisingFilledAltLoop2" fill="freeze" attributeName="stroke-dashoffset" begin="2s;lineMdMoonRisingFilledAltLoop2.begin+6s" dur="0.4s" values="4;0">
</animate>
<animate fill="freeze" attributeName="stroke-dashoffset" begin="lineMdMoonRisingFilledAltLoop2.begin+2s" dur="0.4s" values="4;0">
</animate>
<animate fill="freeze" attributeName="stroke-dashoffset" begin="lineMdMoonRisingFilledAltLoop2.begin+1.2s;lineMdMoonRisingFilledAltLoop2.begin+3.2s" dur="0.4s" values="0;4">
</animate>
<set fill="freeze" attributeName="d" begin="lineMdMoonRisingFilledAltLoop2.begin+1.8s" to="M20 5h1.5M20 5h-1.5M20 5v1.5M20 5v-1.5">
</set>
<set fill="freeze" attributeName="d" begin="lineMdMoonRisingFilledAltLoop2.begin+5.8s" to="M19 4h1.5M19 4h-1.5M19 4v1.5M19 4v-1.5">
</set>
</path>
</g>
<path fill="currentColor" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 6 C7 12.08 11.92 17 18 17 C18.53 17 19.05 16.96 19.56 16.89 C17.95 19.36 15.17 21 12 21 C7.03 21 3 16.97 3 12 C3 8.83 4.64 6.05 7.11 4.44 C7.04 4.95 7 5.47 7 6 Z" transform="translate(0 22)">
<animateMotion fill="freeze" calcMode="linear" dur="0.6s" path="M0 0v-22">
</animateMotion>
</path>
</svg>
</label>
<main>
<header>
<h1>
<a href="#" class="image-border image-border--mobile" role="button" aria-pressed="false" onclick=" event.preventDefault(); const img = this.querySelector('img'); const isClicked = this.classList.toggle('clicked'); this.setAttribute('aria-pressed', isClicked); img.src = isClicked ? 'me-black-and-white.jpg' : 'me3.webp'; img.alt = isClicked ? 'A colour version of me.' : 'An image of me with a great view.'; ">
<img class="image-mobile" src="me3.webp" alt="An image of me with a great view.">
</a>
<svg class="cv-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
<path stroke-dasharray="64" stroke-dashoffset="64" d="M13.5 3l5.5 5.5v11.5c0 0.55 -0.45 1 -1 1h-12c-0.55 0 -1 -0.45 -1 -1v-16c0 -0.55 0.45 -1 1 -1Z">
<animate fill="freeze" attributeName="stroke-dashoffset" dur="0.6s" values="64;0">
</animate>
</path>
<path d="M14.5 3.5l2.25 2.25l2.25 2.25z" opacity="0">
<animate fill="freeze" attributeName="d" begin="0.6s" dur="0.2s" values="M14.5 3.5l2.25 2.25l2.25 2.25z;M14.5 3.5l0 4.5l4.5 0z">
</animate>
<set fill="freeze" attributeName="opacity" begin="0.6s" to="1">
</set>
</path>
<path stroke-dasharray="8" stroke-dashoffset="8" d="M9 13h6">
<animate fill="freeze" attributeName="stroke-dashoffset" begin="0.8s" dur="0.2s" values="8;0">
</animate>
</path>
<path stroke-dasharray="4" stroke-dashoffset="4" d="M9 17h3">
<animate fill="freeze" attributeName="stroke-dashoffset" begin="1s" dur="0.2s" values="4;0">
</animate>
</path>
</g>
</svg>
George Brook
</h1>
<div class="intro">
<a href="#" class="image-border image-border--desktop" role="button" aria-pressed="false" onclick=" event.preventDefault(); const img = this.querySelector('img'); const isClicked = this.classList.toggle('clicked'); this.setAttribute('aria-pressed', isClicked); img.src = isClicked ? 'me-black-and-white.jpg' : 'me3.webp'; img.alt = isClicked ? 'A colour version of me.' : 'An image of me with a great view.'; ">
<img class="image-mobile" src="me3.webp" alt="An image of me with a great view.">
</a>
<div class="blurb">
<p>
I’m a front-end developer who enjoys building fast, accessible websites with clean, well-structured code. I care about good CSS, thoughtful UI, and making things work smoothly for users and developers alike. I like working with design systems, improving team standards, and exploring how tools like AI can support front-end work.
</p>
<br>
<p>
Most recent personal public project:
<a href="https://devtools-ecru.vercel.app">
https://devtools-ecru.vercel.app
</a>
</p>
</div>
</div>
<section>
<h2>
Education
</h2>
<p>
<strong>
Bachelor of Science (Physics, Upper Second Class Honours)
</strong>
<br>
University of Bath — 2012
</p>
<p>
<em>
Dissertation: Investigating Noise and Underwater Acoustics in the Deep Sea. Built MATLAB algorithms to analyze signal data.
</em>
</p>
</section>
<section>
<h2>
Professional Experience
</h2>
<h3>
Catch Digital (London, UK – Remote)
</h3>
<p>
<strong>
Senior Front-End Developer
</strong>
· March 2022 – May 2025
</p>
<ul>
<li>
Designed and implemented modular front-end systems across enterprise-scale websites.
</li>
<li>
Spearheaded the adoption of atomic design principles and scalable component libraries using Storybook and modern CSS architecture (BEM).
</li>
<li>
Optimized page performance across 20+ websites, reducing load times through code splitting and performance-first tooling.
</li>
<li>
Modernized build pipelines with Webpack, GitHub Actions, and CI/CD workflows, improving developer efficiency.
</li>
<li>
Led the integration of headless CMS platforms and third-party APIs, including secure authentication flows with JWT.
</li>
<li>
Built reusable React components for e-commerce tools like shopping carts and dynamic product filters.
</li>
<li>
Mentored junior developers on JavaScript best practices and accessibility standards.
</li>
<li>
Regularly led client demos and translated complex technical solutions into business-aligned outcomes.
</li>
</ul>
<p>
<strong>
Notable Projects/Clients:
</strong>
</p>
<p>
<em>
My Business Stream (Scottish Water), IOP, Norton Abrasives, Edrington Digital Platform, SES, IAB UK, TTTech Auto, Framestore, Ashmore Group
</em>
</p>
<em>
<small>
<strong>
Reason for Leaving:
</strong>
Company restructure and merger.
</small>
<h3>
Zoocha Ltd (Hertford, UK – Remote)
</h3>
<p>
<strong>
Mid → Senior Front-End Developer
</strong>
· March 2014 – February 2022
</p>
<ul>
<li>
Delivered front-end solutions for high-traffic websites, including public sector and finance projects.
</li>
<li>
Led compliance efforts for accessibility (AAA/WCAG) and legal standards.
</li>
<li>
Developed prototypes and MVPs using the latest front-end stacks.
</li>
<li>
Advocated for and implemented atomic design systems and reusable UI components.
</li>
<li>
Coached team members on writing scalable, maintainable code using modern HTML, CSS, and JavaScript standards.
</li>
</ul>
<p>
<strong>
Notable Projects/Clients:
</strong>
</p>
<p>
<em>
Greater London Authority, TalkLondon, Ofsted Reports, FCA, Falmouth University, Visit Britain, Visit Jersey, Ofsted Parent View
</em>
</p>
<em>
<small>
<strong>
Reason for Leaving:
</strong>
Transition to UK-only office model while based in South Africa.
</small>
</em>
</em>
</section>
<em>
<em>
<section>
<h2>
Technical Proficiency
</h2>
<ul>
<li>
<strong>
Languages & Frameworks
</strong>
<br>
React, Next.js, Vue.js, Svelte, TypeScript, JavaScript (ES6+), HTML5, CSS3, SASS, Tailwind CSS, jQuery, Twig
</li>
<li>
<strong>
Component & UI Development
</strong>
<br>
Storybook, Atomic Design, BEM methodology, Accessible UI (WCAG 2.1/2.2), Semantic HTML
</li>
<li>
<strong>
Testing & Quality Assurance
</strong>
<br>
Jest, React Testing Library, Playwright, Pa11y, Lighthouse, ESLint, Stylelint, Prettier
</li>
<li>
<strong>
Build & Automation Tools
</strong>
<br>
npm, Yarn, Webpack, Vite, Gulp, Grunt, Lint-Staged
</li>
<li>
<strong>
Version Control & Collaboration
</strong>
<br>
Git, GitHub, Bitbucket, Azure DevOps, Jira, Confluence, Agile/Scrum, Code Reviews, Mentorship
</li>
<li>
<strong>
CMS & Platforms
</strong>
<br>
Drupal, WordPress, Prismic
</li>
<li>
<strong>
DevOps & Backend
</strong>
<br>
PHP, PHPStan, Composer, MySQL, Docker, DDEV, Linux, NGINX, Jenkins, AWS (Amplify, EC2, S3), Acquia Cloud, Pantheon, DigitalOcean, Vercel
</li>
<li>
<strong>
Analytics & Monitoring
</strong>
<br>
Google Analytics, Sentry
</li>
</ul>
</section>
<section class="personal-info">
<h2>
More About Me
</h2>
<p>
When I’m not coding, I enjoy endurance running, competitive and recreational tennis, and perfecting my homemade lasagne recipe. I am also passionate about art and music, and love exploring new creative outlets.
</p>
<ul>
<li>
<a href="https://codepen.io/georgebrook/pen/mqexXB" target="_blank" rel="noopener">
Codepen
</a>
</li>
<li>
<a href="https://github.com/georgebrook" target="_blank" rel="noopener">
Github
</a>
</li>
<li>
<a href="https://imgur.com/a/artwork-drf0g" target="_blank" rel="noopener">
Artwork Portfolio
</a>
</li>
<li>
<a href="https://soundcloud.com/zzxxccii" target="_blank" rel="noopener">
Music
</a>
</li>
<li>
<a href="https://www.drupal.org/u/georgebrook" target="_blank" rel="noopener">
Drupal Profile
</a>
</li>
<li>
<a href="https://www.linkedin.com/in/georgebrook/" target="_blank" rel="noopener">
LinkedIn
</a>
</li>
</ul>
</section>
<footer class="site-footer">
<p>
Thank you for visiting my site. I look forward to connecting!
</p>
</footer>
</em>
</em>
</header>
</main>
<em>
<em>
</em>
</em>
</body>
</html>