Tvist



Overview
Tvist.is is the marketing website for Tvist, an Icelandic creative and branding agency. It is a classic agency site: a bold front page, a project portfolio, company and team pages, client lists, and open-role sections. Everything is composed from a Prismic headless CMS through a Next.js Pages Router frontend.
The site is strongly animated. Framer Motion, react-awesome-reveal, and react-fast-marquee drive the hero, text-reveal, and running-text effects, while Embla carousels and react-player handle the videotron and media slices. The visual identity leans on a pink/primary color system with a custom narrow display typeface.
Unlike Uos.is, Tvist is a single-locale (Icelandic) site. Routing is CMS-driven: page documents carry a route field, and a catch-all page resolves requests against Prismic, so editors define their own URL structure.
Tech Stack & Rationale
Layer | Technology | Why |
|---|---|---|
Framework | Next.js 13.5 (Pages Router), React 18 | SSG via getStaticProps/getStaticPaths; simple, mature routing for a CMS site |
Language | TypeScript | Typed Prismic document/content models |
Styling | Tailwind CSS 3 | Utility-first styling plus custom typeface and component layers |
CMS | Prismic + Slice Machine | Headless content: pages, projects, layouts, error, redirect_link types and 18 slices |
Animation | Framer Motion, react-awesome-reveal, react-fast-marquee | Hero, text-reveal, and marquee animations |
Media | react-player, Embla Carousel | Vimeo videotron and carousel slices |
SEO | next-sitemap + @reecem/prismic-sitemap | Prismic-aware sitemap and robots.txt generation |
Progress | nextjs-progressbar | Route-change progress indicator |
Architecture
The site is statically generated from Prismic. A catch-all route resolves every request against the pages and redirect_link custom types, while a layout document wraps every page with the shared navbar and footer.
The flow runs: Request /route → [...customs].tsx (getStaticProps) → queryByRoute (Prismic client) → DynamicLayout (layout + slices) → queryByUID(layouts) (main-layout) → SliceZone render (18 slices).
- Routing — pages/[...customs].tsx is the catch-all page. Its getStaticProps calls queryByRoute(client, pathname) to find the matching pages document by its route field (or a redirect_link document to follow).
- Layout resolution — the page also fetches the layouts document with UID main-layout (queryByUID), which supplies the navbar, footer, and menu slices that DynamicLayout wraps around the page content.
- Content querying — core/prismic/client.ts re-exports typed helpers (queryByRoute, queryByUID, queryByType) built on @prismicio/client, with linkResolver and route injection handled in core/prismic/utils.
- Slice rendering — the page's slice zone is rendered through @prismicio/react's SliceZone with the slices/index.ts component map (FrontPageHero, Videotron, ProjectList, ClientList, EmployeeList, etc.).
- Build & SEO — after next build, next-sitemap (augmented by @reecem/prismic-sitemap) generates sitemap.xml and robots.txt into public/, resolving URLs from the same Prismic link resolver used at runtime.
Folder Structure
tvist/
├── pages/ # Pages Router: index, [...customs], projects/[uid], 404, api (preview)
├── components/
│ ├── _layouts/ # DynamicLayout wrapper
│ └── _shared/ # Button, Image, Link, SEOTags, Pagination, Loader, icons, animations
├── core/
│ ├── prismic/ # client + types + utils (inject, linkResolver, query)
│ ├── contexts/ # layout & project React contexts
│ ├── hooks/ # useClearance, useEmbla, useResize
│ ├── animation/ # shared motion variants/easing
│ ├── data/ # SpaceData.ts
│ ├── lib/ # generateMetaData
│ ├── styles/ # base, components, tailwind, typefaces, utilities
│ └── utils/ # animations, check, debug
├── customtypes/ # Prismic models (pages, projects, layouts, error, redirect_link)
├── slices/ # 18 reusable Prismic slices
├── prismicio.ts # Prismic client + auto previews
├── next.config.js # link resolver + Prismic sitemap wiring
└── next-sitemap.config.js # sitemap/robots.txt generation- pages/ — the Pages Router entry points and API routes (preview, exit-preview).
- components/ — shared presentational components and the DynamicLayout wrapper.
- core/ — the app's kernel: Prismic helpers, contexts, hooks, animation utilities, styles, and metadata helpers.
- customtypes/ — the Prismic content model definitions.
- slices/ — the slice library consumed by Slice Machine and the SliceZone.
Content Model
Tvist has no relational database; all content is editorial and lives in Prismic. A page's URL is a first-class content field, which lets editors control the site structure without code changes.
Custom type | Purpose |
|---|---|
pages | Slice-composed pages; the route field sets the URL (/, /about, …) |
projects | Portfolio projects (client name, date, category list, hero/media slices) |
layouts | Shared layout documents (navbar, footer, menus) with UID main-layout |
error | Custom error page content |
redirect_link | CMS-managed redirects (source route → destination) |
The projects type carries a client_name, a date, a categorylist group (a Select of Icelandic service categories such as STEFNUMÓTUN, VEFHÖNNUN, MÖRKUN), and a slice zone (project_hero, videotron, image, paragraph, company_role). Pages and projects both carry an SEO & Metadata tab (meta_title, meta_description, meta_image), consumed by the SEOTags component.
Impact & Results
- In production for Tvist, an Icelandic creative and branding agency.
- Editors define the entire URL structure through Prismic, so the site can be re-organized without code changes.
My Contributions
I contributed to this project as one of the main developers (52 commits). Key work:
- Rebuilt the front page, navbar, and footer and fixed the mobile navbar behavior.
- Built the project section: the project list/grid, the projects/[uid] detail page, and the "other projects" navigation with previous/next project cards.
- Added the about page and refined the employee card and company-review slices.
- Implemented SEO and metadata: the SEOTags component, meta tag updates, and the next-sitemap + Prismic sitemap integration.
- Polished media and motion: the Vimeo videotron rounding, slide fixes, and font/weight adjustments across slices.
References
[1] Tvist, "Tvist — creative agency," [Online]. Available: https://tvist.is
[2] Next.js, "Next.js Pages Router documentation," nextjs.org, 2023. [Online]. Available: https://nextjs.org/docs/pages
[3] Prismic, "Prismic documentation — headless CMS," prismic.io, 2025. [Online]. Available: https://prismic.io/docs
[4] Framer Motion, "Motion for React documentation," framer.com, 2025. [Online]. Available: https://motion.dev
[5] next-sitemap, "next-sitemap — sitemap generator for Next.js," github.com, 2025. [Online]. Available: https://github.com/iamvishnusankar/next-sitemap
Comments
Leave a Comment
You must be signed in to comment
0 Comments
No comments yet. Be the first to comment!