noise -> signal

000

press any key to skip

Pitch-POC marketing site for a construction-chemicals company (Next.js, SSG)

Problem

UltraChem Infra Solutions Pvt. Ltd. (Nagpur, Maharashtra) needed a web presence to showcase its construction-chemical product catalog, target sectors, and technical resources (catalogue/brochure PDFs, TDS links) to contractors and government-infrastructure buyers, and to capture sales inquiries. Built by Harshal as a pitch POC for the company.

What it does

A fully static corporate website: home, about, products (catalog page plus individually pre-rendered product detail pages with features/applications/TDS download), sectors, resources/downloads, careers, gallery, and contact pages. All content — company info, navigation, categories, 20+ product records, stats, sectors — lives in a single typed TypeScript data module rendered into static pages; GSAP ScrollTrigger powers scroll-reveal animations and stat counters.

Architecture

[web] Next.js 15 App Router site (SSG, React 19) (client)
[data] lib/site-data.ts — typed catalog/content store (store)
[assets] public/assets images, catalogue & brochure PDFs (store)
[gsap] GSAP + ScrollTrigger animation components (worker)

web ──▶ data · imports catalog/nav/company data at build time
web ──▶ assets · next/image AVIF/WebP optimized images, PDF links
gsap ──▶ web · client-side scroll reveal & counters

Simplified — box-and-arrow sketch of the repo structure, not a system diagram.

Decisions

  1. 01

    All site content centralized in one typed data module

    Product catalog, navigation, company info, sectors and stats are plain exported constants with a Product type; pages and the dynamic [slug] route derive everything from it, so content edits never touch components

    Evidence: lib/site-data.ts

  2. 02

    Static pre-rendering per product via generateStaticParams

    Each of the ~20 catalog products is a build-time HTML page with its own generateMetadata (title/description), favoring SEO and load speed over any CMS

    Evidence: app/products/[slug]/page.tsx

  3. 03

    Animation isolated in small 'use client' wrappers

    GsapReveal and StatCounters are the only client components; all pages remain server components, keeping the bundle's client JS limited to GSAP touchpoints

    Evidence: components/gsap-reveal.tsx

  4. 04

    Industrial 'safety yellow/black' design system

    A standalone design.html documents the Yellow Solid Worker theme (palette #fcc200/#1a1a1a) that maps to the tailwind.config.ts safety-* tokens used across every page

    Evidence: design.html

  5. 05

    Image optimization configured explicitly

    next.config.ts enables AVIF and WebP formats for the 16 photographic assets and logo served from public/assets

    Evidence: next.config.ts

The hard parts

  • Content architecture: reconciling a large real-world product catalog (duplicate/near-duplicate SKUs like ultracure-rb7 vs ultracure-rb-7) into clean routes and navigation
  • Keeping pages server-rendered while wiring scroll-triggered GSAP animations and counters through client-component boundaries

Known limitations

  • Contact form has no submission handling — plain uncontrolled form with no action/endpoint or validation (app/contact/page.tsx); map is an explicit placeholder
  • No README, no tests, no license, no CI config in the repo
  • TDS 'download' links point to /resources#downloads anchor rather than real per-product documents (lib/site-data.ts)
  • No CMS or backend — every content change requires a rebuild
  • Duplicate logo.svg exists both in assets/ and public/assets/

Command palette

Jump to a section, project or link