Valentin Ledent

French designer, art director, brand and graphic designer currently based in Paris.
My practice lies at the intersection of strategy, branding, visual identity, typography,
digital and editorial design — Shaping brands that map emotions and ideas into clear visual forms.

After completing a Foundation Year in Applied Arts (MANAA), Two-year Degree
in Graphic Design and a Master’s degree in Art Direction, Brand Strategy and Design,
I approach each project like a map to be drawn — defining landscapes of meaning and form.

Portfolio available upon request.

You can find me here ↓

ledent.valentin@gmail.com Linkedin Instagram

Agency & Studio Experience

Vaadigm, Graphéine, Havas Paris (Branding departement),
Pilote Paris, W Conran Design

(() => { // ——— Paramètres à personnaliser ——— const GIF_URL = "./img/portfolio-boussole-image-40.mp4"; // MP4 ou GIF const QUERY_KEY = "intro"; // ex: ?intro=1 pour déclencher const EXPIRES_ISO = "2026-01-31"; // date limite d’affichage (YYYY-MM-DD) const ALWAYS_ON = false; // const POSTER = "./img/portfolio-boussole-image-40-poster.jpg"; // (optionnel) image d’attente // ——— Helpers ——— function isVideoUrl(u){ return /\.mp4(\?.*)?$/i.test(u); } const qs = new URLSearchParams(location.search); const today = new Date(); const expires = new Date(EXPIRES_ISO + "T23:59:59"); const hasParam = qs.has(QUERY_KEY); const notExpired = isFinite(expires) ? (today <= expires) : true; function shouldShowIntro() { if (!notExpired) return false; if (sessionStorage.getItem("introSeen") === "1") return false; // pas deux fois par session return hasParam || ALWAYS_ON; } // ——— Styles ——— const css = ` .intro-overlay { position: fixed; inset: 0; z-index: 9000; background: rgba(255,255,255,0.95); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); display: none; align-items: center; justify-content: center; } .intro-overlay.on { display: flex; animation: introFade .25s ease-out; } @keyframes introFade { from{opacity:0} to{opacity:1} } .intro-dialog { position: relative; max-width: 92vw; max-height: 92vh; display:flex; align-items:center; justify-content:center; outline: none; } .intro-dialog img, .intro-dialog video { display:block; max-width:92vw; max-height:92vh; width:auto; height:auto; } .intro-close { position:absolute; top:-12px; right:-12px; border:none; border-radius:999px; padding:10px 12px; background:#111; color:#fff; font:700 12px/1, system-ui, -apple-system, "Segoe UI", Roboto, Arial; cursor:pointer; box-shadow:0 4px 16px rgba(0,0,0,.2); transform:translate(8px, -8px); } .intro-close:focus { outline: 2px solid #111; outline-offset: 2px; } .intro-skip { position: absolute; /* plus bas = plus proche du bord bas, donc une valeur plus petite */ bottom: clamp(8px, 2vh, 16px); left: 50%; transform: translateX(-50%); /* Area Normal + fallback */ font-family: "Area Normal", system-ui, -apple-system, "Segoe UI", Roboto, Arial; font-weight: 600; font-size: 13px; line-height: 1.25; color: #111; /* bien noir */ opacity: .85; /* un poil plus lisible */ pointer-events: none; /* reste non cliquable, c’est un hint */ user-select: none; } } @media (max-width:600px){ .intro-close { top:-8px; right:-8px; transform:translate(4px, -4px); } } `; const style = document.createElement("style"); style.textContent = css; document.head.appendChild(style); // ——— DOM overlay ——— const overlay = document.createElement("div"); overlay.className = "intro-overlay"; overlay.setAttribute("role","dialog"); overlay.setAttribute("aria-modal","true"); overlay.setAttribute("aria-label","Intro"); const dialog = document.createElement("div"); dialog.className = "intro-dialog"; dialog.tabIndex = -1; let mediaEl; if (isVideoUrl(GIF_URL)) { const v = document.createElement("video"); v.autoplay = true; v.loop = true; v.muted = true; v.playsInline = true; // iOS/Safari v.preload = "metadata"; // if (POSTER) v.poster = POSTER; // (décommente si tu as un poster) // v.src sera défini quand on ouvre l’intro mediaEl = v; } else { const im = document.createElement("img"); im.src = GIF_URL; im.alt = "Intro"; mediaEl = im; } const btn = document.createElement("button"); btn.className = "intro-close"; btn.type = "button"; btn.textContent = "x"; const skip = document.createElement("div"); skip.className = "intro-skip"; skip.textContent = "Cliquez hors de l’image ou sur la croix pour entrer"; dialog.appendChild(mediaEl); dialog.appendChild(btn); overlay.appendChild(dialog); overlay.appendChild(skip); document.body.appendChild(overlay); // ——— Fermeture + cleanup ——— const closeIntro = () => { if (mediaEl && mediaEl.tagName === "VIDEO") { try { mediaEl.pause(); } catch {} mediaEl.removeAttribute("src"); mediaEl.load(); // libère le buffer } overlay.classList.remove("on"); sessionStorage.setItem("introSeen","1"); }; btn.addEventListener("click", (e) => { e.stopPropagation(); closeIntro(); }); overlay.addEventListener("click", (e) => { if (!dialog.contains(e.target)) closeIntro(); }); document.addEventListener("keydown", (e) => { if (overlay.classList.contains("on") && (e.key === "Escape" || e.key === "Esc")) closeIntro(); }); // ——— Affichage conditionnel ——— if (shouldShowIntro()) { overlay.classList.add("on"); if (mediaEl && mediaEl.tagName === "VIDEO" && !mediaEl.src) { mediaEl.src = GIF_URL; mediaEl.load(); mediaEl.play().catch(()=>{}); } // iOS/Safari: tenter un play explicite juste après l’insertion if (mediaEl && mediaEl.tagName === "VIDEO") { setTimeout(() => { mediaEl.play().catch(()=>{}); }, 0); } setTimeout(() => btn.focus(), 0); } // ——— Exposition utilitaire (facultatif) ——— // window.showIntro = () => { sessionStorage.removeItem("introSeen"); overlay.classList.add("on"); if(mediaEl?.tagName==="VIDEO") mediaEl.play().catch(()=>{}); }; // window.hideIntro = closeIntro; })(); ///