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 <[email protected]>
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 168 200">
|
||||
<!-- PLACEHOLDER profile picture: replace this file with the real one. -->
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#3a4247"/>
|
||||
<stop offset="1" stop-color="#101315"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#g)" d="M84,28 C108,28 122,46 122,72 C122,96 112,114 100,122 L102,136 C130,142 156,156 164,182 L166,200 L2,200 L4,182 C12,156 38,142 66,136 L68,122 C56,114 46,96 46,72 C46,46 60,28 84,28Z"/>
|
||||
<path fill="none" stroke="#f2f4f5" stroke-opacity=".3" d="M84,28 C108,28 122,46 122,72 C122,96 112,114 100,122 L102,136 C130,142 156,156 164,182 L166,200 L2,200 L4,182 C12,156 38,142 66,136 L68,122 C56,114 46,96 46,72 C46,46 60,28 84,28Z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 788 B |
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
||||
<rect width="24" height="24" fill="#050607"/>
|
||||
<path d="M3,8.5 V3 H8.5 M15.5,3 H21 V8.5 M21,15.5 V21 H15.5 M8.5,21 H3 V15.5" stroke="#f2f4f5" stroke-width="1.8"/>
|
||||
<rect x="9.25" y="9.25" width="5.5" height="5.5" fill="#4dff95"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 314 B |
+36
-10
@@ -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<HTMLDivElement>(null);
|
||||
const meshRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
function onMove(e: React.PointerEvent<HTMLDivElement>) {
|
||||
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 (
|
||||
<div
|
||||
className={`relative aspect-[168/200] [perspective:600px] ${className}`}
|
||||
className={`relative aspect-square [perspective:600px] ${className}`}
|
||||
onPointerMove={onMove}
|
||||
onPointerLeave={onLeave}
|
||||
>
|
||||
<div ref={tiltRef} className="absolute inset-0 transition-transform duration-200 ease-out [transform-style:preserve-3d]">
|
||||
<div
|
||||
ref={tiltRef}
|
||||
className="absolute inset-0 transition-transform duration-200 ease-out [transform-style:preserve-3d]"
|
||||
>
|
||||
{/* wireframe pass */}
|
||||
<div className="absolute inset-0 [mask-image:repeating-linear-gradient(0deg,#000_0_1px,transparent_1px_5px)]">
|
||||
<Image
|
||||
@@ -44,15 +61,24 @@ export function Bust({ src, delay = "0s", className = "" }: { src: string; delay
|
||||
/>
|
||||
</div>
|
||||
{/* solid pass */}
|
||||
<div className="bust-solid seq absolute inset-0" style={{ "--d": delay } as React.CSSProperties}>
|
||||
<Image src={src} alt="Profile picture" fill sizes="168px" className="object-cover" />
|
||||
<div
|
||||
className="bust-solid seq absolute inset-0"
|
||||
style={{ "--d": delay } as React.CSSProperties}
|
||||
>
|
||||
<Image
|
||||
src={src}
|
||||
alt="Profile picture"
|
||||
fill
|
||||
sizes="168px"
|
||||
className="object-cover"
|
||||
/>
|
||||
</div>
|
||||
{/* residual mesh that floats a few px above the photo */}
|
||||
<div
|
||||
{/*<div
|
||||
ref={meshRef}
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 opacity-[0.12] transition-transform duration-200 ease-out [background-image:repeating-linear-gradient(0deg,#f2f4f5_0_1px,transparent_1px_8px)] [mask-image:linear-gradient(90deg,#000,transparent_70%)]"
|
||||
/>
|
||||
/>*/}
|
||||
{/* scan line */}
|
||||
<div
|
||||
aria-hidden="true"
|
||||
|
||||
+96
-27
@@ -1,5 +1,10 @@
|
||||
import Link from "next/link";
|
||||
import { dossierFields, lock, profile, type DossierField } from "@/content/profile";
|
||||
import {
|
||||
dossierFields,
|
||||
lock,
|
||||
profile,
|
||||
type DossierField,
|
||||
} from "@/content/profile";
|
||||
import { Bust } from "./Bust";
|
||||
import { Scramble } from "./Scramble";
|
||||
import { LocalTime, SessionStamp } from "./Telemetry";
|
||||
@@ -12,22 +17,42 @@ const d = (s: number) => ({ "--d": `${s}s` }) as React.CSSProperties;
|
||||
const DOSSIER_START = 1.35;
|
||||
const DOSSIER_STAGGER = 0.14;
|
||||
|
||||
function DossierList({ fields, className = "" }: { fields: DossierField[]; className?: string }) {
|
||||
function DossierList({
|
||||
fields,
|
||||
className = "",
|
||||
}: {
|
||||
fields: DossierField[];
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<dl className={`grid grid-cols-[124px_minmax(0,1fr)] gap-y-2.5 border-t border-white/8 pt-[18px] text-xs leading-[1.45] xl:grid-cols-[116px_minmax(0,1fr)] ${className}`}>
|
||||
<dl
|
||||
className={`grid grid-cols-[124px_minmax(0,1fr)] gap-y-2.5 border-t border-white/8 pt-[18px] text-xs leading-[1.45] xl:grid-cols-[116px_minmax(0,1fr)] ${className}`}
|
||||
>
|
||||
{fields.map((f, i) => {
|
||||
const delay = DOSSIER_START + i * DOSSIER_STAGGER;
|
||||
return (
|
||||
<div key={f.label} className="contents">
|
||||
<dt className="pt-[3px] text-[9px] uppercase tracking-[0.22em] text-mute">{f.label}</dt>
|
||||
<dt className="pt-[3px] text-[9px] uppercase tracking-[0.22em] text-mute">
|
||||
{f.label}
|
||||
</dt>
|
||||
<dd className="flex flex-wrap gap-x-3.5">
|
||||
{f.links
|
||||
? f.links.map((l, j) => (
|
||||
<a key={l.href} href={l.href} className="border-b border-white/25 hover:border-accent">
|
||||
<Scramble text={l.label} delay={delay + j * 0.2} step={30} />
|
||||
{f.links ? (
|
||||
f.links.map((l, j) => (
|
||||
<a
|
||||
key={l.href}
|
||||
href={l.href}
|
||||
className="border-b border-white/25 hover:border-accent"
|
||||
>
|
||||
<Scramble
|
||||
text={l.label}
|
||||
delay={delay + j * 0.2}
|
||||
step={30}
|
||||
/>
|
||||
</a>
|
||||
))
|
||||
: <Scramble text={f.value} delay={delay} step={30} />}
|
||||
) : (
|
||||
<Scramble text={f.value} delay={delay} step={30} />
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
);
|
||||
@@ -38,7 +63,10 @@ function DossierList({ fields, className = "" }: { fields: DossierField[]; class
|
||||
|
||||
export function Hero() {
|
||||
return (
|
||||
<section aria-labelledby="hero-title" className="relative overflow-hidden border-b border-line xl:flex xl:min-h-dvh xl:items-center">
|
||||
<section
|
||||
aria-labelledby="hero-title"
|
||||
className="relative overflow-hidden border-b border-line xl:flex xl:min-h-dvh xl:items-center"
|
||||
>
|
||||
<TerrainLayer />
|
||||
|
||||
<div className="relative z-10 mx-auto w-full max-w-[1440px] pt-[68px] md:pt-[84px] xl:h-[864px]">
|
||||
@@ -57,7 +85,12 @@ export function Hero() {
|
||||
<Scramble text="LOCK ACQUIRED" delay={0.85} step={35} nowrap />
|
||||
</div>
|
||||
<div>
|
||||
<Scramble text={`${lock.lat} · ${lock.lon}`} delay={0.95} step={30} nowrap />
|
||||
<Scramble
|
||||
text={`${lock.lat} · ${lock.lon}`}
|
||||
delay={0.95}
|
||||
step={30}
|
||||
nowrap
|
||||
/>
|
||||
</div>
|
||||
<div className="uppercase">
|
||||
<Scramble text={lock.place} delay={1.05} step={30} nowrap />
|
||||
@@ -67,7 +100,9 @@ export function Hero() {
|
||||
className="trace seq absolute top-[233px] right-[510px] left-[calc(var(--lx)+66px)] hidden h-px bg-accent/55 xl:block"
|
||||
style={d(0.9)}
|
||||
>
|
||||
<span className="absolute -top-4 left-0 text-[9px] whitespace-nowrap tracking-[0.2em] text-accent">TRACE ▸ 0001</span>
|
||||
<span className="absolute -top-4 left-0 text-[9px] whitespace-nowrap tracking-[0.2em] text-accent">
|
||||
TRACE ▸ 0001
|
||||
</span>
|
||||
<span className="absolute -top-[3px] -right-[3px] size-[7px] bg-accent" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -76,7 +111,11 @@ export function Hero() {
|
||||
{/* Headline */}
|
||||
<div className="xl:absolute xl:top-[364px] xl:left-16 xl:w-[620px]">
|
||||
<p className="mb-3 text-[9px] tracking-[0.28em] text-mute xl:mb-5 xl:text-[10px] xl:tracking-[0.3em]">
|
||||
<Scramble text="TARGET RESOLVED · SUBJECT 0001" delay={0.2} step={15} />
|
||||
<Scramble
|
||||
text="TARGET RESOLVED · SUBJECT 0001"
|
||||
delay={0.2}
|
||||
step={15}
|
||||
/>
|
||||
</p>
|
||||
<h1
|
||||
id="hero-title"
|
||||
@@ -86,10 +125,13 @@ export function Hero() {
|
||||
<br />
|
||||
<Scramble text="& BUILDER" delay={0.5} step={35} nowrap />
|
||||
</h1>
|
||||
<p className="mt-4 text-[15px] leading-normal text-ink-2 xl:mt-6 xl:text-[17px]">
|
||||
{/*<p className="mt-4 text-[15px] leading-normal text-ink-2 xl:mt-6 xl:text-[17px]">
|
||||
<Scramble text={profile.stance} delay={0.7} step={15} />
|
||||
</p>
|
||||
<div className="resolve seq mt-7 flex flex-col gap-2.5 sm:flex-row sm:flex-wrap sm:gap-3 xl:mt-10" style={d(1.4)}>
|
||||
</p>*/}
|
||||
<div
|
||||
className="resolve seq mt-7 flex flex-col gap-2.5 sm:flex-row sm:flex-wrap sm:gap-3 xl:mt-10"
|
||||
style={d(1.4)}
|
||||
>
|
||||
<Link
|
||||
href="/projects/"
|
||||
className="inline-flex min-h-12 items-center justify-between gap-3 bg-ink px-[22px] text-xs font-medium tracking-[0.2em] text-night transition-colors hover:bg-accent hover:text-night"
|
||||
@@ -100,7 +142,7 @@ export function Hero() {
|
||||
href="/about/"
|
||||
className="bracket inline-flex min-h-12 items-center justify-between gap-3 border border-white/12 px-[22px] text-xs tracking-[0.2em] transition-colors [--bc:rgb(242_244_245/0.6)] hover:border-transparent hover:text-accent hover:[--bc:var(--color-accent)]"
|
||||
>
|
||||
OPEN DOSSIER <span aria-hidden="true">↗</span>
|
||||
ABOUT ME <span aria-hidden="true">↗</span>
|
||||
</Link>
|
||||
</div>
|
||||
<DossierList fields={dossierFields} className="mt-9 xl:hidden" />
|
||||
@@ -120,37 +162,64 @@ export function Hero() {
|
||||
<figure className="bracket w-[112px] flex-none [--bc:rgb(242_244_245/0.4)] xl:w-[168px]">
|
||||
<Bust src={profile.pfp} delay="1.2s" />
|
||||
{profile.pfpIsPlaceholder && (
|
||||
<figcaption className="pt-2 pb-0.5 text-[9px] tracking-[0.2em] text-mute max-xl:hidden">PFP · PLACEHOLDER</figcaption>
|
||||
<figcaption className="pt-2 pb-0.5 text-[9px] tracking-[0.2em] text-mute max-xl:hidden">
|
||||
PFP · PLACEHOLDER
|
||||
</figcaption>
|
||||
)}
|
||||
</figure>
|
||||
<div className="min-w-0 xl:pt-1">
|
||||
<div className="text-[9px] tracking-[0.24em] text-mute">ALIAS</div>
|
||||
<h2 id="profile-name" className="mt-1.5 font-display text-[28px] leading-none font-semibold tracking-[0.06em] uppercase xl:text-4xl">
|
||||
<Scramble text={profile.displayName.toUpperCase()} delay={1.2} step={90} nowrap />
|
||||
<div className="text-[9px] tracking-[0.24em] text-mute">
|
||||
ALIAS
|
||||
</div>
|
||||
<h2
|
||||
id="profile-name"
|
||||
className="mt-1.5 font-display text-[28px] leading-none font-semibold tracking-[0.06em] uppercase xl:text-4xl"
|
||||
>
|
||||
<Scramble
|
||||
text={profile.displayName.toUpperCase()}
|
||||
delay={1.2}
|
||||
step={90}
|
||||
nowrap
|
||||
/>
|
||||
</h2>
|
||||
<div className="mt-2.5 text-[9px] leading-[1.9] tracking-[0.16em] text-mute xl:mt-[22px]">
|
||||
<div className="max-xl:hidden">MESH 2.5D · RESOLVED</div>
|
||||
<div className="max-xl:hidden">CLEARANCE · PUBLIC</div>
|
||||
{profile.pfpIsPlaceholder && <div className="xl:hidden">PFP · PLACEHOLDER</div>}
|
||||
{profile.pfpIsPlaceholder && (
|
||||
<div className="xl:hidden">PFP · PLACEHOLDER</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<DossierList fields={dossierFields} className="mt-[22px] hidden xl:grid" />
|
||||
<DossierList
|
||||
fields={dossierFields}
|
||||
className="mt-[22px] hidden xl:grid"
|
||||
/>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="pointer-events-none absolute inset-x-0 bottom-0 z-10 hidden xl:block">
|
||||
<div className="relative mx-auto h-20 max-w-[1440px]">
|
||||
{/* Corner telemetry, pinned to the bottom of the screen-tall hero */}
|
||||
<div aria-hidden="true" className="appear seq absolute bottom-[22px] left-16 hidden text-[9px] leading-[1.8] tracking-[0.16em] text-mute/70 xl:block" style={d(0.2)}>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="appear seq absolute bottom-[22px] left-16 hidden text-[9px] leading-[1.8] tracking-[0.16em] text-mute/70 xl:block"
|
||||
style={d(0.2)}
|
||||
>
|
||||
<SessionStamp />
|
||||
</div>
|
||||
<div aria-hidden="true" className="absolute bottom-[22px] left-1/2 hidden -translate-x-1/2 text-[9px] tracking-[0.3em] text-mute xl:block">
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute bottom-[22px] left-1/2 hidden -translate-x-1/2 text-[9px] tracking-[0.3em] text-mute xl:block"
|
||||
>
|
||||
SCROLL ▾ NODES
|
||||
</div>
|
||||
<div aria-hidden="true" className="appear seq absolute right-16 bottom-[22px] hidden text-right text-[9px] leading-[1.8] tracking-[0.16em] xl:block" style={d(0.2)}>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="appear seq absolute right-16 bottom-[22px] hidden text-right text-[9px] leading-[1.8] tracking-[0.16em] xl:block"
|
||||
style={d(0.2)}
|
||||
>
|
||||
<div className="text-accent">
|
||||
<LocalTime />
|
||||
</div>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
/** selimaj.dev mark: a lock bracket around a point. */
|
||||
export function Mark({ size = 24, className }: { size?: number; className?: string }) {
|
||||
return (
|
||||
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden="true" className={className}>
|
||||
<path d="M2.5,8 V2.5 H8 M16,2.5 H21.5 V8 M21.5,16 V21.5 H16 M8,21.5 H2.5 V16" stroke="currentColor" strokeWidth="1.3" />
|
||||
<rect x="9.5" y="9.5" width="5" height="5" fill="currentColor" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { Mark } from "./Mark";
|
||||
import { SessionClock } from "./Telemetry";
|
||||
|
||||
const links = [
|
||||
@@ -13,7 +12,9 @@ const links = [
|
||||
];
|
||||
|
||||
const isCurrent = (pathname: string, href: string) =>
|
||||
href === "/" ? pathname === "/" : pathname.startsWith(href.replace(/\/$/, ""));
|
||||
href === "/"
|
||||
? pathname === "/"
|
||||
: pathname.startsWith(href.replace(/\/$/, ""));
|
||||
|
||||
export function SiteHeader() {
|
||||
const pathname = usePathname();
|
||||
@@ -25,8 +26,11 @@ export function SiteHeader() {
|
||||
className={`absolute inset-x-0 top-0 z-30 ${isHome ? "" : "border-b border-line"}`}
|
||||
>
|
||||
<div className="mx-auto flex max-w-[1440px] items-center justify-between gap-6 px-4 py-3 md:px-16 md:py-[22px]">
|
||||
<Link href="/" className="flex min-h-11 items-center gap-3" aria-label="selimaj.dev home">
|
||||
<Mark />
|
||||
<Link
|
||||
href="/"
|
||||
className="flex min-h-11 items-center gap-3"
|
||||
aria-label="selimaj.dev home"
|
||||
>
|
||||
<span className="font-display text-sm font-semibold tracking-[0.24em]">
|
||||
SELIMAJ<span className="text-mute">.DEV</span>
|
||||
</span>
|
||||
@@ -40,7 +44,14 @@ export function SiteHeader() {
|
||||
onClick={() => setOpen((o) => !o)}
|
||||
>
|
||||
{open ? "CLOSE" : "MENU"}
|
||||
<svg width="18" height="12" viewBox="0 0 18 12" fill="none" stroke="currentColor" aria-hidden="true">
|
||||
<svg
|
||||
width="18"
|
||||
height="12"
|
||||
viewBox="0 0 18 12"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M0,1 H18 M6,6 H18 M0,11 H18" />
|
||||
</svg>
|
||||
</button>
|
||||
@@ -61,7 +72,12 @@ export function SiteHeader() {
|
||||
onClick={() => setOpen(false)}
|
||||
className={`flex min-h-11 items-center gap-2 uppercase md:py-3.5 ${current ? "text-ink" : "text-mute hover:text-accent"}`}
|
||||
>
|
||||
{current && <span aria-hidden="true" className="size-1.5 bg-accent shadow-[0_0_8px_var(--color-accent)]" />}
|
||||
{current && (
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="size-1.5 bg-accent shadow-[0_0_8px_var(--color-accent)]"
|
||||
/>
|
||||
)}
|
||||
{l.label}
|
||||
</Link>
|
||||
</li>
|
||||
@@ -70,7 +86,10 @@ export function SiteHeader() {
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<div aria-hidden="true" className="hidden text-right text-[10px] leading-relaxed tracking-[0.14em] text-mute lg:block">
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="hidden text-right text-[10px] leading-relaxed tracking-[0.14em] text-mute lg:block"
|
||||
>
|
||||
<SessionClock />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+13
-10
@@ -1,4 +1,7 @@
|
||||
import type { Status } from "./projects";
|
||||
import { projectById, type Status } from "./projects";
|
||||
|
||||
/** Proof statuses always come from the project list, so they can't drift. */
|
||||
const statusOf = (id: string): Status => projectById(id)!.status;
|
||||
|
||||
export type Proof = {
|
||||
label: string;
|
||||
@@ -36,7 +39,7 @@ export const dossier: DossierFile[] = [
|
||||
label: "Orus",
|
||||
note: "My open-source brand for privacy and opsec tools",
|
||||
href: "/projects/#orus",
|
||||
status: "LIVE",
|
||||
status: statusOf("orus"),
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -52,9 +55,9 @@ export const dossier: DossierFile[] = [
|
||||
"Osias is a blockchain-powered AI agent for trading emotions and behavior. Alongside it sits a Minecraft economy concept with jurisdictions, taxes, and IPOs.",
|
||||
],
|
||||
proof: [
|
||||
{ label: "Osias", note: "osias.trade", href: "https://osias.trade", status: "BUILDING" },
|
||||
{ label: "Orus", note: "Open-source privacy and opsec brand", href: "/projects/#orus", status: "LIVE" },
|
||||
{ label: "EquitySMP", note: "Real-world-style server economy", href: "/projects/#equitysmp", status: "BUILDING" },
|
||||
{ label: "Osias", note: "osias.trade", href: "https://osias.trade", status: statusOf("osias") },
|
||||
{ label: "Orus", note: "Open-source privacy and opsec brand", href: "/projects/#orus", status: statusOf("orus") },
|
||||
{ label: "EquitySMP", note: "Real-world-style server economy", href: "/projects/#equitysmp", status: statusOf("equitysmp") },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -69,9 +72,9 @@ export const dossier: DossierFile[] = [
|
||||
"The interesting problems are usually one layer lower than where most people stop.",
|
||||
],
|
||||
proof: [
|
||||
{ label: "Saturn", note: "Minecraft client, written from scratch", href: "/projects/#saturn", status: "ARCHIVED" },
|
||||
{ label: "Enclave + transport protocol", note: "Chat platform, and the protocol it runs on", href: "/projects/#enclave", status: "BUILDING" },
|
||||
{ label: "git.selimaj.dev", note: "Gitea on a Docker and Coolify homelab", href: "https://git.selimaj.dev", status: "LIVE" },
|
||||
{ label: "Saturn", note: "Minecraft client, written from scratch", href: "/projects/#saturn", status: statusOf("saturn") },
|
||||
{ label: "Enclave + transport protocol", note: "Chat platform, and the protocol it runs on", href: "/projects/#enclave", status: statusOf("enclave") },
|
||||
{ label: "git.selimaj.dev", note: "Gitea on a Docker and Coolify homelab", href: "https://git.selimaj.dev", status: statusOf("git") },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -102,8 +105,8 @@ export const dossier: DossierFile[] = [
|
||||
"Long-range PC and 4G-controlled RC planes built around a custom watercooled powertrain. Algorithmic trading. Minecraft with friends.",
|
||||
],
|
||||
proof: [
|
||||
{ label: "Cyberdecks", note: "Build photos and logs to come", href: "/projects/#briefcase-deck", status: "BUILDING" },
|
||||
{ label: "RC planes", note: "Build photos and logs to come", href: "/projects/#rc-planes", status: "BUILDING" },
|
||||
{ label: "Cyberdecks", note: "Build photos and logs to come", href: "/projects/#briefcase-deck", status: statusOf("briefcase-deck") },
|
||||
{ label: "RC planes", note: "Build photos and logs to come", href: "/projects/#rc-planes", status: statusOf("rc-planes") },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -8,9 +8,9 @@ export const profile = {
|
||||
displayName: "Selimaj",
|
||||
title: "Entrepreneur & Builder",
|
||||
stance: "I build the layer underneath.",
|
||||
// PLACEHOLDER: replace this one file to swap the profile picture.
|
||||
pfp: "/profile/pfp.svg",
|
||||
pfpIsPlaceholder: true,
|
||||
// Replace this one file to swap the profile picture (the favicon is src/app/icon.png).
|
||||
pfp: "/profile/Mono.png",
|
||||
pfpIsPlaceholder: false,
|
||||
github: "https://github.com/selimaj-dev",
|
||||
git: "https://git.selimaj.dev",
|
||||
} as const;
|
||||
@@ -35,7 +35,7 @@ export const dossierFields: DossierField[] = [
|
||||
{ label: "Based", value: "Tirana, Albania" },
|
||||
{ label: "Brands", value: "Orus" },
|
||||
// PLACEHOLDER decision: remove this entry to stop stating it publicly.
|
||||
{ label: "Building since", value: "12" },
|
||||
{ label: "Age", value: "16" },
|
||||
{ label: "Focus", value: "Privacy, independence, opsec, dev tooling" },
|
||||
{ label: "Known for", value: "Saturn, Enclave" },
|
||||
{ label: "Record", value: "Formerly #1 on Discipline, Albania" },
|
||||
|
||||
Reference in New Issue
Block a user