Overview

Tenebra template home pages

A dark, painterly HTML template for a fine art photographer of portraits and still lifes who sells her work as limited-edition prints. Tenebra ships three home pages, a dark and a light theme, right-to-left support, and logic that is worked out rather than typed in: every print in three sizes, each size its own numbered edition with the numbers left, the next number and a price that steps up as the edition sells; a configurator for paper, frame and mat; the edition register; portrait sittings booked in daylight from the season’s sunset; a proofing gallery; the exhibitions on now, next and past from the visitor’s date; a display check for print care; and a shop with a bag, coupon, shipping and tax.

What’s included

  • 3 home pages, each with its own scroll moment: a still life composes itself (the linen, the jug, the pewter, two pears and a knife set down on the walnut table one by one), the edition ledger strikes its sold numbers, and a print’s frame and mat change option by option with the price of each
  • A dark studio theme by default and a light theme on one switch in every header, remembered between visits and applied before the page paints
  • Right-to-left stylesheets and a flag language picker in every header: a right-to-left language turns any page around
  • WebGL: Craquelure, the fine cracks of old varnish spreading across the dark bands, and the footer’s cloth — a linen cloth simulated thread by thread, falling and settling over a still life you never see
  • Limited editions: three sizes, each its own edition with 2 artist’s proofs, the numbers sold and on hold, the next number, a price ladder, and the edition register of every work
  • The print page: size, paper, frame and mat with a live framed preview, the price line by line and the register for the chosen size
  • Portrait sittings: four kinds, a four-step booking that only offers slots ending an hour before the day’s sunset, a deposit, and the sitter’s proofing gallery
  • Portfolio masonry with series filters and search, a gallery wall, three single-work layouts, series and exhibitions now, next and past
  • The print shop: series, subject, size and price filters, sort and search, bag, coupon, free-shipping meter, crate or tube shipping, tax, checkout with an order number, wishlist
  • Print care with a display check, team, profile, journal, FAQ with search, account pages, coming soon, 404
  • Window Light preloader, Side Light reveals, the mat bevel drawing in on hover, Swiper sliders and Fancybox lightboxes
  • Fully responsive, zero console errors
📄 33 HTML files

Getting Started

Thank you for choosing Tenebra. Follow the steps below to get your site live.

1. Open locally

Unzip the downloaded package and open tenebra/index.html in any modern browser (Chrome, Firefox, Edge, Safari). No build tools or server are required — the editions, the configurator, the sitting booking, the proofing gallery, the display check and the shop all work straight from the files.

2. Deploy to a server

Upload the contents of the tenebra/ folder to your hosting provider using an FTP client (such as FileZilla) or your hosting control panel. Once uploaded, navigate to your domain and the template will load immediately.

3. Customise

All custom styling lives in assets/css/style.css (with a numbered Table of CSS at the top) and assets/css/responsive.css. Colours and fonts are controlled by CSS variables — see Colors & Fonts. The works, their editions, the papers, frames and mats, the sittings, the exhibitions and the shop rules live in one place — see Editions & Sittings.

Tip: Replace the neutral placeholder images in assets/img/ with your own photography at the same dimensions for the best result. The team portraits in img/team/ are 3:4; the still life’s objects in img/stilllife/ are drawn, transparent PNGs and ship with the template.

File Structure

Below is an overview of the key files and folders included in this template.

index.html / homepage-2.html / homepage-3.htmlThree home pages: The Studio (the still life composing itself), The Editions (the edition ledger), The Gallery beside the side menu (the frame and mat swap)
portfolio.html / gallery.htmlEvery work in a masonry with series filters and search; the gallery wall at each work’s own proportion, with a lightbox
work-details.html / work-details-2.html / work-details-3.htmlThree single-work layouts: big images, a slider, small images with side notes; each with its three editions
series.html / exhibition-details.htmlThe exhibitions on now, next and past from the date, the six series; one exhibition with its dates, works and a map
sittings.html / book-sitting.html / proofing.htmlThe four sittings, the light by season; the four-step sitting booking; the sitter’s proofing gallery
shop.html / product-single.html / editions.htmlThe print shop with filters; the print page with size, paper, frame and mat and its edition register; the register of every edition
print-care.htmlHow to keep a print, and the display check that works out how long it will last on a wall
cart.html / checkout.html / wishlist.htmlThe bag of numbered prints, checkout with delivery and an order number, the wishlist
about.html / team.html / team-details.htmlThe photographer, the studio team, a team profile
blog.html / blog-details.htmlThe journal with search; a post with reading time, share and comments
faq.htmlQuestions by topic with search
contact.htmlContact cards with the live viewing-room status, map, hours and the contact form
account.html / login.html / register.html / forgot-password.htmlThe account (orders, numbered prints, sittings, details) and the login pages
coming-soon.html / 404.htmlCountdown to the new series, error page
sendmail.phpAJAX mail handler for the contact and comment forms (see Contact Form)
assets/css/style.cssAll custom styles, numbered Table of CSS (19 sections)
assets/css/responsive.cssDesktop-first breakpoints 1399 / 1199 / 991 / 767 / 575, plus wide screens from 1200, 1600 and 1960
assets/css/style.rtl.css / responsive.rtl.cssThe right-to-left twins (see RTL)
assets/css/plugins/Bootstrap (LTR and RTL), Swiper, Fancybox (vendor CSS)
assets/js/main.jsAll custom scripts, numbered JS INDEX (33 blocks)
assets/js/plugins/jQuery, Bootstrap, Swiper, Fancybox, GSAP, ScrollTrigger
assets/img/Images, one folder per section (see Images)
assets/fonts/theme-icons/The sun and moon of the theme switch, loaded locally
assets/webfonts/ + assets/css/fontawesome-all.cssFont Awesome Free, loaded locally

Folder Structure

The package unzips to two folders: Documentation/ (this guide) and tenebra/, the template. Every page sits in the template’s root; everything the pages load sits under assets/:

tenebra/
├── *.html                              the 33 pages, all in the root (see File Structure)
├── sendmail.php                        the AJAX mail handler for the forms
└── assets/
    ├── css/
    │   ├── style.css                   all custom styles, numbered Table of CSS
    │   ├── style.rtl.css               the right-to-left twin of style.css
    │   ├── responsive.css              breakpoints 1399 / 1199 / 991 / 767 / 575
    │   ├── responsive.rtl.css          the right-to-left twin of responsive.css
    │   ├── fontawesome-all.css         Font Awesome Free, loaded locally
    │   └── plugins/                    vendor stylesheets
    │       ├── bootstrap.min.css
    │       ├── bootstrap.rtl.min.css   Bootstrap for right-to-left pages
    │       ├── jquery.fancybox.min.css
    │       └── swiper-bundle.min.css
    ├── js/
    │   ├── main.js                     all custom scripts, numbered JS INDEX (33 blocks)
    │   └── plugins/                    vendor scripts
    │       ├── bootstrap.bundle.min.js
    │       ├── gsap.min.js
    │       ├── jquery-3.7.1.min.js
    │       ├── jquery.fancybox.min.js
    │       ├── ScrollTrigger.min.js
    │       └── swiper-bundle.min.js
    ├── fonts/
    │   └── theme-icons/                the sun and moon of the theme switch
    ├── webfonts/                       Font Awesome Free font files
    └── img/                            images, one folder per section
        ├── blog/                        5 files
        ├── faces/                       5 files
        ├── flags/                       6 files
        ├── icons/                       34 files
        ├── logo/                        5 files
        ├── menu/                        3 files
        ├── stilllife/                   7 files
        ├── team/                        5 files
        └── works/                       74 files

To publish the site, upload the contents of tenebra/ to your web root. Photos keep their folder, file name and size when you replace them, so no page needs editing.

Colors & Fonts

The whole design is driven by CSS variables declared at the top of style.css. Change a token once and every section, button and card updates. Colours used with transparency have an -rgb twin (for example --tn-coral-rgb) — change both together.

Charcoal Ground--tn-charcoal
Raised Panel--tn-raised
Footer Slate--tn-slate
Still-Life Wall--tn-umber
Coral--tn-coral
Coral Deep--tn-coral-deep
Coral Soft--tn-coral-soft
Museum Board--tn-mat
Heading--tn-heading
Body--tn-text

Charcoal is the studio: the ground of every page, with the raised panel for cards, the header bar and the frame round the page. The footer slate is kept for the footer and the night bands; the olive umber is the still-life wall the scroll moments and the craquelure bands are set on. Coral draws the hairline under every title, the prices, the active links and the primary buttons (coral buttons carry charcoal text). Museum board is the mat round a print and the edition register’s page. --tn-bg, --tn-surface, --tn-cream, --tn-heading and --tn-text are the semantic names the components use — the light theme swaps those (see Dark & Light Mode).

Fonts

Two Google Fonts are loaded in the head of each page: Old Standard TT (headings in widely tracked capitals, prices and figures; its italic sets the soft word in a title and the leads) and Open Sans (body, navigation, labels and buttons). Swap them by editing the Google Fonts link and the --tn-ff-display / --tn-ff-body / --tn-ff-figure variables.

Logo

The logo is a T whose foot runs out into a looping hairline swash, in coral, beside or above TENEBRA in tracked Old Standard TT capitals. It ships as ready-made PNG files in assets/img/logo/:

  • logo.png / logo-light.png — the row lockup for light and dark grounds (headers, the mobile menu)
  • logo-stack-light.png — the stacked lockup on dark grounds (the footer, the preloader)
  • mark.png — the T alone (the edition register, the seals on the login and error pages)
  • favicon.png — the browser tab icon

The logo’s lettering appears only inside the images. To use your own logo, replace these files; the header sizes the logo by its height, so a wider or narrower file needs no CSS change.

Dark & Light Mode

Tenebra opens dark: the charcoal studio is the default and needs no attribute. Every header (and the mobile menu) has a theme switch that opens the shutters. The choice is saved in the browser under the key tenebra-theme and applied by a one-line script in the <head> before the page paints, so a light visitor never sees a dark flash. The switch sets data-theme="light" on the <html> tag.

Light Ground--tn-bg
Light Band--tn-cream
Light Heading--tn-heading
Light Body--tn-text
Coral Ink On Light--tn-accent-text
  • Tokens — the light values sit in one block, [data-theme="light"] { … }, right after :root in style.css. Change a light colour there.
  • Bands that stay dark — sections with the class is-night (the footer, the mobile menu’s foot, the sidebar call to action, the account menu, the proofing bar) and is-umber (the still life, the edition ledger, the frame room, the light by season, the display check) keep their ground in both themes.
  • Museum board — the edition register’s page takes tn-on-mat and keeps its board and ink in both themes.
  • Icons — each illustrated icon ships in a dark and a light ink and the right one shows by theme and ground.
  • Start light — to open the site light for first-time visitors, add data-theme="light" to the <html> tag of each page; the switch still works and is still remembered.

Editions & Sittings

The figures on every page come from one data block, JS block 09 Tenebra Data near the top of main.js (var TENEBRA). Edit it once and the editions, prices, dates and totals follow. Prices are in US dollars; times are minutes after midnight (1080 = 6:00 pm); weekdays run 0 = Sunday to 6 = Saturday.

worksEvery work: title, series, subject (still life or portrait), year, photograph and a price tier. An editioned work carries its sold numbers and the numbers on hold for each size (s, m, l); a work without them is shown in the portfolio only (private collection).
sizes / proofs30 × 40 cm (edition of 25), 50 × 70 cm (edition of 15), 80 × 110 cm (edition of 7), each its own edition at its own base price, plus 2 artist’s proofs; the tube and crate shipping for each size.
ladderThe price steps: First Release up to 40% of the edition sold, × 1.00; Second Release up to 80% of the edition sold, × 1.25; Last Numbers up to 100% of the edition sold, × 1.60.
papers / frames / matsPaper surcharges (Cotton Rag included, Baryta Fibre +10%, Japanese Kozo +18%), frames and mats priced by size; a mat needs a frame.
series / exhibitionsThe six series, and the exhibitions with their venue, city, start and end dates; the clock sorts them into on now, coming next and past from the visitor’s date.
viewing / sunsetThe viewing room’s hours by weekday (null = by appointment) for the open-now line, and the sunset in each month that the sitting slots follow.
sittingsThe sitting days, the slot starts, how far ahead, the deposit (30%), the four kinds (length, price, prints included, proofs), the backdrops and the extras.
proofingThe sitter, the sitting, the proofs and the price of each extra print ($120).
careThe paper’s rating (110 years at 450 lux, 12 hours a day), the rooms and the glazing for the display check.
shop / teamFree shipping from $3,000, express $95 more, tax 8%, coupon COLLECTOR10 for 10% off; the studio team.

How an edition is priced

A print’s base price is its size’s base times the work’s tier, to the nearest $10. The share of the edition already sold sets the step on the ladder, and the next number is sold at that step.

Worked example: White Peonies, 30 × 40 cm: base $530; 15 of 25 sold, so the edition is at Second Release (× 1.25): the next number costs $660.

A configured print

Worked example: Pears In The Dark, 50 × 70 cm: the edition price $2,010, on baryta (+10%) $2,210, a walnut frame $420 and an ivory mat $130 — $2,760; it ships crated ($120), with tax 8% $220.80.

A print in the bag holds its number: the register and every count on the site treat it as on hold for that visitor. The bag, the wishlist and the coupon are kept in the browser (localStorage); the first visit starts with one demo print and two saved works so every shop page has something to show — to start empty, remove the demo lines in doShop() (block 27 Print Shop).

Sittings by daylight

A slot is offered only when the sitting, at its own length, ends an hour before that day’s sunset; longer sittings get fewer slots in winter.

Worked examples: In December the sun sets at 4:30 pm, so the last two-hour portrait sitting starts at 12:30 pm. A Heirloom Portrait ($1,450) with hair & make-up ($180) comes to $1,630: $489 deposit today, $1,141 after the proofs.

Proofs and print care

Worked examples: A Portrait Sitting includes 1 print; picking three proofs adds two extra prints at $120 each. A print in a Bright Living Room (300 lux) lit 10 hours a day behind standard glass: 110 × (450 × 12) / (300 × 10) = about 198 years before visible fading.

Checkout, the sitting booking, the proofing gallery’s send and the account forms confirm on screen with a reference — connect them to your own systems to take real orders and bookings.

WebGL Layers

Two WebGL pieces move on the page: Craquelure — the fine cracks of an old varnish spreading slowly across the page titles and the dark bands, region by region, holding and fading — and the Cloth in the footer — a linen cloth with two coral threads, simulated point by point, falling and settling over a still life that is never shown, lifted away and dropped again. Each is one canvas:

<canvas class="tn-gl" data-gl="craquelure" aria-hidden="true"></canvas>
  • Colours — the craquelure reads three colours and an opacity from CSS variables on its section: --gl-1, --gl-2, --gl-3 and --gl-alpha; the cloth reads --cloth-linen, --cloth-shade and --cloth-thread on the footer. The theme switch repaints them.
  • Performance — a layer only runs while its section is on screen and the tab is visible. Visitors who prefer reduced motion get one still frame (the cloth at rest). Without WebGL, the section’s own background shows.
  • Remove one — delete the canvas; nothing else depends on it.

RTL (Right To Left)

Tenebra is RTL-ready: the layout with its paddings and margins, the sliders and the animations all mirror. Right to left comes from the stylesheets, not from separate pages: the language picker (a flag and a code) beside the dark / light switch lists the languages that read left to right and right to left. Choosing Arabic stores the language and the direction (keys tenebra-lang and tenebra-dir) and reloads; the one-line script in <head> then sets dir="rtl" and swaps the three stylesheets for the files named in their data-rtl attribute before the page paints. Nothing is translated — you bring your own right-to-left copy. To make a page right to left for good:

1. Set The Direction

Add dir="rtl" to the page’s <html> tag (and set lang to your language):

<html lang="en" class="no-js" dir="rtl">

2. Swap Three Stylesheets

assets/css/plugins/bootstrap.min.css→ assets/css/plugins/bootstrap.rtl.min.css
assets/css/style.css→ assets/css/style.rtl.css
assets/css/responsive.css→ assets/css/responsive.rtl.css

The scripts read the direction from the dir attribute: sliders and every move that must mirror follow it on their own. Prices, edition numbers and the register keep reading left to right, and the still life keeps its window on the left.

Editing the styles: style.rtl.css and responsive.rtl.css are mirrored twins of the LTR files, made with RTLCSS. A few hand-made rules at the end of style.rtl.css (after RTL fixes) keep what must not mirror. If you change style.css, regenerate the twin with npx rtlcss style.css style.rtl.css and copy the RTL fixes block back to its end.

JavaScript Guide

All custom behaviour lives in assets/js/main.js, wrapped in a jQuery IIFE and organised into 33 numbered blocks (see the JS INDEX comment at the top of the file):

  • 01–08 — Preloader, Sticky Header, Offcanvas Menu, Scroll Reveals, Back To Top, Anchor Scroll, Light & Dark Mode, Direction, WebGL Layers. The core every page shares: the Window Light preloader, the header, the Side Light reveals, the theme and direction switch and the Craquelure layer.
  • 09–10 — Tenebra Data, Editions Engine & Studio Clock. Tenebra Data holds every figure; the Editions Engine works out each edition’s numbers left, its next number and its price, and the Studio Clock the viewing room, today’s sunset and the exhibitions on now, next and past.
  • 11–18 — Custom Select, Hero Sliders, Card Sliders, Accordion, Filter Tabs, Grid Search, Newsletter, Choice Cards. Shared components: selects, sliders, accordions, filters, search, forms.
  • 19–21 — Still Life Composes Itself, Edition Ledger, Frame & Mat Swap. The three home pages’ scroll moments.
  • 22–33 — Print Configurator, Sitting Booking, Proofing Gallery, Display Check, Contact Form, Print Shop, Account Forms, Article Tools, Demo Forms, Launch Countdown, Footer Cloth, FAQ Search. The feature pages: the print configurator, the sitting booking, the proofing gallery, the display check, contact, the print shop, accounts, the journal, the coming-soon countdown, the footer’s cloth and FAQ search.

Each block is a self-contained doSomething() function that safely skips pages where its section is not present — you can delete any block you do not need. Every animation respects prefers-reduced-motion automatically: content appears in its final state and the scrubbed scenes rest in place.

Reveals: add tn-lit to a photograph’s link or wrapper so it emerges from black as light rises from its left (Side Light), tn-fade to text so it rises softly into place, and tn-rule for the coral hairline under a title. data-delay="0.2" staggers any of them. Wrap a photograph in <span class="tn-mat"> so a white museum mat with its bevel draws in round it on hover.
Scroll moments: the still life sets its six objects down one after another, the edition ledger strikes its sold numbers one after another and rings the next one, and the frame room changes the frame and mat step by step. Each is scrubbed against its own section’s travel, none of them pins the page, and each page is authored in the finished state.
Countdown: the coming-soon page counts down to 10:00 am on the next 20 March — no date to update. Change it in doLaunchCountdown().

Images

The download package ships with neutral placeholder images so you can see every layout at the correct dimensions. Replace them with your own photos using the same file names, or update the src attributes. Images are grouped inside assets/img/:

img/blog/Journal posts — 5 files: 1300×806, 2817×1747
img/faces/Round portraits for voices, bylines and avatar groups — 5 files: 305×305, 308×308
img/flags/The language picker’s flags (SVG, included) — 6 files: SVG
img/icons/Illustrated line icons, each in a dark and a light ink (included) — 34 files: 128×128
img/logo/Logo, light logo, stacked logos, mark and favicon (included) — 5 files: 1339×205, 64×64, 1118×432, 360×425
img/menu/Home previews in the mega menu — 3 files: 560×350
img/stilllife/The still life’s table, linen, jug, pewter, pears and knife, transparent PNG (included) — 7 files: 1154×912, 513×770, 840×68, 282×587, 260×519, 804×183, …
img/team/The studio team, portraits at 3:4 — 5 files: 767×1023, 836×1115, 837×1117, 583×777
img/works/The photographs: every work, the heroes, the page titles, the shop and the proofs — 74 files: 1100×1100, 900×900, 900×747, 1300×1300, 1218×888, 1508×969, …

The logo files, the illustrated icons, the still life’s drawn objects and the language flags are included and ready to use. All demo photography shown on the live preview is for preview purposes only and is not included in the download.

Contact Form

The contact form and the comment form post to sendmail.php, a lightweight AJAX mail handler. The success or error message appears under the button without reloading the page. The newsletter, sitting booking, proofing, checkout, account, login, register and forgot-password forms are demo forms: they confirm on screen and are ready to connect to your own systems. To activate the mail handler on your server:

1. Set your email address

Open sendmail.php and replace the placeholder recipient at the top of the file with your own address:

$email = 'example@example.com';

2. Upload to a PHP host

The form needs a server with PHP mail() support (virtually every shared host). It will not send from your local computer or from a static-only host — there the form shows a friendly “upload to a PHP-enabled host” notice instead.

3. Optional: enable Google reCAPTCHA v3

Invisible reCAPTCHA v3 spam protection is already built into the handler. It stays dormant until the form submits a token — that is why no badge or checkbox appears out of the box. To switch it on:

  • Create v3 keys (a site key and a secret key) for your domain in the Google reCAPTCHA admin console
  • In sendmail.php, replace YOUR_RECAPTCHA_V3_SECRET_KEY with your secret key
  • In contact.html, add a hidden token field inside the form and load the reCAPTCHA script with your site key just before </body>:
<!-- inside the form -->
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response">

<!-- before the closing </body> tag -->
<script src="https://www.google.com/recaptcha/api.js?render=YOUR_SITE_KEY"></script>
<script>
  grecaptcha.ready(function () {
    grecaptcha.execute('YOUR_SITE_KEY', { action: 'contact' }).then(function (token) {
      document.getElementById('g-recaptcha-response').value = token;
    });
  });
</script>

Once the token field is present, sendmail.php verifies every submission with Google and rejects low-score (bot) requests.

Credits

This template is built using the following open-source libraries and resources.

  • Bootstrap 5.3.3
  • jQuery 3.7.1
  • Swiper 11
  • GSAP 3 + ScrollTrigger
  • Fancybox 3.5
  • Font Awesome Free
  • RTLCSS
  • Google Fonts: Old Standard TT, Open Sans

All plugin files and icon fonts are loaded locally. The only external requests are the Google Fonts stylesheet, the Google Maps embeds and the video popups.

Support

If you have any questions or need help with the template, please reach out through the marketplace where you purchased the template: open the item there and send us your question from its support page. We aim to respond within 24–48 hours.