// 4D Agency — interactive bits const { useState, useEffect, useRef } = React; /* ============================================================ TRACK DATA ============================================================ */ const TRACKS = [ { id: 1, src: "tracks/01.mp3", cover: "tracks/cover01.jpg", name: "Valse d'un printemps", style: "Nostalgie · Orchestre de chambre", bpm: "160 BPM", dur: "01:39", key: "F minor" }, { id: 2, src: "tracks/02.mp3", cover: "tracks/cover02.jpg", name: "Village", style: "Exploration Médieval · Orchestral", bpm: "87 BPM", dur: "01:01", key: "B minor" }, { id: 3, src: "tracks/03.mp3", cover: "tracks/cover03.jpg", name: "Le Mafieux", style: "Tension · Orchestral", bpm: "90 BPM", dur: "01:04", key: "E minor" }, { id: 4, src: "tracks/04.mp3", cover: "tracks/cover04.jpg", name: "Excalibur", style: "Epique · Orchestral", bpm: "122 BPM", dur: "01:18", key: "D minor" }, { id: 5, src: "tracks/05.mp3", cover: "tracks/cover05.jpg", name: "Temps qui passe", style: "Ambiance · Synthétiseurs", bpm: "77 BPM", dur: "02:29", key: "F# minor" }]; /* ============================================================ NAVIGATION ============================================================ */ function Nav() { return ( ); } /* ============================================================ HERO ============================================================ */ function Hero() { return (
4D · Agency COMPOSITEURS POUR L'IMAGE Paris / Remote

Créer
des musiques
immersives
pour vos oeuvres
narratives.

Votre partenaire musical pour renforcer la narration, l’émotion et l’identité sonore de vos projets - de la première esquisse thématique au master prêt à l'intégration.

Parlez-nous de votre projet Écouter nos extraits
Disponibilité limitée pour conserver la qualité.
{/*
14 Bandes-son livrées 36 mois Studios partenaires actifs
*/}
Défilez Acte I
); } /* ============================================================ MARQUEE BAND ============================================================ */ function Marquee() { const items = [ "Jeu narratif", "Film", "Serie", "Documentaire", "Jeu narratif", "Film", "Serie", "Documentaire", "Jeu narratif", "Film"]; const block = {items.map((t, i) => {t} )} ; return ( ); } /* ============================================================ PROCESS ============================================================ */ function Process() { const steps = [ { roman: "I", title: "Composition", lede: "Conception des thèmes et motifs.", body: "Nous traduisons vos intentions narratives et émotionnelles en idées musicales cohérente et identifiable.", tag: "Brief · références · démos thématiques" }, { roman: "II", title: "Orchestration", lede: "Instruments, textures, émotion.", body: "Chaque thème se déploie à travers une palette sonore sur mesure, où instruments acoustiques, textures et synthétiseurs définissent sa couleur émotionnelle.", tag: "Maquette · prise live · sound design" }, { roman: "III", title: "Mixing / Mastering", lede: "Prêt à l’intégration.", body: "Exports, stems et masters préparés selon les contraintes techniques de votre production, avec une livraison claire et prête à l’intégration.", tag: "Stems · loops · masters · documentation" }]; return (
Acte I — Le processus
02 ·

Le processus

Trois étapes pour creer une musique cohérente, immersive et prête à l'intégration.
{steps.map((s, i) =>
{s.roman}

{s.title}

{s.lede}

{s.body}

{s.tag} ·
)}
BOITE À OUTILS · {["Cubase 13", "Kontakt 8", "Orchestral Tools", "Vienna Ensemble Pro", "Serum", "Omnisphere", "Fabfilter"].map((t) => {t} )}
); } /* ============================================================ EXCERPTS PLAYER ============================================================ */ function makeFallbackBars(trackId) { const seed = trackId * 37 + 11; return Array.from({ length: 84 }, (_, i) => { const v = Math.sin((i + seed) * 0.27) * 0.5 + Math.cos((i + seed) * 0.11) * 0.3 + 0.55; return Math.max(0.18, Math.min(1, v + Math.sin(i * 0.7 + seed) * 0.18)); }); } function Excerpts() { const [active, setActive] = useState(0); const [playing, setPlaying] = useState(false); const [progress, setProgress] = useState(0); const [duration, setDuration] = useState(0); const audioRef = useRef(null); const wantPlay = useRef(false); // intent ref — stable across closures const waveformsRef = useRef({}); const blobUrlsRef = useRef({}); const [bars, setBars] = useState(() => makeFallbackBars(TRACKS[0].id)); // Create the Audio element once if (!audioRef.current) { audioRef.current = new Audio(); audioRef.current.preload = "auto"; } // Wire up persistent event listeners once useEffect(() => { const a = audioRef.current; const onTime = () => { if (a.duration) setProgress(a.currentTime / a.duration); }; const onMeta = () => setDuration(a.duration); const onEnd = () => { setPlaying(false); setProgress(0); wantPlay.current = false; }; a.addEventListener("timeupdate", onTime); a.addEventListener("loadedmetadata", onMeta); a.addEventListener("ended", onEnd); return () => { a.removeEventListener("timeupdate", onTime); a.removeEventListener("loadedmetadata", onMeta); a.removeEventListener("ended", onEnd); a.pause(); }; }, []); // Fetch track as blob URL (Chrome can seek blob URLs without range requests), // then decode waveform from the same buffer — single download for both. useEffect(() => { const a = audioRef.current; const id = TRACKS[active].id; const src = TRACKS[active].src; setProgress(0); setDuration(0); // Fast path: already cached if (blobUrlsRef.current[id]) { a.src = blobUrlsRef.current[id]; if (wantPlay.current) a.play().catch(() => {}); if (waveformsRef.current[id]) setBars(waveformsRef.current[id]); else setBars(makeFallbackBars(id)); return; } setBars(makeFallbackBars(id)); let dead = false; fetch(src) .then(r => { if (!r.ok) throw new Error(); return r.arrayBuffer(); }) .then(buf => { if (dead) return; // Decode waveform — slice so decodeAudioData doesn't detach original buf const ctx = new (window.AudioContext || window["webkitAudioContext"])(); ctx.decodeAudioData(buf.slice(0), decoded => { ctx.close(); if (dead) return; const ch = decoded.getChannelData(0); const seg = Math.floor(ch.length / 84); const rms = Array.from({ length: 84 }, (_, i) => { let s = 0, off = i * seg; for (let j = off; j < off + seg; j++) s += ch[j] * ch[j]; return Math.sqrt(s / seg); }); const mx = Math.max(...rms, 1e-6); const normalized = rms.map(v => 0.18 + (v / mx) * 0.82); waveformsRef.current[id] = normalized; if (!dead) setBars(normalized); }, () => { ctx.close(); }); // Blob URL → Chrome can seek without HTTP range requests const url = URL.createObjectURL(new Blob([buf], { type: "audio/mpeg" })); blobUrlsRef.current[id] = url; a.src = url; if (wantPlay.current) a.play().catch(() => {}); }) .catch(() => { if (dead) return; a.src = src; // fallback to direct src if (wantPlay.current) a.play().catch(() => {}); }); return () => { dead = true; }; }, [active]); function togglePlay() { const a = audioRef.current; if (playing) { a.pause(); wantPlay.current = false; setPlaying(false); } else { wantPlay.current = true; a.play().catch(() => {}); setPlaying(true); } } function selectTrack(i) { wantPlay.current = true; setPlaying(true); setActive(i); // triggers useEffect → loads src → plays } function seekOnWaveform(e) { const a = audioRef.current; if (!a.duration) return; const r = e.currentTarget.getBoundingClientRect(); const ratio = Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)); a.currentTime = ratio * a.duration; setProgress(ratio); } const track = TRACKS[active]; const fmt = sec => `${Math.floor(sec / 60)}:${String(Math.floor(sec % 60)).padStart(2, "0")}`; const curSec = duration ? progress * duration : 0; const durStr = duration ? fmt(duration) : track.dur; return (
Acte II — Extraits
03 ·

Extraits musicaux

Cinq pièces sélectionnées réalisées en 2025–2026. Casque recommandé pour entendre les détails.
{track.cover ? {track.name} : {track.id.toString().padStart(2, "0")} · cover }
4D Agency original

{track.name}

{track.style}
BPM · {track.bpm.replace(" BPM", "")} Key · {track.key}
{bars.map((h, i) => ( ))}
{fmt(curSec)} / {durStr} {playing ? "● PLAYING" : "○ PAUSED"}
{TRACKS.map((t, i) => (
selectTrack(i)}> {String(i + 1).padStart(2, "0")}
{t.name}
{t.style}
{t.bpm} {t.dur} {i === active && playing ? "▶" : ""}
))}
Chaque extrait présenté est une composition originale créée pour cette démo et n’a pas encore été exploité dans une production.
Démarrer notre collaboration Demander un devis
); } /* ============================================================ MANIFESTO ============================================================ */ function Manifesto() { return (
Acte III — Qui sommes-nous
04 ·

Manifeste - qui sommes-nous

Deux sensibilités, une même exigence : composer des musiques qui portent l’identité et l’émotion de votre projet.
4D Agency — portrait studio
Plate I 4D Agency

4D Agency est née d’une amitié : celle d’un compositeur formé au conservatoire et d’un passionné de création sonore moderne. Deux écoles, une même conviction: utiliser les nouveaux outils de production musicale au service de la composition, jamais à son détriment.

Nous composons des bandes-son immersives et thématiques pour l’image et l’interactif : films, séries, documentaires et jeux vidéo. Chaque projet est traité comme une œuvre singulière, avec son propre rythme, ses tensions et ses silences.

« Dans un projet audiovisuel, la musique devient indissociable du projet et doit être portée par une ambition à sa hauteur. » - principe fondateur, 4D Agency

Notre approche allie rigueur de composition, créativité et communication : échanges réguliers, délais clairs et retours intégrés à chaque étape du projet.

Florian Nephtali COMPOSITEUR · CO-FONDATEUR
Ayemen El Hor COMPOSITEUR · CO-FONDATEUR
); } /* ============================================================ WHY US ============================================================ */ function WhyUs() { const benefits = [ { n: "01", title: "Identité sonore cohérente", body: "Un thème principal et des variations pensées pour marquer durablement l’univers et la mémoire du public.", ico: }, { n: "02", title: "Collaboration fluide", body: "Un seul point de contact, des notes structurées, un cloud partagé. Vos retours sont intégrés en jours, pas en semaines.", ico: }, { n: "03", title: "Production rapide & structurée", body: "Un planning découpé en jalons clairs. Pas de surprise, pas de débordement.", ico: }, { n: "04", title: "Qualité audio pro", body: "Des banques de sons et effets haut de gamme au service d’une production sonore riche et précise.", ico: }]; return (
Acte IV — Pourquoi 4D
05 ·

Pourquoi 4D Agency

Ce que vous gagnez en nous confiant la bande-son de votre projet.
{benefits.map((b) =>
{b.ico} {b.n}

{b.title}

{b.body}

)}
{/*

4D a su trouver la voix de notre monde dès la première démo. Leur thème principal a survécu à six mois d’itérations gameplay — et c’est lui qu’on entend dans la bande-annonce.

CN Camille Noiret · Creative Director, Studio Veilleur
98% Projets livrés dans les délais
12h Temps de réponse moyen
2 / 8 Slots projets ouverts ce trimestre
*/}
); } /* ============================================================ CTA BAND ============================================================ */ function CtaBand() { return (
Acte V · La rencontre

Lançons votre
bande-son.

Un appel de 30 minutes suffit pour savoir si nous pouvons collaborer. Apportez vos références, votre univers ou vos doutes, nous vous aiderons à définir une direction musicale claire pour votre projet.

Parlez-nous de votre projet Réserver un échange Lancer une collaboration
); } /* ============================================================ FOOTER ============================================================ */ function Footer() { return ( ); } /* ============================================================ APP ============================================================ */ function App() { const TweaksUI = window.TweaksUI; return ( <>