Reference site:
https://pacomepertant.com/
Subject: Motion and sound designer portfolio for Pacôme Pertant
Purpose: Capture the visual language, interaction model, animation principles, and implementation guidance so the style can be studied and adapted without copying the website directly.
The live site itself is protected by a browser verification screen in normal web fetches, and local Playwright access from this sandbox was blocked by network/browser restrictions. Because of that, this study is based on:
- Public Awwwards page and Awwwards element breakdowns for the site.
- Public Landing Love screenshots of the live experience.
- Recent.design metadata describing the framework, interaction tags, and libraries.
- GSAP public post describing the animation stack.
- Visual analysis of available screenshots showing the spiral gallery, list mode, project detail pages, about section, controls, and overall layout.
- High confidence: palette, dark/light theme split, spiral/list gallery model, menu/audio controls, project list, 3D/WebGL gallery, GSAP/Three.js/Nuxt presence, sound emphasis, smooth transitions.
- Medium confidence: exact animation timings, easing curves, hover physics, loading sequence duration, mobile behavior.
- Low confidence: exact font family, internal component names, shader implementation, exact Three.js camera values.
Use this as a design direction document, not a pixel-perfect forensic clone.
The site treats a portfolio as a motion instrument rather than a static archive. The interface is minimal, but the work is presented through rhythm, depth, sound, and spatial movement.
The main experience is built around three ideas:
-
A dark stage
The home page is almost entirely black, with subtle grid texture and floating media cards. The dark background turns every project thumbnail into a glowing object. -
Two browsing modes
Users can switch between an expressive spiral view and a highly scannable list view. This gives the site both spectacle and usability. -
Motion and sound as identity
The portfolio belongs to a motion and sound designer, so animation, rhythm, transitions, hover trails, and audio toggles are not decoration. They are the brand.
- Minimal
- Experimental
- Playful
- Dark
- Cinematic
- Rhythmic
- Spatial
- Sound-aware
- Editorial on detail pages
- Portfolio as showreel
The site feels like:
- A showreel in orbit.
- A dark-room gallery where project thumbnails float like animated canvases.
- A music visualizer translated into portfolio navigation.
- A minimal editorial portfolio when entering project detail pages.
The brand personality is confident but not corporate. It avoids long explanations on the home page and relies on movement, contrast, and curation.
/
├── Entry / Loader
│ ├── Enter with sound
│ └── Enter without sound
│
├── Home
│ ├── Spiral view
│ ├── List view
│ ├── Menu
│ ├── Audio toggle
│ └── Project navigation
│
├── Project detail
│ ├── Title
│ ├── Short description
│ ├── Video / motion embed
│ ├── Still images
│ ├── Case link CTA
│ └── Next project / transition
│
├── About
│ ├── Short bio
│ ├── Emoji-like inline icons
│ ├── Horizontal project strip
│ └── Contact / socials
│
└── Menu overlay
├── Work
├── About
├── Contact
└── Social links- Paths of life
- The disease spread on Tiktok
- Ah, Psychedelics
- Thought
- Jupiter
- Chromatik
- Digital Travel
- Mercedes AMG
- The purity revealed
The design is almost binary: black and white, with color coming mainly from project thumbnails.
:root {
--color-black: #0a0a0a;
--color-white: #fafafa;
--color-muted-white: rgba(250, 250, 250, 0.64);
--color-faint-white: rgba(250, 250, 250, 0.12);
--color-faint-black: rgba(10, 10, 10, 0.12);
--surface-home: #0a0a0a;
--surface-detail: #fafafa;
--text-on-dark: #fafafa;
--text-on-light: #0a0a0a;
}| Token | Usage |
|---|---|
#0a0a0a |
Home background, menu surface, immersive gallery stage |
#fafafa |
Text on dark, project detail page background, menu pill background |
| Color thumbnails | The only strong color source; project artwork creates emotional variety |
| Transparent white | Grid, dividers, inactive controls, subtle UI marks |
| Transparent black | Buttons and text on project pages |
Do not add a separate brand accent color. The work thumbnails are the accent system.
The type appears to be a clean, modern grotesk/sans-serif. It is bold, direct, and neutral enough to let the motion work dominate.
Use one of these:
font-family:
"Inter",
"Geist",
"Suisse Intl",
"Helvetica Neue",
Arial,
sans-serif;:root {
--font-xs: clamp(0.625rem, 0.55rem + 0.2vw, 0.75rem);
--font-sm: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
--font-md: clamp(0.875rem, 0.8rem + 0.35vw, 1rem);
--font-lg: clamp(1.25rem, 1rem + 1vw, 2rem);
--font-xl: clamp(2rem, 1.5rem + 3vw, 4rem);
--font-list: clamp(2rem, 3.2vw, 4.5rem);
--font-project-title: clamp(2.75rem, 7vw, 8.5rem);
}| Element | Style |
|---|---|
| Center list titles | Large, bold, tight line height, centered |
| Project detail title | Oversized, top-left, black on white |
| Body copy | Small, compact, almost caption-like |
| UI controls | Tiny lowercase labels, circular dot indicator |
| Menu button | Small rounded pill, lowercase |
| About text | Medium-large paragraph, centered top block |
- Keep text short.
- Let type become a spatial object.
- Prefer lowercase UI labels:
spiral,list,menu. - Use heavy weight for project names.
- Use small body copy to create scale contrast.
The home page keeps controls pinned around the edges:
┌─────────────────────────────────────────────────────────────┐
│ logo menu pill │
│ spiral • list │
│ │
│ │
│ 3D spiral gallery / list │
│ │
│ │
│ rotating showreel mark sound toggle │
└─────────────────────────────────────────────────────────────┘| Control | Position | Notes |
|---|---|---|
| Logo | Top-left | Circular glossy symbol, small but colorful |
| View toggle | Top-center | spiral • list, active state marked by a dot |
| Menu | Top-right | White pill on dark background |
| Audio | Bottom-right | White circular button with speaker icon |
| Showreel marker | Bottom-left | Circular/rotating stamp-like element with preview card |
The edges hold utility. The center holds the experience.
The background is not flat black. It uses a subtle grid that gives the 3D content depth and scale.
.stage {
background-color: var(--color-black);
background-image:
linear-gradient(rgba(255,255,255,0.035) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.035) 1px, transparent 1px);
background-size: 40px 40px;
}- Keep grid nearly invisible.
- Avoid high-contrast graph-paper styling.
- Fade grid toward edges with radial/linear overlays.
- Use grid to suggest space, not decoration.
The site opens with a loading/entry state and a sound choice.
- Show a minimal loading state.
- Ask the user whether to enter with or without sound.
- Do not autoplay sound without consent.
- Use the choice to initialize sound state globally.
[ Loader ]
Please wait while your request is being verified / loading assets
[ Enter with sound ] [ Enter without sound ]- Text fades or splits into view.
- Background remains dark.
- Small circular brand object can rotate or pulse.
- Transition from loader into gallery should feel like entering a stage.
The spiral view is the signature interaction.
- Project thumbnails appear as floating rectangular planes.
- Planes are positioned in 3D depth, not a flat grid.
- Some planes curve or warp slightly, suggesting WebGL shaders or geometry deformation.
- Cards overlap in perspective.
- The currently focused card sits near the center, larger and clearer.
- Peripheral cards are partially cropped, blurred, darker, or angled.
| Trigger | Response |
|---|---|
| Mouse move | Gallery subtly parallax-shifts; cursor may leave a trail |
| Scroll / wheel | Spiral advances through projects |
| Hover card | Card becomes more visible, less distorted, possibly scales forward |
| Click card | Project transition opens detail page |
Toggle list |
Cards collapse/morph/fade into centered text list |
Use Three.js planes with texture materials.
interface ProjectCard3D {
id: string;
title: string;
texture: THREE.Texture;
position: THREE.Vector3;
rotation: THREE.Euler;
scale: THREE.Vector3;
focusProgress: number;
}const radius = 4.5;
const depthStep = 0.55;
const angleStep = 0.72;
projects.forEach((project, index) => {
const t = index - activeIndex;
const angle = t * angleStep;
project.position.x = Math.sin(angle) * radius;
project.position.y = Math.cos(angle) * radius * 0.45;
project.position.z = -Math.abs(t) * depthStep;
project.rotation.y = -Math.sin(angle) * 0.55;
project.rotation.x = Math.cos(angle) * 0.16;
project.scale.setScalar(t === 0 ? 1.25 : 0.8);
});The spiral should feel like a controlled orbit, not a chaotic carousel.
The list view is the usability anchor.
- Black background remains.
- Project names are stacked vertically in the center.
- Text is large, white, bold, and tightly spaced.
- The view toggle changes active state from
spiraltolist. - The rest of the UI stays consistent.
.project-list {
min-height: 100svh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.project-list__items {
display: flex;
flex-direction: column;
gap: 0.05em;
}
.project-list__item {
font-size: var(--font-list);
font-weight: 700;
line-height: 0.95;
letter-spacing: -0.055em;
}| Trigger | Response |
|---|---|
| Hover project name | Text brightens; preview thumbnail may appear or cursor trail responds |
| Click project name | Page transition to project detail |
Toggle spiral |
Text dissolves/morphs back into floating card gallery |
Experimental portfolios often lose usability. This list view repairs that by giving the user a fast index of the work.
Project pages invert the experience from black immersive gallery to white editorial case-study pages.
- Background becomes
#fafafa. - Text becomes
#0a0a0a. - Project title appears huge at top-left.
- Short description sits at top-right in a narrow text column.
- Media is arranged in a staggered composition rather than a uniform grid.
- Large white space surrounds the videos/images.
- Media cards have softly rounded corners.
- A small black CTA pill such as
see the case •appears near the description.
┌──────────────────────────────────────────────────────────────┐
│ Jupiter Release motion created ... │
│ │
│ │
│ ┌───────────────────────────────┐ │
│ │ video still │ │
│ └───────────────────────────────┘ │
│ │
│ ┌────────────────────────────┐ │
│ │ image/video │ │
│ └────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘.project-page {
min-height: 100svh;
background: var(--surface-detail);
color: var(--text-on-light);
padding: clamp(1rem, 3vw, 4rem);
}
.project-hero {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(16rem, 32rem);
gap: clamp(2rem, 8vw, 10rem);
align-items: start;
}
.project-title {
font-size: var(--font-project-title);
line-height: 0.88;
letter-spacing: -0.075em;
font-weight: 700;
}
.project-description {
max-width: 34ch;
font-size: var(--font-sm);
line-height: 1.15;
font-weight: 600;
}
.project-media-grid {
margin-top: clamp(3rem, 10vh, 9rem);
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: clamp(1rem, 2.2vw, 2rem);
}
.media-card {
border-radius: 0.5rem;
overflow: hidden;
background: #111;
}- Use a 12-column grid.
- Avoid symmetrical gallery layouts.
- Let one asset occupy 5 to 6 columns, another 5 columns offset lower.
- Use vertical gaps as rhythm.
- Alternate large video blocks and still-image blocks.
The about section returns to the dark stage.
- Short bio is centered near the top.
- Bio is set in large white text.
- Inline emoji-like icons appear inside the paragraph.
- A horizontal strip of project thumbnails spans the lower part of the viewport.
- The menu pill and audio toggle remain available.
- The showreel marker remains at bottom-left.
I’m Pacome Pertant, [icon] motion and sound designer
based in Paris. [icon] I move shapes and sound [icon] to
create emotional content. [icon] Always playing with
rhythm, sound and visual narrative on a 2D and/or
3D canvas. Clean at times, [icon] experimental at others.The about section does not behave like a traditional biography page. It is still part of the animated environment. The bio is concise, almost like a statement in a gallery.
Awwwards identifies a dedicated Menu Open interaction. The menu should be treated as a motion component, not just a dropdown.
- The white
menu •pill triggers the menu. - The overlay likely opens with a soft expansion, wipe, or masked transition.
- Menu entries should be large and direct.
- Background should retain black/white contrast.
- The open state should preserve the site’s playful dot language.
work
about
contact
instagram
behance
x / twitter
email| Phase | Behavior | Duration |
|---|---|---|
| Press | Pill compresses slightly | 120ms |
| Open | Overlay expands/masks in | 500 to 800ms |
| Items | Links stagger in with split text | 450 to 700ms |
| Close | Reverse with faster timing | 350 to 500ms |
Use GSAP timeline:
const tl = gsap.timeline({ paused: true });
tl.to(menuMask, {
scale: 1,
duration: 0.7,
ease: "expo.out"
});
tl.from(menuLinks, {
yPercent: 110,
opacity: 0,
stagger: 0.045,
duration: 0.8,
ease: "power4.out"
}, "-=0.45");The subject is motion and sound, so animations should feel timed, musical, and intentional. Avoid random easing everywhere.
Cards do not merely fade. They orbit, fold, scale, warp, or move through depth.
The content can be expressive, but controls should stay minimal and readable.
- Spiral view = spectacle.
- List view = clarity.
- Detail page = editorial focus.
The interface stays almost monochrome so that thumbnails become the color system.
:root {
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
--ease-in-out-quart: cubic-bezier(0.76, 0, 0.24, 1);
--duration-tap: 120ms;
--duration-hover: 220ms;
--duration-ui: 420ms;
--duration-view-switch: 900ms;
--duration-page-transition: 1000ms;
--duration-loader: 1400ms;
}| Interaction | Duration | Ease |
|---|---|---|
| Button hover | 180 to 240ms | out-quart |
| Card hover | 350 to 600ms | out-expo |
| Spiral scroll settle | 700 to 1200ms | out-expo |
| Spiral to list | 800 to 1200ms | in-out-quart / expo |
| Page transition | 900 to 1300ms | expo |
| Menu open | 500 to 800ms | expo |
| Split text reveal | 600 to 900ms | power4/expo |
| Interaction | What happens | Implementation approach |
|---|---|---|
| Loading | Minimal entry before gallery | GSAP timeline, asset preloading |
| Sound choice | User chooses sound on/off | Howler.js state initialized after consent |
| Spiral gallery | Cards float in 3D orbit | Three.js camera + textured planes |
| Spiral/list toggle | 3D gallery becomes text list | GSAP state transition + DOM/WebGL sync |
| List view | Large centered project index | DOM text, SplitText hover/reveal |
| Page transition | Move from gallery/list to case page | Mask/clip-path + project media continuity |
| Menu open | Pill expands to navigation | GSAP + CSS masks |
| Mouse trail | Cursor leaves visual trace | Canvas or absolutely positioned particles |
| Video player | Opens/plays project motion | Custom player overlay, keyboard support |
| Footer scroll transition | Lower content transforms on scroll | GSAP ScrollTrigger + Lenis |
Sound is a central part of the portfolio identity, but it must stay user-controlled.
- Ask before enabling sound.
- Keep a persistent audio toggle at bottom-right.
- Use short UI sounds, not constant noise, unless the user explicitly opts into ambient audio.
- Mute videos by default unless opened in a focused player.
- Save sound preference in local storage.
type SoundState = "unknown" | "enabled" | "disabled";
interface AudioStore {
state: SoundState;
muted: boolean;
volume: number;
}| Event | Sound style |
|---|---|
| Enter with sound | Soft whoosh / tonal hit |
| View toggle | Short click or synthetic pop |
| Card hover | Very subtle blip, pitch varies by card |
| Project open | Transition swell |
| Menu open | Rounded tap + low sweep |
<AppShell />
<Loader />
<SoundGate />
<LogoOrb />
<ViewToggle />
<MenuButton />
<MenuOverlay />
<AudioToggle />
<ShowreelBadge />
<SpiralGallery />
<ProjectPlane />
<ProjectList />
<ProjectTransition />
<ProjectPage />
<ProjectMediaGrid />
<VideoPlayer />
<AboutPanel />
<FooterScrollTransition />
<CursorTrail />| Component | Responsibility |
|---|---|
AppShell |
Global fixed controls, route transitions, sound state |
Loader |
Preload assets and reveal entry choices |
ViewToggle |
Switch between spiral and list views |
SpiralGallery |
Render WebGL gallery and input mapping |
ProjectList |
Accessible DOM list of project links |
ProjectTransition |
Animate route changes |
VideoPlayer |
Focused playback with controls |
MenuOverlay |
Full navigation experience |
CursorTrail |
Pointer expression layer |
The public metadata points to an implementation using:
- Nuxt.js / Vue.js
- Three.js
- GSAP
- GSAP ScrollTrigger
- GSAP SplitText
- Lenis for smooth scrolling
- Howler.js for sound
- LottieFiles for vector animations
- Pinia for state
- PWA setup
If recreating the design language in React:
Framework: Next.js or Vite + React
3D: Three.js + React Three Fiber
Animation: GSAP + @gsap/react
Smooth scroll: Lenis
Sound: Howler.js
State: Zustand or Jotai
Video: Native video + custom controls
Assets: WebP/AVIF + MP4/WebMFramework: Nuxt 3
3D: Three.js
Animation: GSAP
Smooth scroll: Lenis
Sound: Howler.js
State: Pinia
Assets: Nuxt image / static media pipelineAn experimental portfolio still needs accessible fallbacks.
- The list view must be keyboard navigable.
- Every project card must have a real link and text label.
- Audio must be opt-in.
- Video player must support keyboard controls.
- Provide
prefers-reduced-motionmode. - Provide
prefers-reduced-transparencyfriendly states where possible. - Ensure
menu,audio, andview togglebuttons have accessible names. - Avoid trapping keyboard focus in WebGL canvas.
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
scroll-behavior: auto !important;
transition-duration: 0.001ms !important;
}
}| Normal | Reduced motion |
|---|---|
| Floating spiral gallery | Static 2D grid or list |
| Page transition masks | Fast fade |
| Cursor trail | Disabled |
| Smooth scroll inertia | Native scroll |
| SplitText reveals | Static text |
The site depends on heavy visual media, so performance must be designed upfront.
- Use low-resolution poster images for initial gallery textures.
- Lazy-load full video only when the user opens a project/player.
- Use
WebPorAVIFfor thumbnails. - Use short looping
mp4/webmclips for motion previews. - Compress textures to power-of-two sizes if used in WebGL.
- Dispose Three.js textures and geometries on route changes.
- Pause or reduce render loop when the tab is hidden.
- Render on demand when gallery is idle if possible.
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.75));
renderer.setSize(width, height);
// Pause on hidden tab
document.addEventListener("visibilitychange", () => {
isRendering = document.visibilityState === "visible";
});| Phase | Assets |
|---|---|
| Initial | Logo, CSS, loader, low-res gallery thumbnails |
| After entry | Home gallery textures, core sounds if enabled |
| On hover/focus | Higher-quality preview if needed |
| On project open | Project hero media and video |
| Below fold | Lazy-loaded case study media |
- Full 3D spiral gallery.
- Edge-pinned controls.
- Large centered list view.
- Staggered editorial project pages.
- Reduce number of visible cards.
- Decrease gallery depth.
- Keep spiral/list toggle.
- Project pages use 8-column or 6-column layout.
- Prefer list view as a strong fallback.
- Spiral can remain but should show fewer cards and less distortion.
- Controls should remain thumb-friendly.
- Menu pill top-right remains useful.
- Audio button bottom-right should not block content.
- Project detail pages become single-column with large title and stacked media.
@media (max-width: 768px) {
.project-hero {
grid-template-columns: 1fr;
gap: 1.5rem;
}
.project-title {
font-size: clamp(3rem, 17vw, 6rem);
}
.project-media-grid {
display: flex;
flex-direction: column;
}
.view-toggle {
top: 1rem;
left: 50%;
transform: translateX(-50%);
}
}The site has a dedicated page transition element in Awwwards. Use transitions to connect gallery objects to detail pages.
-
Card expansion
The selected gallery card scales toward the camera, then the detail page appears from behind it. -
Mask wipe
A black or white circular/organic mask expands from the clicked card or cursor. -
Depth dive
Camera moves into the selected card, then cuts into the project page. -
SplitText reveal
Project title reveals after the background color switches.
const transition = gsap.timeline();
transition
.to(selectedCard, {
scale: 1.35,
z: 2,
duration: 0.55,
ease: "power3.out"
})
.to(pageMask, {
clipPath: "circle(150% at 50% 50%)",
duration: 0.9,
ease: "expo.inOut"
}, "-=0.25")
.from(projectTitleChars, {
yPercent: 110,
opacity: 0,
stagger: 0.012,
duration: 0.8,
ease: "power4.out"
}, "-=0.35");Awwwards identifies a Mouse trail element. The cursor is likely part of the identity layer.
- Keep it subtle.
- Trail should follow fast enough to feel responsive, slow enough to feel physical.
- It should not hide text or controls.
- Disable it on touch devices and reduced-motion mode.
| Option | Pros | Cons |
|---|---|---|
| DOM particles | Easy to implement | Can be expensive if many nodes |
| Canvas trail | Efficient and expressive | Needs manual render loop |
| WebGL particles | Best for complex visuals | More implementation work |
const points: { x: number; y: number; life: number }[] = [];
window.addEventListener("pointermove", (event) => {
points.push({ x: event.clientX, y: event.clientY, life: 1 });
});
function draw() {
ctx.clearRect(0, 0, width, height);
for (const point of points) {
point.life -= 0.025;
ctx.globalAlpha = Math.max(point.life, 0);
ctx.beginPath();
ctx.arc(point.x, point.y, 5 * point.life, 0, Math.PI * 2);
ctx.fill();
}
points = points.filter((point) => point.life > 0);
requestAnimationFrame(draw);
}- Rounded corners: small, not overly soft.
- White page background means media should cast no heavy shadows.
- Use spacing, not borders, to separate content.
- Autoplay only muted previews.
- Click opens focused player or external case link.
Awwwards identifies a dedicated Video player element.
Required states:
idle poster
hover preview
opening transition
playing
paused
muted/unmuted
fullscreen
closed- Use a strong opening transition.
- Keep controls minimal.
- Preserve native keyboard interactions.
- Allow Escape to close.
- Remember audio state.
The home page is not just a list of work. It is a memorable way to browse the work.
The list view is crucial. Always pair experimental navigation with a simple navigation mode.
Buttons are tiny. Labels are direct. Most of the interface disappears behind the work.
The site avoids decorative accent colors because the work is already colorful.
Dark home page creates drama. White detail pages create focus and readability.
A motion designer’s site should not use generic fades. Transitions should demonstrate timing, rhythm, and spatial imagination.
Avoid these mistakes when adapting the style:
- Do not make the 3D gallery so abstract that users cannot find projects.
- Do not autoplay sound.
- Do not hide the list view.
- Do not overload the UI with extra colors.
- Do not use massive videos before first interaction.
- Do not make every element animated all the time.
- Do not sacrifice keyboard navigation for WebGL spectacle.
- Do not copy Pacôme’s project visuals, logo, or exact artwork.
export const projects = [
{
slug: "jupiter",
title: "Jupiter",
description: "Release motion created to mark the launch of a stablecoin.",
thumbnail: "/projects/jupiter/thumb.webp",
media: [
{ type: "video", src: "/projects/jupiter/hero.mp4" },
{ type: "image", src: "/projects/jupiter/frame-01.webp" }
]
}
];Before adding WebGL, create the list view as the canonical navigation.
<nav aria-label="Projects" className="project-list">
{projects.map((project) => (
<a href={`/work/${project.slug}`} key={project.slug}>
{project.title}
</a>
))}
</nav>If WebGL fails, users still get the list.
{supportsWebGL && view === "spiral" ? (
<SpiralGallery projects={projects} />
) : (
<ProjectList projects={projects} />
)}Use GSAP timelines for:
- loader reveal
- view switch
- menu open
- route transition
- SplitText reveals
- ScrollTrigger detail-page reveals
Only after visual UX works.
src/
├── app/
│ ├── layout.tsx
│ ├── page.tsx
│ └── work/[slug]/page.tsx
├── components/
│ ├── app-shell.tsx
│ ├── loader.tsx
│ ├── sound-gate.tsx
│ ├── view-toggle.tsx
│ ├── menu-overlay.tsx
│ ├── audio-toggle.tsx
│ ├── showreel-badge.tsx
│ ├── project-list.tsx
│ ├── spiral-gallery.tsx
│ ├── project-plane.tsx
│ ├── project-media-grid.tsx
│ └── video-player.tsx
├── lib/
│ ├── animation.ts
│ ├── audio.ts
│ ├── projects.ts
│ ├── use-reduced-motion.ts
│ └── webgl.ts
├── styles/
│ ├── globals.css
│ ├── tokens.css
│ └── motion.css
└── public/
└── projects/- Monochrome interface palette.
- Project thumbnails provide color.
- Dark immersive home stage.
- Light editorial project pages.
- Subtle grid texture.
- Fixed edge controls.
- Sound choice before audio plays.
- Spiral gallery.
- List fallback.
- Animated view switch.
- Animated menu open.
- Mouse trail or pointer response.
- Custom page transitions.
- Video player with accessible controls.
- WebGL gracefully degrades.
- Reduced motion mode.
- Lazy-loaded media.
- Render loop optimization.
- Keyboard navigation.
- Sound preference persistence.
- Mobile simplification.
https://pacomepertant.com/https://www.awwwards.com/sites/pacome-pertant-portfoliohttps://www.awwwards.com/inspiration/menu-open-pacome-pertant-portfoliohttps://www.awwwards.com/inspiration/spiral-view-pacome-pertant-portfoliohttps://www.awwwards.com/inspiration/spiral-to-list-pacome-pertant-portfoliohttps://www.awwwards.com/inspiration/video-player-pacome-pertant-portfoliohttps://www.landing.love/sites/pacomepertant/https://recent.design/i/pw6bwd5-pacome-pertant- GSAP public social post about the site and stack
A minimal black-and-white portfolio where the homepage behaves like an interactive 3D showreel, the list view restores clarity, and project pages switch into spacious white editorial layouts so the motion work can breathe.