Web
RJ Hair & Nail Studio — a static salon site ported one-to-one to Next.js
A hair and nail salon's site, first built as a static HTML system and then ported page-for-page to Next.js 16 for per-page metadata, sitemap, manifest and a HairSalon JSON-LD service catalogue — same markup, same stylesheet, same motion.
Problem
What needed solving?
The salon books through WhatsApp and Instagram and needed a site that feels like its work — dramatic photography, a full service menu, signature looks — while being findable for local searches. The first version was a static HTML build; the question was how to gain proper SEO (canonical URLs, Open Graph, structured data) without redesigning or re-animating anything the owner had already approved.
Context
Who was it for?
Client site · Hair & nail salon, Rewa (MP)
Approach
- Port, don't rebuild: each HTML page's main content becomes JSX with the same classes, the stylesheet is carried over verbatim, and the original behaviour script loads after hydration — so the preloader, inertial scroll, masked reveals, slanted wipes, sliders and modals behave exactly as before.
- Write a converter that regenerates the Next.js pages and the shared shell from the built HTML site, so either source can be edited and the other regenerated.
- Add what Next.js makes cheap: per-page metadata, canonical URLs, Open Graph and Twitter cards, sitemap, robots, a web manifest and JSON-LD.
- Keep booking where customers already are — a WhatsApp call to action and the Instagram profile — and remember 'saved looks' in the visitor's browser.
Architecture
How the system was designed.
Statically prerendered Next.js 16 pages that render the original HTML as JSX inside a shared shell (icon sprite, preloader, header, footer, modals, cookie bar). The original CSS and behaviour script are served unchanged; a Python converter can regenerate the pages from the HTML source. Site facts and the service menu are data files that also feed the JSON-LD.
Implementation
What was built.
- 01Seventeen routes statically prerendered — home, services, looks, studio, why RJ, how to book, find us, team, offers, latest work, gallery, reels, FAQ, menu, about, contact, privacy — each page a `page-…` class on `<main>` so the original page-scoped styles still apply.
- 02The stylesheet is the original file with only font URLs and two selector families changed, because the page class moved from `<body>` to `<main>`; the behaviour script is loaded with next/script after hydration.
- 03A catalogue of sixteen services in three families, filterable by `?type=`, also emitted as a HairSalon JSON-LD offer catalogue.
- 04Self-hosted licensed typefaces (SangBleu Empire, Euclid Square, Wonder Garden Script) as woff2; photography from the studio's own Instagram posts plus credited stock.
- 05A converter script (`scripts/convert-html.py`) rebuilds the pages and the shell from the HTML site, keeping both versions in step.


AI
Where AI was used and why.
This project did not use AI — a deliberate choice. Not every system needs a model.
Technology
Relevant stack.
- Next.js 16
- React 19
- TypeScript
- Static HTML → JSX converter (Python)
- JSON-LD
- Railway
Outcome
Only factual results.
Outcome to be added. Results are only published here when they can be stated factually — no estimated metrics.
Lessons
Important engineering insights.
- A one-to-one port is a legitimate engineering choice: the owner keeps the approved design and gains the framework's SEO plumbing.
- Moving a page class from body to main is the kind of small change that breaks a whole stylesheet — the `:has()` selector rescued it without rewriting rules.
- Structured data for a service menu is worth building from the same data file the page renders, so the two can never disagree.
Have a project in mind?
Tell me what you're trying to build. I'll come back with an honest view on scope, architecture and the right approach.