Lumina documentation

A 24-page agency and portfolio template built with HTML5, CSS3, vanilla JavaScript and Bootstrap 5. No other framework, no build step required, and no network connection needed to run it.

1. Getting started

The HTML files in the root of the template are the template. Open any of them in a browser and it works — there is nothing to install and no server to start.

  1. Unzip the download.
  2. Open index.html in a browser to check everything looks right.
  3. Edit the HTML directly, or use the source layout described in section 10 if you would rather change the header once instead of twenty-four times.
  4. Upload the whole folder to any static host.

Optional local server. Some browsers restrict file:// pages. If a font or script does not load when you open a file directly, serve the folder instead: npx serve . or python3 -m http.server.

2. File structure

lumina-html-template/
├── *.html                  24 ready-to-edit pages
├── assets/
│   ├── css/
│   │   ├── style.css       design system + every component
│   │   ├── style.min.css   minified copy
│   │   ├── fonts.css       @font-face rules (generated)
│   │   └── fonts.min.css
│   ├── js/
│   │   ├── main.js         all interactions, commented
│   │   └── main.min.js     minified copy
│   ├── img/                25 generated SVG placeholders
│   ├── fonts/              8 self-hosted woff2 files
│   └── vendor/             Bootstrap, Swiper, Lenis + licences
├── src/                    sources for the optional build
│   ├── partials/           head, header, footer, scripts
│   ├── pages/              body content, one file per page
│   └── icons.json          the 45 icons this template uses
├── tools/                  asset, vendor, icon and minify scripts
├── docs/                   this documentation
├── build.js                assembles src/ into the root HTML
└── README.md

3. The 24 pages

PageFileNotable
Home — Agencyindex.htmlRotating headline, process rows, slider
Home — Portfoliohome-portfolio.htmlSplit hero, experience list
Home — Studiohome-studio.htmlTabs, skill bars
Aboutabout.htmlValues, stats, team preview
Servicesservices.htmlNumbered rows, accordion
Service Detailsservice-details.htmlSticky sidebar
Portfolio Gridportfolio.htmlCategory filter
Portfolio Masonryportfolio-masonry.htmlCSS columns, lightbox
Case Studyportfolio-details.htmlResult stats, next project
Teamteam.htmlHover social bar
Team Memberteam-details.htmlFocus areas, counters
Pricingpricing.htmlMonthly / yearly switch
Testimonialstestimonials.htmlFilterable reviews
Careerscareers.htmlJob cards, benefits
Job Openingcareer-details.htmlApplication form
Journal Gridblog.htmlFeatured post, pagination
Journal Listblog-list.htmlFilterable list rows
Articleblog-details.htmlContents sidebar, author
FAQfaq.htmlThree accordion groups
Contactcontact.htmlValidated form
Privacy Policyprivacy.htmlSticky contents
Terms of Serviceterms.htmlSticky contents
404404.htmlNo header or footer
Coming Sooncoming-soon.htmlCountdown, subscribe

4. Colours & themes

Every colour is a CSS custom property declared at the top of assets/css/style.css. Change the accent and the buttons, links, icons, badges, focus rings and gradients all follow.

:root {
  --lu-accent: #ff4d2e;        /* drives the whole template */
  --lu-accent-ink: #ff4d2e;    /* the accent used as text */
  --lu-accent-fill: #e11d00;   /* the accent behind white text */
  --lu-bg: #0a0a0c;
  --lu-bg-elev: #121216;
  --lu-text: #f4f4f1;
  --lu-text-muted: #8f8f99;
  --lu-line: rgba(244, 244, 241, 0.1);
}

The accent is three tokens rather than one, because a single colour cannot do all three jobs and still meet WCAG AA. --lu-accent is the brand colour and paints lines, dots, glows, the progress bar and the rotating word in the hero headline — display-size text needs only 3:1, and the brand colour gives 3.1:1 even on the light background. --lu-accent-ink is the accent used as text; it stays the brand colour on dark and darkens to #c81500 in the light theme, where the bright one reads at only 3.1:1 on paper. --lu-accent-fill is the accent behind white text — the primary button, the skip link, the pricing badge — because white on #ff4d2e is 3.3:1 and needs 4.5:1. If you change the accent, pick all three: a light brand colour, a darker one for text on light surfaces, and one dark enough to carry white.

Light theme

The same names are redefined under [data-theme="light"]. The toggle in the header writes the choice to localStorage, and a small script in <head> applies it before the first paint so the page never flashes.

To ship light as the default, change <html lang="en" data-theme="dark"> to data-theme="light" on every page — or once in build.js if you use the build.

5. Typography

RoleFamilyToken
DisplaySyne 600/700/800--lu-font-display
BodyInter 400/500/600--lu-font-body
LabelsJetBrains Mono 400/500--lu-font-mono

All three are self-hosted in assets/fonts/ under the SIL Open Font License, with @font-face rules generated into assets/css/fonts.css. Nothing is fetched from Google Fonts at runtime.

Swapping a family

  1. Install the replacement: npm i @fontsource/your-font
  2. Edit the FAMILIES array in tools/vendor.js
  3. Run npm run vendor
  4. Update the token in style.css

Sizes use clamp(), so headings scale smoothly between phone and desktop without per-breakpoint overrides.

Watch the display size. The masked line reveal clips anything wider than its column. A hero that shares its row with another column should carry lu-hero--split, which uses a smaller scale.

6. Icons

Icons are inlined as plain <svg> when the page is built, so there is no icon library and no runtime pass over the DOM. The 45 icons used here come from Lucide and live in src/icons.json.

Adding an icon

  1. Put a placeholder in your markup: <i data-lucide="rocket"></i>
  2. Run npm run icons to extract it
  3. Run npm run build

Editing the root HTML by hand instead? Copy an existing <svg> and swap its paths for any 24×24 icon on a 2px stroke grid.

Names change between Lucide versions. If npm run icons reports one as not found, look up its current name — home became house and unlock became lock-open, for example.

7. Images

The 25 files in assets/img/ are abstract SVGs generated by tools/gen-assets.js. Alongside them sits og.jpg, the 1200×630 social-share card referenced by og:image on every page — replace it with your own and update the URL in src/partials/head.html. No stock photography is bundled, so there is nothing to license before you redistribute or sell a site built on this template.

Replacing them with real photography: keep the aspect ratios.

UseRatioFiles
Portfolio tiles4 : 3work-1…8.svg
Article thumbnails16 : 10post-1…6.svg
Team portraits3 : 4member-1…8.svg
Wide features16 : 9feature-1…2.svg

Every <img> already carries width, height and loading="lazy". Keep those attributes — they are what stops the layout shifting while images load.

8. Components

ComponentMarkup hookNotes
Scroll revealdata-revealup (default), left, right, zoom, fade; delay with --d
Line reveal.lu-linesSplits the heading on <br>
Counterdata-count="140"Decimals respected
Word rotator.lu-rotatorOne <span> per word
Filterdata-filter-bar + data-catWorks for work, posts, reviews
Accordion.lu-accdata-single="false" allows several open
Tabsdata-tabsARIA tablist, arrow keys
Skill bardata-pct="96"Fills when scrolled into view
Sliderdata-swiperdata-per-view sets desktop columns
Lightboxdata-lightbox="path"Arrow keys, Escape, focus restored
Searchdata-search-openIndex is SEARCH_INDEX in main.js
Cookie bar.lu-cookieChoice stored in localStorage
Countdowndata-countdown="ISO date"Used on Coming Soon
Pricing switchdata-billingdata-monthly / data-yearly

Example

<div data-reveal>Fades up when it enters the viewport</div>
<div data-reveal="left" style="--d: 120ms">Slides in, slightly later</div>

9. Forms

Four forms ship with the template: contact, job application, newsletter and the Coming Soon subscribe box. All are validated in the browser and none of them post anywhere — that part is yours to wire up.

Open assets/js/main.js, find initForms(), and replace the success branch:

if (ok) {
  const res = await fetch("/api/contact", {
    method: "POST",
    body: new FormData(form),
  });
  // show your own confirmation
}

Any endpoint works — a serverless function, Formspree, Basin, or your own backend. Add data-validate to any new form to get the same validation behaviour.

10. Right-to-left

The template ships an RTL stylesheet, assets/css/rtl.css. Most of the layout already uses logical properties — padding-inline, margin-inline, inset-inline — so the file only restates the genuinely directional rules and stays under 4 KB.

Mirroring a page takes two changes, and both are already marked in every page’s <head>:

<html lang="ar" dir="rtl" data-theme="dark">

<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="assets/css/rtl.css">   <!-- uncomment this -->

index-rtl.html is a working example: it is index.html with exactly those two changes and nothing else. Open the two side by side to see what moves.

The example keeps its English copy on purpose, so you can compare it with the original. One thing to expect while it does: a full stop after Latin text lands on the left in an RTL context. That is the browser’s bidirectional algorithm behaving correctly, and it goes away as soon as the text is Arabic, Hebrew, Farsi or Urdu.

Checked in RTL across all 24 pages: no horizontal scroll, and nothing escaping the viewport.

11. Build tools

Optional. The root HTML files are complete on their own; the build exists so shared markup lives in one place while you work.

CommandDoes
npm run buildAssembles src/ into the 24 root pages
npm run build:minSame, pointing at the minified assets
npm run minifyRegenerates the .min files
npm run iconsRe-extracts used icons into src/icons.json
npm run assetsRegenerates the SVG placeholders
npm run vendorRe-copies libraries and fonts from node_modules
npm run setupAll of the above, in order
npm run serveServes the folder locally

Page titles and meta descriptions live in the MANIFEST array in build.js, alongside the filename. Add an entry there and a matching file in src/pages/ to create a new page.

12. Going live

  1. Replace https://example.com in the canonical, Open Graph and Twitter tags. They are in src/partials/head.html, or in each page's <head>.
  2. Add a real assets/img/og.jpg at 1200×630 for social sharing.
  3. Replace the placeholder contact details, addresses and the example.com email addresses.
  4. Have a lawyer review privacy.html and terms.html. They are drafting aids, not legal advice.
  5. Run npm run build:min for the minified build.
  6. Upload everything except node_modules/.

Any static host works: Netlify, Vercel, Cloudflare Pages, GitHub Pages, S3, or ordinary shared hosting. There is no server-side code.

13. Accessibility

  • Semantic landmarks throughout, one <h1> per page, headings in order
  • Skip-to-content link as the first focusable element
  • Visible focus rings on every interactive element
  • aria-expanded, aria-controls, aria-selected and aria-pressed on toggles
  • aria-live status messages on forms
  • Dialogs trap nothing away from you: Escape closes, focus returns
  • Full prefers-reduced-motion support — reveals, marquees, smooth scroll and autoplay stand down
  • A <noscript> block renders the whole site without JavaScript
  • No interactive element nests inside another
  • On phones every control — buttons, the menu, filters, pagination, breadcrumbs, social and footer links — is at least 44 × 44 px. Links inside a sentence keep their natural size, as WCAG allows.
  • The team cards’ social row is revealed on hover with a mouse and shown outright on a touch screen, so it is never out of reach

If you add content, keep contrast in mind in both themes, and give every image a meaningful alt — or an empty one when it is purely decorative.

14. FAQ

Do I need Node to use this?

No. The root HTML files work as they are. Node is only for the optional build and asset scripts.

Can I use it for a client project?

Yes, under your purchased licence. One regular licence covers one end product.

Why is there no jQuery?

Nothing here needs it. Everything is plain modern JavaScript, which keeps the payload small and removes a dependency to maintain.

Can I use Bootstrap’s JavaScript components?

Yes. Lumina’s own script runs the menus, tabs, accordions and sliders, so Bootstrap’s JavaScript isn’t loaded by default — that keeps every page lighter. The full bundle still ships in assets/vendor/bootstrap.bundle.min.js. To use a modal, dropdown, tooltip or any other Bootstrap component, load it before the template script:

<script src="assets/vendor/bootstrap.bundle.min.js" defer></script>

Add that line to each page that needs it, or once to src/partials/scripts.html if you rebuild with node build.js — the line is already there, commented out.

How do I remove an animation?

Delete the data-reveal attribute, or remove the .lu-lines class from a heading. Page scrolling is native; Lenis only animates in-page anchor links. To turn that off, remove the Lenis <script> tag — the code checks for it and falls back cleanly.

Can I use it with WordPress or another CMS?

The markup is plain HTML and easy to port into templates, but this package is a static template only. No theme files are included.

My contact form does nothing.

That is by design — see section 9. It validates and stops; you connect it to a backend.

15. Credits & licences

The design, layout, components and written content of this template are original. Placeholder artwork is generated from code, so no stock photography is included or required.

ItemLicenceUsed forSource
Bootstrap 5.3.3MITGrid and layout utilitiesgetbootstrap.com
Swiper 11.2.10MITTestimonial sliderswiperjs.com
Lenis 1.1.18MITSmooth anchor-link scrollinggithub.com/darkroomengineering/lenis
Lucide iconsISCThe 45 inlined iconslucide.dev
SyneSIL OFL 1.1Display typefacefonts.google.com/specimen/Syne
InterSIL OFL 1.1Body typefacersms.me/inter
JetBrains MonoSIL OFL 1.1Labels and datajetbrains.com/lp/mono

Licence texts travel with the files: the libraries' in assets/vendor/ (LICENSE and LICENSE-lucide), the fonts' in assets/fonts/LICENSE.txt, and all of them together in licensing.txt at the top of the download. Each licence permits redistribution inside a commercial product as long as the notices travel with it, which they do in this package.

16. Verification

Every figure below was measured on this package, not estimated. You can reproduce all of it yourself.

W3C validation

All 24 pages pass the Nu Html Checker — the same engine behind validator.w3.org — with no errors and no warnings.

npx vnu-jar --format json *.html
# or upload any page to validator.w3.org

Lighthouse

Home page, mobile profile with throttling, measured against the minified build (npm run build:min) — the median of five runs:

CategoryScore
Performance96
Accessibility100
Best Practices100
SEO100
MetricValue
First Contentful Paint1.7 s
Largest Contentful Paint2.6 s
Total Blocking Time7 ms
Cumulative Layout Shift0.004
npm run build:min
npm run serve
npx lighthouse http://localhost:3000/ --view

Where the remaining points go. The two libraries ship as their full distributions, so upgrading either stays a file swap: bootstrap.min.css is 227 KB (30 KB over gzip) and swiper-bundle.min.js is 151 KB (42 KB over gzip), and the template uses a fraction of each. If you want the last few points, run PurgeCSS over the Bootstrap file and build Swiper with only the modules you need.

Other checks

  • No horizontal scroll at 320, 360, 390, 768, 1024 or 1440 px on any page, in either theme
  • No JavaScript or console errors on any page — checked in Chrome, Firefox and Safari (WebKit), including with browser storage blocked, as inside the ThemeForest preview frame
  • No broken links and no missing images
  • Exactly one <h1> per page, headings in order
  • No interactive element nested inside another
  • Contrast meets WCAG AA in both themes: every run of text on every page was measured against the surface behind it, and none falls below 4.5:1 (3:1 for large text)
  • Every control is at least 44 × 44 px at phone widths

17. Changelog

v1.0.0 — 27 September 2026

  • First release.
  • 24 pages sharing one design system, dark and light themes, and a right-to-left stylesheet with index-rtl.html as a working example.
  • Mega menu, search overlay, lightbox, filter bars, counters, tabs, accordions, sliders, cookie bar and four validated forms.
  • 45 icons inlined as SVG at build time; fonts and libraries self-hosted, so the template makes no external request.
  • Optional source layout with a static builder, an icon inliner and a minifier; minified CSS and JS included.

18. Support

Before you contact support, please check this documentation and the FAQ above — most questions are answered here.

What to include in a support request

  • The page or component you are working on.
  • What you changed, and what you expected to happen.
  • A screenshot or a short description of the result.
  • Your browser and operating system, if the problem looks like a rendering issue.

Contact

Use the Item Support tab on your ThemeForest purchase. We aim to reply within two working days.

Item support covers help with the template, bugs and small adjustments. It does not cover custom design work or third-party plugin configuration — those can be quoted separately.