Portfolio: Templates
The four portfolio templates, their design language, premium gating, and how the private submodule works.
Portfolio: Templates
Four templates, sourced from a private git submodule (apps/portfolio/template-library, pinned
to a specific upstream commit) and rendered server-side.
| Template | Audience | Personality | Notable design elements | Access |
|---|---|---|---|---|
| Signal | Engineers and product leaders | Structured / technical | Dual dark/light theme, scroll-stacking project cards, mouse-glow bento cards, and a live local-time clock in the hero | Free (default) |
| Atelier | Designers and creative builders | Expressive / editorial | Print/magazine-style asymmetric masonry, serif headlines, flat 0px-radius cards, drifting orbit spheres | Free |
| Nimbus | Full-stack and frontend developers | Atmospheric / tech-editorial | GSAP animations, cursor-follow ring, per-character text-scramble hover, marquee ticker, magnetic CTA buttons, bento mouse-glow — and deliberately no cards, shadows, or blur anywhere, per its own design spec | Premium |
| Cipher | Developers | Interactive CLI emulator | A fully interactive draggable terminal window with command autocomplete, a blinking caret, a live clock, and a hidden matrix-rain easter egg (plus sudo make-coffee) | Premium |
Which templates have a live clock?
Signal and Cipher both render a real, ticking local-time display. Nimbus does not — it has no clock component at all. Older marketing copy that attributed live-time tracking to Nimbus was incorrect and has since been corrected at the source.
Premium gating
Premium gating is enforced at publish time, not just in the picker:
- A non-premium account can select and preview Nimbus or Cipher freely.
- Publishing (or re-publishing after an edit) with a premium template blocks a non-premium account with an upgrade prompt.
Premium access comes from the portfolio_publish entitlement family — see
Billing & Credits.
Custom domains
Only VeriWorkly-issued subdomains are supported
Custom-domain routing and certificate automation are explicitly out of scope for now, per the
template library's own README. Published portfolios are served on {username}.veriworkly.com
(premium) or portfolio.veriworkly.com/portfolio/{username} (free).
How the registry works
template-library/registry.ts maps each template id to its metadata and a lazy loader:
export const templatesRegistry = {
signal: {
name: "Signal",
note: "A precise, proof-first profile for product engineers.",
mood: "Structured / technical",
audience: "Engineers and product leaders",
strengths: ["Project proof", "Clear timelines", "Technical credibility"],
image: "/templates/signal-template-preview.png",
isPremium: false,
loader: () => import("./signal/SignalTemplate"),
design: signalDesign,
},
// atelier, nimbus, cipher …
} satisfies Record<string, TemplateRegistryEntry>;apps/portfolio/templates/catalog/templates.ts derives the public gallery list from that registry,
so the gallery and the renderer can never drift apart. isPremiumTemplate(id) is the single source
of truth for gating.
The backend's publish validator independently accepts only
"signal" | "atelier" | "nimbus" | "cipher", so an unknown template id is rejected server-side even
if a client sends one.
Adding a template
Because templates live in a private submodule, this is not an open contribution path today. For maintainers, the steps are:
- Add a folder in
template-library/with its React component, adesign.tsdetail file, and an optional scoped stylesheet. - Register it in
template-library/registry.tswith its metadata,isPremiumflag, and loader. - Add the template id to the backend's
templateIdenum inapps/server/src/validators/portfolioValidator.ts. - Advance the submodule pointer in the main repository.