From e268f2a359bf2f39bb5be3c5723c2a360d9c7d48 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 3 Oct 2026 21:20:37 +0200 Subject: [PATCH] Use Mono.png as profile picture and favicon; sync proof statuses - Dossier proof statuses now come from projects.ts - Mono.png replaces the placeholder silhouette and the SVG favicon - Header, hero and bust tweaks Co-Authored-By: Claude Opus 5.5 --- README.md | 2 +- public/profile/pfp.svg | 11 --- src/app/icon.png | Bin 0 -> 13144 bytes src/app/icon.svg | 5 -- src/components/Bust.tsx | 46 +++++++++--- src/components/Hero.tsx | 127 ++++++++++++++++++++++++++-------- src/components/Mark.tsx | 9 --- src/components/SiteHeader.tsx | 33 +++++++-- src/content/dossier.ts | 23 +++--- src/content/profile.ts | 8 +-- 10 files changed, 178 insertions(+), 86 deletions(-) delete mode 100644 public/profile/pfp.svg create mode 100644 src/app/icon.png delete mode 100644 src/app/icon.svg delete mode 100644 src/components/Mark.tsx diff --git a/README.md b/README.md index b1f1d19..f83fdc2 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ npm run lint - `profile.ts`: name, title, stance, dossier fields, links, map lock. - `dossier.ts`: the five About files. - `projects.ts`: projects, statuses, node-map positions, featured nodes. -- `public/profile/pfp.svg`: placeholder profile picture. Replace this file (or point `profile.pfp` at a new one). +- `public/profile/Mono.png`: profile picture (the favicon is a copy at `src/app/icon.png`). Replace the file, or point `profile.pfp` at a new one. - `public/terrain.svg`: hero terrain contours (Dajt elevation data). - `src/app/globals.css`: colour tokens, bracket/grid utilities, and all motion. diff --git a/public/profile/pfp.svg b/public/profile/pfp.svg deleted file mode 100644 index 876035b..0000000 --- a/public/profile/pfp.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/app/icon.png b/src/app/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0a70baf57f5e860aeac7c2bbbb7e241831eef95e GIT binary patch literal 13144 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 ZM^9=@p(mHd6>bf - - - - diff --git a/src/components/Bust.tsx b/src/components/Bust.tsx index b4220ae..aea43b1 100644 --- a/src/components/Bust.tsx +++ b/src/components/Bust.tsx @@ -8,17 +8,31 @@ import { useRef } from "react"; * "wireframe", a scan sweeps across and resolves it to solid, and on desktop * the layers tilt apart slightly with the pointer. No 3D library needed. */ -export function Bust({ src, delay = "0s", className = "" }: { src: string; delay?: string; className?: string }) { +export function Bust({ + src, + delay = "0s", + className = "", +}: { + src: string; + delay?: string; + className?: string; +}) { const tiltRef = useRef(null); const meshRef = useRef(null); function onMove(e: React.PointerEvent) { - if (e.pointerType !== "mouse" || matchMedia("(prefers-reduced-motion: reduce)").matches) return; + if ( + e.pointerType !== "mouse" || + matchMedia("(prefers-reduced-motion: reduce)").matches + ) + return; const r = e.currentTarget.getBoundingClientRect(); const x = (e.clientX - r.left) / r.width - 0.5; const y = (e.clientY - r.top) / r.height - 0.5; - if (tiltRef.current) tiltRef.current.style.transform = `rotateX(${(-y * 8).toFixed(2)}deg) rotateY(${(x * 10).toFixed(2)}deg)`; - if (meshRef.current) meshRef.current.style.transform = `translate(${(x * -6).toFixed(1)}px, ${(y * -6).toFixed(1)}px)`; + if (tiltRef.current) + tiltRef.current.style.transform = `rotateX(${(-y * 8).toFixed(2)}deg) rotateY(${(x * 10).toFixed(2)}deg)`; + if (meshRef.current) + meshRef.current.style.transform = `translate(${(x * -6).toFixed(1)}px, ${(y * -6).toFixed(1)}px)`; } function onLeave() { @@ -28,11 +42,14 @@ export function Bust({ src, delay = "0s", className = "" }: { src: string; delay return (
-
+
{/* wireframe pass */}
{/* solid pass */} -
- Profile picture +
+ Profile picture
{/* residual mesh that floats a few px above the photo */} -
{/* Corner telemetry, pinned to the bottom of the screen-tall hero */} -