Hero decode effect, static terrain, and selimaj.dev rebrand

- Brute-force scramble that decodes hero values left to right
- Full-screen hero on desktop with telemetry pinned to the bottom
- Terrain no longer drifts; home skips the page transition
- selimaj.dev is the root brand; Orus becomes one brand with its own
  projects, and independent projects branch from the root

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-03 21:04:01 +02:00
co-authored by claude
parent 85dbdb3db4
commit fd72e1082a
20 changed files with 406 additions and 227 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

+3 -3
View File
@@ -1,7 +1,7 @@
import type { Metadata } from "next";
import Link from "next/link";
import { dossier } from "@/content/dossier";
import { orus, profile } from "@/content/profile";
import { profile } from "@/content/profile";
export const metadata: Metadata = {
title: "Dossier",
@@ -25,8 +25,8 @@ export default function AboutPage() {
<dl className="bracket grid min-w-[280px] grid-cols-[110px_minmax(0,1fr)] gap-y-2 border border-white/6 bg-surface px-[22px] py-[18px] text-[11px] [--bc:rgb(242_244_245/0.4)]">
<dt className="pt-0.5 text-[9px] tracking-[0.22em] text-mute">SUBJECT</dt>
<dd>{profile.displayName}</dd>
<dt className="pt-0.5 text-[9px] tracking-[0.22em] text-mute">ROOT</dt>
<dd>{orus.name}</dd>
<dt className="pt-0.5 text-[9px] tracking-[0.22em] text-mute">DOMAIN</dt>
<dd>selimaj.dev</dd>
<dt className="pt-0.5 text-[9px] tracking-[0.22em] text-mute">FILES</dt>
<dd>{String(dossier.length).padStart(2, "0")}</dd>
<dt className="pt-0.5 text-[9px] tracking-[0.22em] text-mute">ACCESS</dt>
-9
View File
@@ -97,10 +97,6 @@ html[data-boot] .seq {
animation-fill-mode: both;
}
.drift {
animation: drift 80s ease-in-out infinite alternate;
will-change: transform;
}
.spin {
animation: spin 16s linear infinite;
transform-origin: 60px 60px;
@@ -185,11 +181,6 @@ html[data-boot] .seq {
}
}
@keyframes drift {
to {
transform: translate3d(-28px, 14px, 0);
}
}
@keyframes spin {
to {
transform: rotate(360deg);
+2 -2
View File
@@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<rect width="24" height="24" fill="#050607"/>
<circle cx="12" cy="12" r="8.5" stroke="#f2f4f5" stroke-width="1.6" stroke-dasharray="44 9"/>
<circle cx="12" cy="12" r="2.6" fill="#4dff95"/>
<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: 275 B

After

Width:  |  Height:  |  Size: 314 B

+1 -1
View File
@@ -17,7 +17,7 @@ const jetbrains = JetBrains_Mono({
export const metadata: Metadata = {
title: { default: "Selimaj · Entrepreneur & Builder", template: "%s · Selimaj" },
description: "Selimaj, entrepreneur and builder. Founder of Orus. I build the layer underneath.",
description: "Selimaj, entrepreneur and builder. I build the layer underneath.",
metadataBase: new URL("https://selimaj.dev"),
};
+2 -2
View File
@@ -4,14 +4,14 @@ import { projects } from "@/content/projects";
export const metadata: Metadata = {
title: "Projects",
description: "Everything built and conceived under Orus, from Saturn and Enclave to cyberdecks and RC planes.",
description: "Everything I’ve built and conceived, from Enclave and Osias to cyberdecks and RC planes.",
};
export default function ProjectsPage() {
return (
<main className="pt-[68px] md:pt-[85px]">
<div className="mx-auto max-w-[1440px] px-4 pt-10 pb-20 md:px-16 md:pt-16 md:pb-24">
<div className="label tracking-[0.3em]">Node index · Root Orus · {projects.length} nodes</div>
<div className="label tracking-[0.3em]">Node index · Root selimaj.dev · {projects.length} nodes</div>
<h1 className="mt-3 font-display text-[52px] leading-[0.95] font-semibold uppercase md:text-7xl">Projects</h1>
<p className="mt-[18px] max-w-[560px] text-[13px] leading-[1.7] text-ink-2">
Most of what I&apos;ve built and conceived. Concepts are labelled as concepts.
+7
View File
@@ -1,4 +1,11 @@
"use client";
import { usePathname } from "next/navigation";
// Re-mounts on every navigation, so each page resolves in from wireframe.
// Home is skipped: the hero runs its own sequence and the terrain stays still.
export default function Template({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
if (pathname === "/") return <>{children}</>;
return <div className="page-resolve seq">{children}</div>;
}
+4 -1
View File
@@ -27,7 +27,10 @@ export function BootSequence() {
sessionStorage.setItem("boot", "1");
} catch {}
setLeaving(true);
outTimer = window.setTimeout(() => root.removeAttribute("data-boot"), 250);
outTimer = window.setTimeout(() => {
root.removeAttribute("data-boot");
window.dispatchEvent(new Event("boot:done"));
}, 250);
};
const timer = window.setTimeout(finish, DURATION);
window.addEventListener("keydown", finish);
+35 -23
View File
@@ -2,11 +2,9 @@
import Link from "next/link";
import { useEffect, useRef, useState } from "react";
import { featured, projectById, projects } from "@/content/projects";
import { brandOf, featured, featuredRoot, projectById, projects, root } from "@/content/projects";
import { Segment } from "./Segment";
const ROOT = featured[0];
export function FeaturedNodes() {
const [active, setActive] = useState<string | null>(null);
const nodes = featured.map((f) => ({ ...f, project: projectById(f.id)! }));
@@ -30,11 +28,11 @@ export function FeaturedNodes() {
>
{size && (
<div aria-hidden="true" className="hidden md:block">
{nodes.slice(1).map((n) => (
{nodes.map((n) => (
<Segment
key={`${n.id}-${active === n.id}`}
x1={(ROOT.x / 100) * size.w}
y1={(ROOT.y / 100) * size.h}
x1={(featuredRoot.x / 100) * size.w}
y1={(featuredRoot.y / 100) * size.h}
x2={(n.x / 100) * size.w}
y2={(n.y / 100) * size.h}
on={active === n.id}
@@ -45,9 +43,29 @@ export function FeaturedNodes() {
</div>
)}
{/* Root: the site itself, labelled to the left so no line crosses it. */}
<div
className="relative min-h-12 md:absolute md:top-(--y) md:left-(--x) md:min-h-0"
style={{ "--x": `${featuredRoot.x}%`, "--y": `${featuredRoot.y}%` } as React.CSSProperties}
>
<span
aria-hidden="true"
className="absolute top-2.5 left-0 box-border size-7 rounded-full border border-ink/70 bg-night md:-top-3.5 md:-left-3.5"
>
<span className="absolute top-[9px] left-[9px] size-2 rounded-full bg-ink" />
</span>
<span className="ml-10 block px-3 py-2.5 md:absolute md:-top-[22px] md:right-6 md:ml-0 md:w-max md:text-right">
<span className="flex items-baseline gap-3 md:flex-row-reverse">
<span className="font-display text-lg font-semibold tracking-[0.08em] uppercase">{root.name}</span>
<span className="text-[9px] tracking-[0.22em] text-mute uppercase">Root</span>
</span>
</span>
</div>
{nodes.map((n) => {
const on = active === n.id;
const root = n.project.root;
const brand = brandOf(n.project);
const meta = n.id === "orus" ? "BRAND" : brand ? `${n.project.status} · ${brand.toUpperCase()}` : n.project.status;
return (
<Link
key={n.id}
@@ -60,33 +78,27 @@ export function FeaturedNodes() {
>
<span
aria-hidden="true"
className={`absolute box-border border ${
root
? "top-2.5 left-0 size-7 rounded-full md:-top-3.5 md:-left-3.5"
: "top-4 left-2 size-3 md:-top-1.5 md:-left-1.5"
} ${on ? "border-accent shadow-[0_0_14px_var(--color-accent)]" : "border-ink/60"} ${on && !root ? "bg-accent" : "bg-night"}`}
>
{root && <span className={`absolute top-[9px] left-[9px] size-2 rounded-full ${on ? "bg-accent" : "bg-ink"}`} />}
</span>
className={`absolute top-4 left-2 box-border size-3 border md:-top-1.5 md:-left-1.5 ${n.id === "orus" ? "rotate-45" : ""} ${
on ? "border-accent bg-accent shadow-[0_0_14px_var(--color-accent)]" : "border-ink/60 bg-night"
}`}
/>
<span
className={`bracket ml-10 block min-h-11 px-3 py-2.5 group-focus-visible:outline group-focus-visible:outline-accent md:absolute md:-top-[22px] md:ml-0 ${
root ? "md:right-6 md:w-max md:text-right" : "md:left-6 md:w-[280px]"
} ${
className={`bracket ml-10 block min-h-11 px-3 py-2.5 group-focus-visible:outline group-focus-visible:outline-accent md:absolute md:-top-[22px] md:left-6 md:ml-0 md:w-[300px] ${
on ? "[--bc:var(--color-accent)]" : "[--bc:transparent]"
}`}
>
<span className={`flex items-baseline gap-3 ${root ? "md:flex-row-reverse" : ""}`}>
<span className="flex items-baseline gap-3">
<span className="font-display text-lg font-semibold tracking-[0.08em] uppercase">{n.project.name}</span>
<span className="text-[9px] tracking-[0.22em] text-mute">{root ? "ROOT" : n.project.status}</span>
<span className="text-[9px] tracking-[0.22em] text-mute">{meta}</span>
</span>
<span className={`mt-1.5 block text-[11px] leading-[1.55] text-ink-2 ${on && !root ? "" : "md:sr-only"}`}>{n.project.desc}</span>
<span className={`mt-1.5 block text-[11px] leading-[1.55] text-ink-2 ${on ? "" : "md:sr-only"}`}>{n.project.desc}</span>
</span>
</Link>
);
})}
<div aria-hidden="true" className="absolute right-4 bottom-3 hidden text-[9px] tracking-[0.2em] text-mute/70 md:block">
ROOT ORUS · {featured.length} OF {projects.length} NODES
<div aria-hidden="true" className="absolute right-4 bottom-3 hidden text-[9px] tracking-[0.2em] text-mute/70 uppercase md:block">
Root {root.sub} · {featured.length} of {projects.length} nodes
</div>
</div>
);
+38 -29
View File
@@ -1,39 +1,47 @@
import Link from "next/link";
import { dossierFields, lock, orus, 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";
import { TerrainLayer } from "./TerrainLayer";
import { LockReticle, TiranaMap } from "./TiranaMap";
const d = (s: number) => ({ "--d": `${s}s` }) as React.CSSProperties;
/** Dossier values decode one after another, starting once the card has built. */
const DOSSIER_START = 1.35;
const DOSSIER_STAGGER = 0.14;
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}`}>
{fields.map((f) => (
{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>
<dd className="flex flex-wrap gap-x-3.5">
{f.links
? f.links.map((l) => (
? f.links.map((l, j) => (
<a key={l.href} href={l.href} className="border-b border-white/25 hover:border-accent">
{l.label}
<Scramble text={l.label} delay={delay + j * 0.2} step={30} />
</a>
))
: f.value}
: <Scramble text={f.value} delay={delay} step={30} />}
</dd>
</div>
))}
);
})}
</dl>
);
}
export function Hero() {
return (
<section aria-labelledby="hero-title" className="relative overflow-hidden border-b border-line">
<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 max-w-[1440px] pt-[68px] md:pt-[84px] xl:h-[864px]">
<div className="relative z-10 mx-auto w-full max-w-[1440px] pt-[68px] md:pt-[84px] xl:h-[864px]">
{/* Lock assembly: a strip on small screens, the full stage on desktop. */}
<div
aria-hidden="true"
@@ -44,15 +52,16 @@ export function Hero() {
className="reticle seq absolute top-[calc(50%-60px)] left-[calc(var(--lx)-60px)] max-xl:scale-75 xl:top-[174px]"
style={d(0.25)}
/>
<div
className="resolve seq absolute bottom-3 left-4 text-[9px] leading-[1.7] tracking-[0.14em] text-mute xl:bottom-auto xl:left-[calc(var(--lx)-60px)] xl:top-[306px] xl:text-[10px]"
style={d(0.85)}
>
<div className="text-accent">LOCK ACQUIRED</div>
<div className="absolute bottom-3 left-4 text-[9px] leading-[1.7] tracking-[0.14em] text-mute xl:bottom-auto xl:left-[calc(var(--lx)-60px)] xl:top-[306px] xl:text-[10px]">
<div className="text-accent">
<Scramble text="LOCK ACQUIRED" delay={0.85} step={35} nowrap />
</div>
<div>
{lock.lat} · {lock.lon}
<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 />
</div>
<div className="uppercase">{lock.place}</div>
</div>
<div
className="trace seq absolute top-[233px] right-[510px] left-[calc(var(--lx)+66px)] hidden h-px bg-accent/55 xl:block"
@@ -66,20 +75,19 @@ export function Hero() {
<div className="flex flex-col gap-9 px-4 pt-6 pb-16 md:px-16 xl:block xl:p-0">
{/* Headline */}
<div className="xl:absolute xl:top-[364px] xl:left-16 xl:w-[620px]">
<p className="resolve seq mb-3 text-[9px] tracking-[0.28em] text-mute xl:mb-5 xl:text-[10px] xl:tracking-[0.3em]" style={d(1.1)}>
TARGET RESOLVED · SUBJECT 0001
<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} />
</p>
<h1
id="hero-title"
className="resolve seq font-display text-[46px] leading-[0.96] font-semibold uppercase sm:text-[64px] xl:text-[84px] xl:leading-[0.94] xl:tracking-[0.01em]"
style={d(1.2)}
className="font-display text-[46px] leading-[0.96] font-semibold uppercase sm:text-[64px] xl:text-[84px] xl:leading-[0.94] xl:tracking-[0.01em]"
>
Entrepreneur
<Scramble text="ENTREPRENEUR" delay={0.3} step={35} nowrap />
<br />
&amp; Builder
<Scramble text="& BUILDER" delay={0.5} step={35} nowrap />
</h1>
<p className="resolve seq mt-4 text-[15px] leading-normal text-ink-2 xl:mt-6 xl:text-[17px]" style={d(1.3)}>
{profile.stance}
<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)}>
<Link
@@ -95,10 +103,6 @@ export function Hero() {
OPEN DOSSIER <span aria-hidden="true">↗</span>
</Link>
</div>
<div className="resolve seq mt-10 hidden max-w-[580px] items-start gap-3.5 xl:flex" style={d(1.5)}>
<span className="pt-[3px] text-[9px] whitespace-nowrap tracking-[0.24em] text-mute">ROOT ─ ORUS</span>
<span className="text-xs leading-[1.6] text-mute">{orus.oneLiner}</span>
</div>
<DossierList fields={dossierFields} className="mt-9 xl:hidden" />
</div>
@@ -122,7 +126,7 @@ export function Hero() {
<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">
{profile.displayName}
<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>
@@ -135,7 +139,11 @@ export function Hero() {
</article>
</div>
{/* Corner telemetry */}
</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)}>
<SessionStamp />
</div>
@@ -149,6 +157,7 @@ export function Hero() {
<div className="text-mute/70">VISITOR · UNRESOLVED</div>
</div>
</div>
</div>
</section>
);
}
+9
View File
@@ -0,0 +1,9 @@
/** 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>
);
}
-8
View File
@@ -1,8 +0,0 @@
export function OrusMark({ 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}>
<circle cx="12" cy="12" r="9.5" stroke="currentColor" strokeWidth="1.2" strokeDasharray="50 10" />
<circle cx="12" cy="12" r="2.6" fill="currentColor" />
</svg>
);
}
+53 -23
View File
@@ -1,37 +1,40 @@
"use client";
import { useEffect, useState } from "react";
import { groups, projects, type GroupId, type Project } from "@/content/projects";
import { brandOf, groups, projects, root, type GroupId, type Project } from "@/content/projects";
import { Segment } from "./Segment";
import { StatusTag } from "./StatusTag";
const W = 1200;
const H = 720;
const root = projects.find((p) => p.root)!;
const groupIds = Object.keys(groups) as GroupId[];
const isHub = (p: Project) => groups[p.group].node === p.id;
function Marker({ p, on }: { p: Project; on: boolean }) {
const size = p.root ? 30 : 14;
const hub = isHub(p);
const size = hub ? 22 : 14;
const rest =
p.status === "CONCEPT" ? "border border-dashed border-ink/60" : p.status === "ARCHIVED" ? "border border-ink/30" : "border border-ink/65";
return (
<span
aria-hidden="true"
className={`relative box-border flex-none ${p.root ? "rounded-full" : ""} ${
on ? (p.root ? "border border-accent shadow-[0_0_14px_var(--color-accent)]" : "bg-accent shadow-[0_0_12px_var(--color-accent)]") : `${rest} bg-surface`
className={`relative box-border flex-none ${hub ? "rotate-45" : ""} ${
on ? "bg-accent shadow-[0_0_12px_var(--color-accent)]" : `${rest} bg-surface`
}`}
style={{ width: size, height: size }}
>
{p.root && <span className={`absolute top-[10px] left-[10px] size-2 rounded-full ${on ? "bg-accent" : "bg-ink"}`} />}
</span>
/>
);
}
function ProjectCard({ p }: { p: Project }) {
const brand = brandOf(p);
const body = (
<>
<span className="flex items-center justify-between">
<span className="flex items-center justify-between gap-3">
<span className="flex items-center gap-3">
<StatusTag status={p.status} />
{brand && <span className="text-[9px] tracking-[0.22em] text-mute uppercase">{brand}</span>}
</span>
<span aria-hidden="true" className="text-mute transition-colors group-hover:text-accent group-focus-visible:text-accent">
{p.href ? "↗" : "→"}
</span>
@@ -62,7 +65,7 @@ function ProjectCard({ p }: { p: Project }) {
export function ProjectIndex() {
const [view, setView] = useState<"map" | "list">("map");
const [active, setActive] = useState<string>("orus");
const [active, setActive] = useState<string | null>(null);
// Deep links (/projects/#enclave) select that node; small screens start on the list.
useEffect(() => {
@@ -75,7 +78,7 @@ export function ProjectIndex() {
}
}, []);
const sel = projects.find((p) => p.id === active) ?? root;
const sel = projects.find((p) => p.id === active) ?? null;
const count = (s: Project["status"]) => String(projects.filter((p) => p.status === s).length).padStart(2, "0");
return (
@@ -112,10 +115,10 @@ export function ProjectIndex() {
<div className="mt-6 overflow-x-auto border border-white/6">
<div className="grid-bg relative mx-auto bg-surface [background-size:40px_40px]" style={{ width: W, height: H }}>
{groupIds.map((k) => (
<Segment key={k} x1={root.map.x} y1={root.map.y} x2={groups[k].x} y2={groups[k].y} on={!sel.root && sel.group === k} strong />
<Segment key={k} x1={root.map.x} y1={root.map.y} x2={groups[k].x} y2={groups[k].y} on={!!sel && sel.group === k} strong />
))}
{projects
.filter((p) => !p.root)
.filter((p) => !isHub(p))
.map((p) => (
<Segment
key={`${p.id}-${active === p.id}`}
@@ -127,7 +130,11 @@ export function ProjectIndex() {
dashed={p.status === "CONCEPT"}
/>
))}
{groupIds.map((k) => {
{/* Plain hubs (groups without a project of their own). */}
{groupIds
.filter((k) => !groups[k].node)
.map((k) => {
const g = groups[k];
return (
<div key={k} aria-hidden="true">
@@ -141,11 +148,23 @@ export function ProjectIndex() {
</div>
);
})}
{/* Root: the site itself. */}
<div className="absolute flex items-center gap-3 whitespace-nowrap" style={{ left: root.map.x - 15, top: root.map.y - 15 }}>
<span aria-hidden="true" className="relative box-border size-[30px] flex-none rounded-full border border-ink/70 bg-surface">
<span className="absolute top-[10px] left-[10px] size-2 rounded-full bg-ink" />
</span>
<span className="flex flex-col gap-[3px]">
<span className="font-display text-xl font-semibold tracking-[0.08em] uppercase">{root.name}</span>
<span className="text-[8px] tracking-[0.22em] text-mute uppercase">Root · {root.sub}</span>
</span>
</div>
{projects.map((p) => {
const on = active === p.id;
const g = groups[p.group];
const labelLeft = !p.root && p.map.x < g.x;
const m = p.root ? 30 : 14;
const labelLeft = (p.label ?? (p.map.x < g.x ? "l" : "r")) === "l";
const m = isHub(p) ? 22 : 14;
const pad = 8;
return (
<button
@@ -165,15 +184,16 @@ export function ProjectIndex() {
}}
>
<Marker p={p} on={on} />
<span className="flex flex-col gap-[3px]">
{/* A hub's label sits a little high so its root line passes underneath. */}
<span className={`flex flex-col gap-[3px] ${isHub(p) ? "-translate-y-4" : ""}`}>
<span
className={`font-display font-semibold tracking-[0.08em] uppercase ${p.root ? "text-xl" : "text-[13px]"} ${
className={`font-display font-semibold tracking-[0.08em] uppercase ${isHub(p) ? "text-base" : "text-[13px]"} ${
p.status === "ARCHIVED" && !on ? "text-ink/70" : "text-ink"
}`}
>
{p.name}
</span>
<span className="text-[8px] tracking-[0.22em] text-mute">{p.root ? "ROOT" : p.status}</span>
<span className="text-[8px] tracking-[0.22em] text-mute">{isHub(p) ? "BRAND" : p.status}</span>
</span>
</button>
);
@@ -181,8 +201,8 @@ export function ProjectIndex() {
<div aria-hidden="true" className="absolute bottom-3 left-4 text-[9px] tracking-[0.2em] text-mute/70">
GRID 40 · ROOT {root.map.x},{root.map.y}
</div>
<div aria-hidden="true" className="absolute right-4 bottom-3 text-[9px] tracking-[0.2em] text-accent uppercase">
TRACKING ▸ {sel.name}
<div aria-hidden="true" className="absolute right-4 bottom-3 text-[9px] tracking-[0.2em] uppercase">
{sel ? <span className="text-accent">TRACKING ▸ {sel.name}</span> : <span className="text-mute/70">AWAITING TARGET</span>}
</div>
</div>
</div>
@@ -190,12 +210,18 @@ export function ProjectIndex() {
<section
aria-live="polite"
aria-label="Selected node"
className="bracket mt-4 grid gap-6 border border-white/6 bg-surface px-7 py-6 [--bc:var(--color-accent)] md:grid-cols-[minmax(0,1fr)_auto] md:items-center md:gap-x-12"
className={`bracket mt-4 grid min-h-[176px] gap-6 border border-white/6 bg-surface px-7 py-6 md:grid-cols-[minmax(0,1fr)_auto] md:items-center md:gap-x-12 ${
sel ? "[--bc:var(--color-accent)]" : "[--bc:rgb(242_244_245/0.3)]"
}`}
>
{sel ? (
<>
<div>
<div className="flex flex-wrap items-center gap-3.5">
<StatusTag status={sel.status} />
<span className="text-[9px] tracking-[0.24em] text-mute uppercase">{sel.root ? "Root" : groups[sel.group].label}</span>
<span className="text-[9px] tracking-[0.24em] text-mute uppercase">
{isHub(sel) ? "Brand" : (brandOf(sel) ?? groups[sel.group].label)}
</span>
</div>
<h2 className="mt-3 font-display text-3xl font-semibold tracking-[0.04em] uppercase">{sel.name}</h2>
<p className="mt-2 max-w-[720px] text-[13px] leading-[1.7] text-ink-2">{sel.desc}</p>
@@ -223,6 +249,10 @@ export function ProjectIndex() {
VIEW IN LIST <span aria-hidden="true">→</span>
</button>
)}
</>
) : (
<p className="text-[11px] tracking-[0.2em] text-mute">HOVER OR SELECT A NODE TO TRACK IT.</p>
)}
</section>
</div>
+110
View File
@@ -0,0 +1,110 @@
"use client";
import { useEffect, useState } from "react";
const UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#%&@$*+=<>/";
const LOWER = "abcdefghijklmnopqrstuvwxyz0123456789#%&@$*+=<>/";
const DIGIT = "0123456789#%&@$*";
/** Characters that stay put while everything around them is brute-forced. */
const FIXED = /[\s.,·()\-/]/;
const FRAME_MS = 45;
function noise(ch: string) {
if (FIXED.test(ch)) return ch;
const pool = /[0-9]/.test(ch) ? DIGIT : ch === ch.toLowerCase() && ch !== ch.toUpperCase() ? LOWER : UPPER;
return pool[Math.floor(Math.random() * pool.length)];
}
type Frame = { done: string; head: string; rest: string };
/**
* Text that brute-forces itself: every character cycles through random
* glyphs, then the real value locks in from left to right.
*
* Server and no-JS output is the plain text. With reduced motion it never
* animates. While the boot screen is up it waits for `boot:done`.
*/
export function Scramble({
text,
delay = 0,
step = 45,
nowrap = false,
}: {
text: string;
/** Seconds before characters start locking in (noise runs from the start). */
delay?: number;
/** Milliseconds per character as the value locks in. */
step?: number;
nowrap?: boolean;
}) {
const [frame, setFrame] = useState<Frame | null>(null);
useEffect(() => {
if (matchMedia("(prefers-reduced-motion: reduce)").matches) return;
const chars = Array.from(text);
let raf = 0;
let start = 0;
let last = -Infinity;
const build = (locked: number): Frame => ({
done: chars.slice(0, locked).join(""),
head: locked < chars.length ? chars[locked] : "",
rest: chars
.slice(locked + 1)
.map(noise)
.join(""),
});
const loop = (t: number) => {
if (!start) start = t;
const elapsed = t - start - delay * 1000;
const locked = elapsed < 0 ? 0 : Math.floor(elapsed / step);
if (locked >= chars.length) {
setFrame(null);
return;
}
if (t - last >= FRAME_MS) {
last = t;
// Before the reveal starts, the first character is noise too.
setFrame(elapsed < 0 ? { done: "", head: noise(chars[0]), rest: build(0).rest } : build(locked));
}
raf = requestAnimationFrame(loop);
};
const begin = () => {
raf = requestAnimationFrame(loop);
};
if (document.documentElement.hasAttribute("data-boot")) {
// Hide the real value under the boot screen, then start when it lifts.
raf = requestAnimationFrame(() => setFrame({ done: "", head: "", rest: chars.map(noise).join("") }));
window.addEventListener("boot:done", begin, { once: true });
} else {
begin();
}
return () => {
cancelAnimationFrame(raf);
window.removeEventListener("boot:done", begin);
};
}, [text, delay, step]);
if (!frame) return <>{text}</>;
return (
<span className="relative inline-block max-w-full align-top">
<span className="sr-only">{text}</span>
{/* Invisible copy keeps the box exactly the size of the real text. */}
<span aria-hidden="true" className={`invisible ${nowrap ? "whitespace-nowrap" : ""}`}>
{text}
</span>
<span aria-hidden="true" className={`absolute inset-0 ${nowrap ? "whitespace-nowrap" : ""}`}>
{frame.done}
<span className="text-accent">{frame.head}</span>
<span className="opacity-50">{frame.rest}</span>
</span>
</span>
);
}
+1 -1
View File
@@ -4,7 +4,7 @@ export function SiteFooter() {
return (
<footer className="border-t border-line">
<div className="mx-auto flex max-w-[1440px] flex-wrap justify-between gap-6 px-4 pt-7 pb-10 text-[10px] tracking-[0.18em] text-mute md:px-16">
<span>{profile.displayName.toUpperCase()} · BUILT UNDER ORUS</span>
<span>SELIMAJ.DEV · TIRANA, AL</span>
<span className="flex gap-6">
<a href={profile.github} className="hover:text-accent">GITHUB</a>
<a href={profile.git} className="hover:text-accent">GIT.SELIMAJ.DEV</a>
+6 -5
View File
@@ -3,7 +3,7 @@
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useState } from "react";
import { OrusMark } from "./OrusMark";
import { Mark } from "./Mark";
import { SessionClock } from "./Telemetry";
const links = [
@@ -25,10 +25,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="Orus · selimaj.dev home">
<OrusMark />
<span className="font-display text-sm font-semibold tracking-[0.24em]">ORUS</span>
<span className="hidden text-[10px] tracking-[0.18em] text-mute sm:inline">/ SELIMAJ.DEV</span>
<Link href="/" className="flex min-h-11 items-center gap-3" aria-label="selimaj.dev home">
<Mark />
<span className="font-display text-sm font-semibold tracking-[0.24em]">
SELIMAJ<span className="text-mute">.DEV</span>
</span>
</Link>
<button
+2 -2
View File
@@ -1,6 +1,6 @@
/**
* Hero background, bottom to top: terrain contours (real Dajt elevation data),
* grid, scanlines, vignette. Purely decorative.
* grid, scanlines, vignette. Purely decorative and deliberately static.
*/
export function TerrainLayer({ className = "" }: { className?: string }) {
return (
@@ -9,7 +9,7 @@ export function TerrainLayer({ className = "" }: { className?: string }) {
<img
src="/terrain.svg"
alt=""
className="drift absolute -inset-10 h-[calc(100%+80px)] w-[calc(100%+80px)] max-w-none object-cover opacity-20 max-xl:object-[60%_50%]"
className="absolute -inset-10 h-[calc(100%+80px)] w-[calc(100%+80px)] max-w-none object-cover opacity-20 max-xl:object-[60%_50%]"
/>
<div className="grid-bg absolute inset-0" />
<div className="scan-bg absolute inset-0" />
+5 -5
View File
@@ -34,7 +34,7 @@ export const dossier: DossierFile[] = [
proof: [
{
label: "Orus",
note: "A community that has grown around the work",
note: "My open-source brand for privacy and opsec tools",
href: "/projects/#orus",
status: "LIVE",
},
@@ -44,16 +44,16 @@ export const dossier: DossierFile[] = [
slug: "entrepreneurship",
no: "02",
title: "Entrepreneurship",
summary: "Orus as the umbrella. Systems where incentives and behavior matter.",
summary: "Brands and ventures. Systems where incentives and behavior matter.",
proofSummary: "Osias · Orus · EquitySMP",
lead: "Orus is the umbrella for everything serious I make.",
lead: "I build brands, and ventures that stand on their own.",
paragraphs: [
"Beyond it I design systems where incentives and behavior matter.",
"Orus is one of the brands: open-source software for privacy, independence, and opsec. Outside it I design systems where incentives and behavior matter.",
"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: "The umbrella org", href: "/projects/#orus", status: "LIVE" },
{ 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" },
],
},
+1 -7
View File
@@ -15,12 +15,6 @@ export const profile = {
git: "https://git.selimaj.dev",
} as const;
export const orus = {
name: "Orus",
oneLiner:
"A community and toolset for privacy, independence, and opsec, plus the dev tools built under it.",
} as const;
/**
* Map lock. Privacy rule: city centre only (Skanderbeg Square, a public
* landmark). Never put anything finer than city scale here.
@@ -39,7 +33,7 @@ export type DossierField = {
export const dossierFields: DossierField[] = [
{ label: "Based", value: "Tirana, Albania" },
{ label: "Affiliation", value: "Orus (founder)" },
{ label: "Brands", value: "Orus" },
// PLACEHOLDER decision: remove this entry to stop stating it publicly.
{ label: "Building since", value: "12" },
{ label: "Focus", value: "Privacy, independence, opsec, dev tooling" },
+67 -46
View File
@@ -1,6 +1,6 @@
export type Status = "LIVE" | "BUILDING" | "CONCEPT" | "ARCHIVED";
export type GroupId = "core" | "ventures" | "infra" | "hardware";
export type GroupId = "orus" | "ventures" | "infra" | "hardware";
export type Project = {
id: string;
@@ -10,57 +10,91 @@ export type Project = {
desc: string;
tags: string[];
href?: string;
root?: boolean;
/** Position on the 1200×720 node map. */
map: { x: number; y: number };
/** Which side of the marker the label sits on (defaults to away from its hub). */
label?: "l" | "r";
};
export const groups: Record<GroupId, { label: string; x: number; y: number; side: "l" | "r" }> = {
core: { label: "Core", x: 360, y: 220, side: "l" },
/** The map's root: the site itself. Not a project. */
export const root = {
name: "Selimaj",
sub: "selimaj.dev",
map: { x: 600, y: 360 },
} as const;
/**
* Groups branch off the root. A group with `node` uses that project as its hub
* (Orus is a brand with its own projects); the rest get a plain labelled hub.
*/
export const groups: Record<
GroupId,
{ label: string; x: number; y: number; side: "l" | "r"; node?: string }
> = {
orus: { label: "Orus", x: 340, y: 240, side: "r", node: "orus" },
ventures: { label: "Ventures & systems", x: 840, y: 220, side: "r" },
infra: { label: "Infrastructure", x: 360, y: 520, side: "l" },
hardware: { label: "Hardware", x: 840, y: 520, side: "r" },
};
// PLACEHOLDER: statuses for everything except Orus and the self-hosted
// infrastructure are best guesses. Links are filled in where known.
// PLACEHOLDER: statuses other than Orus and the self-hosted infrastructure are
// best guesses. Links are filled in where known.
export const projects: Project[] = [
{
id: "orus",
name: "Orus",
group: "core",
root: true,
group: "orus",
status: "LIVE",
desc: "Community and org for privacy, independence, opsec, and dev tools. Root of everything below.",
tags: ["community", "opsec", "org"],
map: { x: 600, y: 360 },
desc: "One of my brands: open-source software for privacy, independence and opsec. Home to Enclave, Saturn and the cyberdecks.",
tags: ["brand", "oss", "privacy"],
map: { x: 340, y: 240 },
label: "r",
},
{
id: "saturn",
name: "Saturn",
group: "core",
status: "ARCHIVED",
desc: "Minecraft client. Did most of what I set out to do with it.",
group: "orus",
status: "BUILDING",
desc: "Highly advanced and customizable Minecraft client with free emotes and cosmetics",
tags: ["minecraft", "client"],
map: { x: 200, y: 90 },
map: { x: 190, y: 100 },
},
{
id: "enclave",
name: "Enclave",
group: "core",
group: "orus",
status: "BUILDING",
desc: "Discord-like chat platform, running on a custom transport protocol.",
tags: ["chat", "realtime"],
map: { x: 420, y: 70 },
map: { x: 430, y: 80 },
label: "r",
},
{
id: "enclave-protocol",
name: "Enclave protocol",
group: "core",
group: "orus",
status: "CONCEPT",
desc: "Transport protocol replacing HTTP and WSS; Enclave’s chat protocol runs on top of it. Concept and design notes.",
tags: ["networking", "protocol design"],
map: { x: 190, y: 300 },
map: { x: 200, y: 330 },
},
{
id: "briefcase-deck",
name: "Briefcase deck",
group: "orus",
status: "CONCEPT",
desc: "Briefcase cyberdeck: the most versatile and doable build.",
tags: ["hardware", "cyberdeck"],
map: { x: 160, y: 215 },
},
{
id: "compact-deck",
name: "Compact deck",
group: "orus",
status: "CONCEPT",
desc: "Compact premium cyberdeck: a Flipper Zero, but better.",
tags: ["hardware", "cyberdeck"],
map: { x: 290, y: 400 },
},
{
id: "osias",
@@ -94,7 +128,7 @@ export const projects: Project[] = [
id: "algo-trading",
name: "Algo trading",
group: "ventures",
status: "BUILDING",
status: "ARCHIVED",
desc: "Several repos exploring automated crypto trading strategies.",
tags: ["trading", "crypto"],
map: { x: 980, y: 400 },
@@ -107,7 +141,7 @@ export const projects: Project[] = [
desc: "Gitea at git.selimaj.dev, on a Docker and Coolify homelab server behind Cloudflare.",
tags: ["gitea", "docker", "coolify"],
href: "https://git.selimaj.dev",
map: { x: 190, y: 450 },
map: { x: 190, y: 470 },
},
{
id: "homelab",
@@ -118,41 +152,28 @@ export const projects: Project[] = [
tags: ["infra", "docker"],
map: { x: 300, y: 660 },
},
{
id: "briefcase-deck",
name: "Briefcase deck",
group: "hardware",
status: "BUILDING",
desc: "Briefcase cyberdeck: the most versatile and doable build.",
tags: ["hardware", "cyberdeck"],
map: { x: 1020, y: 470 },
},
{
id: "compact-deck",
name: "Compact deck",
group: "hardware",
status: "CONCEPT",
desc: "Compact premium cyberdeck: a Flipper Zero, but better.",
tags: ["hardware", "cyberdeck"],
map: { x: 1000, y: 640 },
},
{
id: "rc-planes",
name: "RC planes",
group: "hardware",
status: "BUILDING",
status: "CONCEPT",
desc: "Custom long-range, PC and 4G-controlled planes pushing speed and efficiency, built around a custom watercooled powertrain.",
tags: ["hardware", "rc", "4g"],
map: { x: 720, y: 660 },
map: { x: 1000, y: 620 },
},
];
export const projectById = (id: string) => projects.find((p) => p.id === id);
/** Home page featured strip: positions are percentages of the stage. */
/** The brand a project is published under, if any. */
export const brandOf = (p: Project) =>
p.group === "orus" && p.id !== "orus" ? "Orus" : undefined;
/** Home page featured strip, branching from the root. Positions are % of the stage. */
export const featuredRoot = { x: 16, y: 50 };
export const featured = [
{ id: "orus", x: 18, y: 50 },
{ id: "saturn", x: 46, y: 22 },
{ id: "enclave", x: 68, y: 52 },
{ id: "equitysmp", x: 44, y: 80 },
{ id: "orus", x: 42, y: 16 },
{ id: "enclave", x: 66, y: 36 },
{ id: "saturn", x: 62, y: 64 },
{ id: "osias", x: 40, y: 84 },
] as const;