Corporate site for XunkeDa Co., Limited (Hong Kong) — software development and IT outsourcing for business: custom software, web and mobile products, API and system integration, business automation, cloud, and AI and data solutions.
Built with semantic HTML5 + Tailwind CSS v3 (compiled) + vanilla JS. No frameworks, no runtime
dependencies, no third-party requests. Light, minimal theme: white / mist grounds, navy #0B1530
text, electric blue #1A56F0 accent; Manrope + Inter + JetBrains Mono self-hosted.
Pages: index.html (single-page, anchor navigation) · privacy.html · terms.html.
npm run setup # install deps + copy fonts + build CSS (first time)
npm run serve # preview at http://localhost:3000Or step by step:
npm install # install dev tooling
npm run fonts # copy self-hosted woff2 into assets/fonts/
npm run build # compile + minify dist/styles.css
npx serve . # or: python3 -m http.server 8000While editing styles / markup, run the watcher:
npm run dev # rebuilds dist/styles.css on saveEditing the design? Utility classes live in the three HTML files and
js/; design tokens are intailwind.config.js; reusable component classes, fonts and motion are insrc/input.css. After any change to those, re-runnpm run build(or keepnpm run devrunning) sodist/styles.cssstays in sync.
Serve from the root. In-page links are root-relative (
/#about,/#contact, logo/#top), so the site must be previewed over HTTP at the site root (npm run serve), not opened viafile://.
The site is pure static files — dist/styles.css and the fonts are committed, so no build is
required to serve it. Absolute URLs (canonical, Open Graph, sitemap, robots, JSON-LD) assume
https://xunkedatech.com/ — update them if the live domain differs.
Publish only the site files. Everything in the publish directory becomes a public URL, so the
repository root (with node_modules/, src/, scripts/, the configs, this README and
HANDOFF.md) must not be served as-is. The Render blueprint stages the served files into
public/ (git-ignored) at build time; do the same on any other host.
- Push the repository to GitHub / GitLab.
- In Render: New → Blueprint (or New → Static Site) and connect the repo.
render.yamldeclares a static service namedxunkedatech: buildnpm install && npm run build, then copyindex.html,privacy.html,terms.html,robots.txt,sitemap.xml,site.webmanifest,dist/,js/andassets/(plus a rootfavicon.ico) intopublic/; publish directorypublic, Node 20,autoDeploy: true. - Headers set by
render.yaml:/assets/fonts/*→Cache-Control: public, max-age=31536000, immutable;/assets/img/*and/assets/logo/*→max-age=86400(icons, OG image and logo keep their file names when replaced);/dist/*and/js/*→max-age=3600, must-revalidate; HTML is not cached. Every path gets a strictContent-Security-Policy(default-src 'self'; inline styles allowed for thestyle="--i:n"attributes;img-src data:for the select chevron),X-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-originandX-Frame-Options: DENY. - Add the custom domain
xunkedatech.compluswww→ apex redirect; Render provisions TLS.
- Cloudflare Pages / Netlify / GitHub Pages / S3 + CloudFront: use the same build command as
render.yaml(build, then stage intopublic/) and set the publish directory topublic. If the host can only publish the repository root, every committed file is then a public URL — keep README / HANDOFF free of anything you would not put on the site. - Serve
index.htmlat/and keep the/assets,/distand/jspaths. - Re-create the headers above in the host's own config if you want them (they are not required for the site to work).
About.md (the internal brief) is git-ignored, so it never reaches the repository or the host.
After the first deploy, confirm that https://xunkedatech.com/About.md, /HANDOFF.md,
/README.md, /package.json and /node_modules/ all return 404.
index.html Home: hero, intro, about, services, technologies, process, industries, contact
privacy.html Privacy Policy (Hong Kong PDPO)
terms.html Terms of Use
src/input.css @tailwind + @font-face + component classes + motion + reduced-motion
tailwind.config.js Design tokens (colours, fonts, clamp type scale, radii, shadows, keyframes)
.browserslistrc Browser targets for autoprefixer / cssnano (keeps -webkit-backdrop-filter for Safari < 18)
dist/styles.css Compiled + minified stylesheet (committed)
js/main.js Scroll-reveal, sticky nav, mobile menu, scroll-spy, mailto contact form
assets/fonts/ Self-hosted Manrope (700/800), Inter (400/500), JetBrains Mono (400) woff2
assets/img/ favicon.svg/.ico, apple-touch-icon.png, og-image.svg/.png
assets/logo/ Interim brand mark + wordmark SVG
scripts/gen-icons.mjs Regenerates the raster icons / OG image from the SVGs (see below)
site.webmanifest PWA manifest (name, icons, theme colour)
robots.txt Allow all + sitemap pointer
sitemap.xml /, /privacy.html, /terms.html
render.yaml Render static-site blueprint (build + public/ staging, cache/security headers, Node version)
The header (<!-- SHARED:header --> … <!-- END SHARED -->) and footer (<!-- SHARED:footer -->
… <!-- END SHARED -->) blocks are byte-identical across the three HTML files — edit them in
index.html and copy to the legal pages.
- English only. The Chinese legal name appears only in the shared footer
(
<span lang="zh-Hant">, once per page) and once as the JSON-LDalternateName. The owner may remove both. - No fabricated facts. Never state employee counts, "years in business", office counts, named
clients or any vanity number. No KPI, count, latency, revenue or percentage figures in decorative
UI. Ordinal indices (
01–08), HTTP status codes (200 OK) and API paths are allowed. - Positioning. XunkeDa is described as a software development company / Software Development & IT Solutions — never with the generic technology-company label used in the original brief.
- Self-contained. No external images, stock photos, web-font CDNs, analytics or third-party requests. Illustrations are inline SVG / CSS compositions only.
- No email address anywhere in visible copy,
hrefattributes, this README orHANDOFF.md. The only address in the project is theCONTACT_EMAILconstant injs/main.js. - Footer always carries
XunkeDa Co., Limited, the registered office (Flat 08Q22, 19/F, China Shipbuilding Tower, 650 Cheung Sha Wan Road, Kowloon, Hong Kong) and the Privacy Policy / Terms of Use / Contact links. - Verbatim copy. Service blurbs, the technology list, process step names, industries, hero and intro copy, form fields and the submit label are taken word-for-word from the brief.
The form is mailto: only: submitting validates the fields, then opens the visitor's email client
pre-filled with the message, addressed to the CONTACT_EMAIL constant in js/main.js. Nothing is
sent by the site itself and no third-party service is involved. If you later want server-side
delivery (Formspree, Netlify Forms, your own endpoint), wire it into initContactForm() in
js/main.js — the markup does not need to change.
- Recipient inbox — replace the placeholder value of the
CONTACT_EMAILconstant injs/main.jswith the confirmed company inbox and send a real test submission. The address must never be printed in visible copy, the footer,hrefattributes, this README orHANDOFF.md. - Raster assets — regenerate
og-image.png,favicon.icoandapple-touch-icon.pngfrom the final SVGs (see below) and hand-check the OG card in a social debugger. - Legal review — have a Hong Kong legal adviser review
privacy.htmlandterms.html, update the "Last updated" dates, then remove the twoTODO(pre-launch)HTML comments. - Technologies — confirm the Technologies section lists only stacks the company will actually deliver.
- Registered office — confirm the full address string character for character (footer, Contact, JSON-LD, legal pages); the About card deliberately shows a shortened form (building and street only). Decide whether the Chinese legal name stays.
- Domain — canonical, Open Graph, sitemap, robots and JSON-LD all use
https://xunkedatech.com/; change them if the live domain differs. - Analytics / cookies — the Privacy Policy states that the site sets no cookies and runs no analytics. If either is ever added, rewrite Privacy Policy section 2 and add a cookie notice.
- Repository + hosting —
git init, first commit, push, create the Render service fromrender.yaml, attach the domain and thewwwredirect, confirm TLS; updatesitemap.xmllastmodat release. - Final checks — re-run the content greps and the SHARED-block diff from
HANDOFF.mdon the release commit; confirm/About.md,/HANDOFF.md,/README.mdand/node_modules/are 404 after deploy. - Logo —
assets/logo/xunkeda-mark.svg,assets/logo/xunkeda-wordmark.svgand the inline marks in the HTML are an interim brand mark. Replace with the official vector if one is produced, then re-run the icon generation.
The raster assets (favicon.ico, apple-touch-icon.png, og-image.png) are committed. Only
regenerate them if you change the source SVGs:
npm i --no-save sharp png-to-ico # one-off tooling; --no-save keeps package.json unchanged
node scripts/gen-icons.mjsThe generated og-image.png rasterises assets/img/og-image.svg with the system fallback fonts
(Helvetica Neue / Arial for Manrope, Menlo for JetBrains Mono). For a pixel-perfect social card,
export og-image.png (1200 × 630) by hand from a browser or design tool with the brand fonts
installed.
Self-hosted via the @fontsource/manrope, @fontsource/inter and @fontsource/jetbrains-mono
packages; npm run fonts copies the five latin woff2 subsets into assets/fonts/. Only
manrope-latin-800 and inter-latin-400 are preloaded; all faces use font-display: swap.
Semantic landmarks, skip link, single <h1> per page, ARIA on the navigation, a modal mobile menu
(inert page behind it, Tab loop, Esc), a labelled form with live errors, always-underlined in-text
links, visible focus rings on light and dark grounds, AA-contrast text everywhere, and full
prefers-reduced-motion support. Targets: index.html ≤ 60 KB, dist/styles.css ≤ 48 KB minified,
js/main.js ≤ 8 KB (raised from the plan's 6 KB to fit the menu focus management and form
handling; currently 7.99 KB, 2.6 KB gzipped), fonts ≤ 125 KB, zero raster and zero third-party
requests on first load; Lighthouse mobile Performance ≥ 95 and Accessibility / Best Practices /
SEO 100.