National E-Waste Circularity Platform
National E-Waste Circularity Platform: technical SEO and web implementation
Figma UI/UX Design, Asset Extraction, Static Web Development, Technical SEO, Accessibility & Next.js Rebuild
Operational Workflow & State Machine
End-to-End Pipeline- 01Receive the approved design file
- 02Audit the approved design
- 03Rebuild as static HTML/CSS/JS
- 04Verify the build
- 05Deploy
Overview
Malaysia's No. 1 E-Waste Recycling Company is an e-waste collection and recycling service in Malaysia, operated in partnership with Established Malaysian technology company, which presents itself as the country's #1 authorised collector, recognised by Jabatan Alam Sekitar (JAS): doorstep pickup, free shipping through Pos Malaysia, a 24/7 drop-off point in Cyberjaya, and cashless rewards. The site is a comprehensive single-page digital gateway covering residential and corporate e-waste pickups, real-time device pricing, accepted electronics catalogs, enterprise recycling compliance, and its environmental credentials.
I built the production website from the design file the client approved as final: a fast, zero-bloat static page (1,076 lines of markup, 534 lines of CSS and 228 lines of JavaScript bundled by Vite), and then rebuilding it as a typed Next.js application.
Problem
A recycling and trade-in service depends on people trusting it enough to hand over a device and the data on it. For a service that leans on its standing with Jabatan Alam Sekitar, the page has to make the process, the pricing, the eligibility rules and the handling of personal data legible before someone commits to anything.
The approved design existed only as a self-extracting design-tool bundle: fonts, images and markup encoded as base64 inside script blocks, unpacked in the browser at runtime, with React and Babel pulled from a CDN and a runtime that re-rendered inline styles on every state change. It demonstrated the design. It was not a website anyone should ship.
Context
The client's decision was that one design file was final and every earlier revision was superseded. That made the brief unusually precise: not build something like this, but ship exactly this, correctly.
A locked design is the interesting constraint. Meeting a long list of content, search and accessibility requirements is straightforward if you are allowed to add sections. Meeting them inside a design nobody may change is a different problem, and it is the one this build was.
My Role
My role was Figma UI/UX Designer and Website Developer for the Malaysia's No. 1 E-Waste Recycling Company homepage. The engagement spanned both visual design in Figma and front-end implementation: translating client brand requirements into responsive UI components, and building a fast, accessible production website that earns trust quickly and holds up on mobile.
On the design side, I prototyped the interface in Figma (Malaysia's No. 1 E-Waste Recycling Company V2.3), refining component typography, color contrast, and layout hierarchy. On the engineering side, I extracted assets, eliminated 250 kB of unnecessary prototype framework runtime, and authored clean, semantic HTML, CSS, and vanilla JS with full technical SEO and Schema.org structured data. Afterwards, I created a typed Next.js 16 / React 19 rebuild in strict TypeScript with 21 modular section components, a booking dialog with focus management, and accessible landmarks.
Developed while employed at Established Malaysian technology company, which operates Malaysia's No. 1 E-Waste Recycling Company. The static Vite build is the live deployed production site (erth-homepage.vercel.app); the typed Next.js and TypeScript rebuild is a local engineering asset.
Engineering Approach
The stack decision was to remove rather than add. A single static page does not need React, Babel, a CDN dependency or a render pass before first paint. Dropping all of it took roughly 250 kB of JavaScript out of the page and left 3.7 kB that does nothing but handle interaction.
The inline styles were deliberately kept. In the approved file the inline style attributes are the design specification: every dimension, colour and clamp() lives there. Rewriting a thousand of them into class names would have introduced visual drift for no functional gain, so the markup was preserved and only the parts a static file cannot express moved into CSS.
Three things had to move. Hover attributes the prototype's runtime interpreted became real hover rules. Open and closed state the prototype expressed by rewriting inline display became hidden, aria-expanded and a class, with CSS deciding appearance. And the desktop and mobile split the prototype computed from window.innerWidth in JavaScript became a media query at the same breakpoint, so the correct layout is painted on the first frame instead of after hydration.
Fixing the prototype
Rebuilding a design file section by section surfaces defects that a demo hides. Four were real enough to fix.
The page wrapper closed early, part-way down the document, so every section after it never inherited the light text colour. One heading rendered black on a near-black background. The colours now live on the body element.
A dialog contained an iframe whose source was an unresolved template binding, so every page load fetched a URL that did not exist. No booking form was configured, so the iframe is gone and the contact-channel list the design already provided is the dialog body.
Six links pointed at the section they were already inside. They now resolve to the action they describe. And two grid definitions forced horizontal scrolling below 400px, which a minmax floor and a released column span fixed.
Verifying the build
A hand-built static page has no type checker, so the guarantees had to be written. A post-build script runs as part of every build and fails it on a referenced asset missing from the output, an in-page link or aria-controls pointing at an id that does not exist, an absent required head tag, JSON-LD that does not parse, an image with no alt text or no intrinsic size, more or fewer than one h1, or any prototype artefact surviving into the output.
That last check is the one that matters most on a project like this. A template binding or a generated class name that leaks into production is invisible in review and obvious to a visitor, and it is exactly the kind of thing a rebuild leaves behind.
Technical SEO
The head block was built out from nothing: the specified title and meta description, a canonical URL, robots directives, a full Open Graph set with the locale declared as Malaysian English, and a large-image Twitter card, plus robots.txt, sitemap.xml, a web manifest and a full favicon set.
Three JSON-LD blocks ship. An Organization node also typed as a recycling centre, carrying the alternate name, legal name, logo, contact details, a full postal address for the Cyberjaya premises, the areas served and a verified social profile. An FAQPage node mirroring the sixteen questions visible on the page. And a WebSite node stating the site name and alternate name.
Structure was treated as information architecture rather than decoration: one h1, section-level h2s, card-level h3s, descriptive alt text, and an internal-linking pass that found several sections were unreachable from the navigation despite being on the page. All page content is in the static HTML; nothing depends on JavaScript to be crawlable.
GEO / AI-search readability
Content an AI system can read and answer from directly is a different target from ranking a page. The approach was to test it rather than assert it: nine questions a visitor actually asks, each checked for whether the page answers it self-containedly.
Where a section needed to survive being extracted on its own, it was written to do so. The block explaining the difference between disposal and recycling defines both terms, states the distinction and says why it matters, so an answer engine quoting only that block still produces something correct.
Recognition claims were restructured to carry who recognised the achievement, when, and where it can be verified, because for an AI system an unattributed claim and an invented one look the same. The FAQ was expanded from the objections customers actually raise rather than from a keyword list, and the structured data mirrors exactly what a reader sees.
Content accuracy
A consistency pass across the page found six contradictions and unsupported claims. These were raised for a client decision rather than resolved unilaterally, because picking one reading of a business rule is not a developer's call to make.
One was a headline figure that appeared to confuse two different units: a large number presented as currency where the cited source reported it as a weight. Catching that before publication mattered more than any markup change in the engagement.
The working stance throughout was to verify, soften, or omit. No award, statistic, certification, testimonial or coverage claim was introduced that the source material did not support.
Performance and accessibility
Every font and image is self-hosted, so the page makes no third-party requests at all. Photographic and illustrative assets were re-encoded to WebP and the largest ones given srcset variants, taking the image payload from 12.0 MB to 2.7 MB. Every image carries intrinsic width and height so nothing shifts as they arrive, below-the-fold images are lazy, the hero backdrop is marked high priority, and the two Latin font subsets are preloaded.
On accessibility: a skip link, main, nav, footer and aside landmarks, accessible names on sections carrying no heading, a visible focus ring on every interactive element, aria-expanded and aria-controls on all disclosures and dropdowns, Escape and focus trapping in both dialogs with focus restored to the opener, keyboard-operable navigation dropdowns, underlines on inline links that colour alone did not distinguish, and prefers-reduced-motion honoured. axe-core reports zero violations in the default, mobile, menu-open, dialog-open and disclosure-open states.
Outcome
The website development is complete. The production homepage is built, verified and deployed on Vercel, serving the approved design as static files with no third-party requests, a passing post-build check, and a head block carrying full metadata and three structured-data blocks where previously there were none.
It is recognisably the same design the client approved. What changed is everything underneath it: a quarter of a megabyte of prototype JavaScript gone, an image payload cut by more than three quarters, four real defects fixed, and a build that refuses to ship if any of that regresses.
What's live, and what isn't
“It exists in the repository” and “it runs in production” are different claims. This is the difference, stated rather than left to be assumed.
- ImplementedProduction homepage buildComplete and deployed on Vercel. Static HTML, CSS and vanilla JavaScript bundled by Vite 7; the source is public on GitHub.
- ImplementedTitle, meta description, canonical, robotsAll present in the shipped page; none existed before.
- ImplementedOpen Graph and Twitter cardFull Open Graph set with Malaysian English locale, and a large-image Twitter card.
- ImplementedStructured dataThree JSON-LD blocks: Organization / RecyclingCenter, a sixteen-question FAQPage, and WebSite.
- ImplementedSemantic landmarks and accessibilitySkip link, main / nav / footer / aside landmarks, focus management in both dialogs. axe-core reports zero violations across five interaction states.
- ImplementedPerformance passSelf-hosted fonts and images, WebP with srcset, intrinsic sizing, lazy loading. Image payload 12.0 MB to 2.7 MB.
- ImplementedPost-build verificationRuns on every build and fails it on a missing asset, dead in-page link, missing head tag, unparseable JSON-LD, image without alt or intrinsic size, or a surviving prototype artefact.
- Built, not liveNext.js and TypeScript rebuildThe whole page rebuilt in Next.js 16, React 19 and strict TypeScript, with typed content and structured data. Complete locally; not deployed and not yet pushed.
- Not connectedFree-pickup eligibility wordingA content question, not a build one. Two readings of the eligibility rule appear in the client-approved copy; it was raised for a ruling and both are carried through as supplied rather than silently picked between.
- Built, not liveGallery and press-outlet imageryIntentional placeholders in the approved design, labelled as awaiting photography and carried through as-is.
Technical stack
Source
Implementation
Rebuild (in progress)
Search & structured data
Performance & accessibility
Quality & platform
Limitations
- The content and SEO strategy was supplied by the client. This engagement was the production build and the requirements-compliance implementation, not the design or the strategy.
- Two sections are placeholders in the approved design pending client-supplied photography, and are carried through rather than invented.
- One eligibility rule is stated two ways in the approved copy and remains a client content decision.
Source and further reading
Finished the technical breakdown?
Return to the concise HR overview or discover other projects in the portfolio.
Writing from this work
Writing a Page an AI Answer Engine Can Quote Correctly: GEO on a Locked Design
Implementing a GEO requirement on a locked design: test the questions visitors ask, make answers self-contained, attribute claims, and escalate contradictions.
Vercel or a Self-Hosted Ubuntu Box? How I Chose Hosting App by App
Eight deployed apps, three hosting shapes: Vercel for pages and serverless APIs, a self-hosted Ubuntu box for a stateful API, and a hybrid for a model Vercel can't run.
Structured Data for a Local Recycling Business: Organization, RecyclingCenter and an FAQPage That Matches the Page
Turning a client's schema requirements into JSON-LD for a Malaysian e-waste service: Organization plus RecyclingCenter, and an FAQPage that mirrors the visible FAQ.
Baseline Security Headers in Next.js, and Why the CSP Waited
Adding five response headers to a Next.js site that served none, why the Content-Security-Policy was deliberately deferred, and a nonce-free CSP on another app.
Porting a Static Page to Next.js Without Visual Drift
Rebuilding a finished page in Next.js 16 and Tailwind 4 so it looks identical: the font fallback, image optimiser and class-conflict traps, and how drift was checked.
Implemented, Available, Not Connected: Writing Honest Status Into Project Docs
"It exists in the repository" and "it runs in production" are different claims. The three-state status model I use across my projects, with real rows from each.
Canonicals That Pointed at a Redirect: www vs Apex, Sitemaps and Permanent Redirects in Next.js
Every canonical, og:url and sitemap entry on this site named a URL that 308-redirected. The fix, plus the sitemap, feed and redirect decisions made around it in Next.js.
Building Software in Cyberjaya: The Development Environment Behind the Work
What a production operations system, a client website, an AI research assistant and a vision inspector actually get built on, from a laptop in Cyberjaya: the machine, the stack, where things are hosted, and the local details that shaped the code.
Cutting a Page's Image Payload From 12 MB to Under 3 MB
The performance and accessibility pass on a production homepage: what was actually slow, what fixed it, and why most of it was not clever.
Verifying a Static Site You Built by Hand
Hand-written HTML has no type checker and no test runner. On a production build I wrote the guarantees instead, as a post-build script that fails the build.
Rebuilding a Design-Tool Prototype as a Production Website
An approved design arrived as a self-extracting bundle running React from a CDN. Shipping it meant removing almost everything and keeping the part that was actually the specification.
Designing for Desktop and Mobile Before Development
Planning responsive behavior as part of the design phase, instead of leaving it as a problem for development to solve alone.
Translating Figma Components Into Reusable Code
How design components in Figma map to reusable UI components in code, and where that mapping gets harder than it looks.
From Figma Design to Production Website
What actually happens between a finished Figma design and a working, deployed website.
Designing a Website in Figma Before Development
Why doing the design work in Figma first, rather than designing in the browser, changes how the build goes.