Overview
Public brand site for a snack and seed-products company that sells in both Thai and Chinese markets. The site is a brand storytelling experience first and a product catalog second — built around parallax scroll, reveal animations, and a Lottie-driven hero — with practical pages for store locator, partners, FAQs, and certifications behind it. A separate admin CMS lets the brand team update content without redeploying.
What I built
- Bilingual site with a dedicated
/cnChinese-language tree alongside the Thai default - Parallax storytelling using react-parallax + react-scroll-parallax for the brand-promise sections ("ourPromise", "joyfull", "hero")
- Product line pages with Lottie animations and reveal-on-scroll transitions
- "Find us" store locator and partner directory pages
- Certifications page (food-safety / quality marks important for export markets)
- react-type-animation for animated copy in the hero
- Companion admin CMS (separate repo) for the brand team to manage content
Tech stack
- Frontend: Next.js 14 App Router, React 18, Tailwind CSS
- UI primitives: Radix UI (accordion, dialog, popover, select, label)
- Animations: Lottie for centerpiece animations, react-parallax + react-scroll-parallax for scroll effects, react-awesome-reveal for section reveals, react-type-animation for animated text
- Carousels: Embla, Slick, react-responsive-carousel
- State: Zustand
- Image optimization: Sharp for production builds
My role
Built the public site end-to-end and the admin CMS that feeds it. Set up the bilingual structure so adding a third locale would be a copy-and-translate operation, not a rewrite. The parallax-heavy design was a careful balancing act — the brand wanted motion as a feature, but the audience includes mobile users on slower connections.
What I learned
The hardest part of parallax-driven brand sites isn't the parallax — it's making the page still work and feel right when motion is reduced or the device can't keep up. Once I started checking prefers-reduced-motion and gating heavy parallax sections on viewport / device capability, the site felt premium on the high-end and acceptable on the low-end instead of being slow everywhere. The bilingual setup also taught me to plan for translation as content, not as code — keeping copy in JSON-ish locale files instead of inline JSX meant the brand team could send translations to a translator without touching the codebase.



