Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/app/(home)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HomeLayout } from "fumadocs-ui/layouts/home";
import { baseOptions } from "@/lib/layout.shared";
import { homeOptions } from "@/lib/layout.shared";

export default function Layout({ children }: LayoutProps<"/">) {
return <HomeLayout {...baseOptions()}>{children}</HomeLayout>;
return <HomeLayout {...homeOptions()}>{children}</HomeLayout>;
}
69 changes: 25 additions & 44 deletions src/app/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,83 +3,64 @@ import Image from "next/image";
import { ArrowRight } from "lucide-react";
import { repos } from "@/lib/source";
import { resolveProjectIcon } from "@/lib/icon";
import { ProjectGrid } from "@/components/project-grid";

const LED_CLUSTERS = [
{ x: "16%", y: 140, size: 34, delay: "0s", duration: "4s" },
{ x: "74%", y: 95, size: 30, delay: "0.8s", duration: "6s" },
{ x: "84%", y: 205, size: 28, delay: "1.4s", duration: "5.2s" },
{ x: "8%", y: 265, size: 26, delay: "1.9s", duration: "4.2s" },
{ x: "26%", y: 310, size: 24, delay: "2.3s", duration: "4.6s" },
{ x: "90%", y: 360, size: 22, delay: "3.1s", duration: "5s" },
];
import { GradientRule } from "@/components/brand/gradient-rule";
import { WordmarkField } from "@/components/brand/wordmark-field";

export default function HomePage() {
return (
<>
<main className="relative flex-1 overflow-hidden">
<div aria-hidden className="tf-dot-grid pointer-events-none absolute inset-0" />
<div aria-hidden className="tf-hero-glow pointer-events-none absolute inset-0" />
{LED_CLUSTERS.map((led) => (
<div
key={`${led.x}-${led.y}`}
aria-hidden
className="tf-led-cluster pointer-events-none absolute inset-0"
style={{
maskImage: `radial-gradient(circle ${led.size}px at ${led.x} ${led.y}px, #000 0%, transparent 100%)`,
WebkitMaskImage: `radial-gradient(circle ${led.size}px at ${led.x} ${led.y}px, #000 0%, transparent 100%)`,
animationDelay: led.delay,
animationDuration: led.duration,
}}
/>
))}
<WordmarkField />

<section className="relative px-6 pb-16 pt-24 text-center">
<section className="relative px-6 pb-14 pt-20 text-center">
<div className="flex flex-col items-center">
<Image
src="/logo.png"
alt="TrickFire Robotics"
width={80}
height={148}
className="tf-logo-glow mb-7"
priority
className="mb-7"
/>
<h1 className="bg-linear-to-b from-fd-foreground to-fd-foreground/60 bg-clip-text text-4xl font-extrabold tracking-tighter text-transparent sm:text-6xl">
TrickFire Robotics
</h1>
<p className="mt-4 max-w-md text-balance text-sm leading-relaxed text-fd-muted-foreground sm:text-base">
Documentation and guides for technologies and repositories Trickfire
<h1 className="tf-glitch text-5xl sm:text-7xl">TrickFire Robotics</h1>
<p className="mt-6 max-w-md text-balance leading-relaxed text-fd-muted-foreground">
Documentation and guides for technologies and repositories TrickFire
uses.
</p>
</div>
</section>

<section className="relative mx-auto max-w-6xl px-6 pb-24">
<ProjectGrid>
<div className="relative mx-auto max-w-6xl px-6">
<GradientRule />
</div>

<section className="relative mx-auto max-w-6xl px-6 pb-24 pt-12">
<div className="flex flex-wrap justify-center gap-5 [&>*]:min-w-0 [&>*]:basis-full sm:[&>*]:basis-[calc((100%-1.25rem)/2)] lg:[&>*]:basis-[calc((100%-2.5rem)/3)]">
{repos.map((repo) => (
<Link
key={repo.id}
href={`/${repo.id}`}
className="group relative flex min-h-28 flex-col gap-3 rounded-2xl border border-fd-border bg-fd-card/70 p-5 backdrop-blur-sm transition-colors duration-300 hover:border-fd-primary/30 hover:bg-fd-card"
className="group tf-panel tf-lift flex flex-col gap-2 border border-fd-border bg-fd-card px-4 py-3.5"
>
<span aria-hidden className="tf-card-glow" />
<span aria-hidden className="tf-card-ring" />
<span className="relative flex items-center gap-3">
<span className="flex size-10 shrink-0 items-center justify-center rounded-xl border border-fd-primary/15 bg-fd-primary/10 text-fd-primary transition-colors duration-300 group-hover:bg-fd-primary/15">
{resolveProjectIcon(repo.icon, "size-[1.15rem]")}
<span className="flex items-center gap-3">
{/* green reads as an outline at rest and fills on hover -
seven solid #00FE00 blocks at once is a lot of shouting */}
<span className="flex size-8 shrink-0 items-center justify-center border border-fd-primary/60 text-fd-primary transition-colors duration-150 group-hover:bg-fd-primary group-hover:text-black">
{resolveProjectIcon(repo.icon, "size-4")}
</span>
<span className="truncate text-[0.975rem] font-semibold text-fd-card-foreground">
<span className="tf-heading truncate text-lg text-fd-card-foreground">
{repo.name}
</span>
<ArrowRight className="ms-auto size-4 shrink-0 text-fd-primary opacity-25 transition-all duration-300 group-hover:translate-x-0.5 group-hover:opacity-100" />
<ArrowRight className="ms-auto size-4 shrink-0 text-fd-primary opacity-0 transition-opacity duration-150 group-hover:opacity-100" />
</span>
{repo.description && (
<span className="relative line-clamp-2 text-[0.825rem] leading-relaxed text-fd-muted-foreground">
<span className="line-clamp-2 text-sm leading-relaxed text-fd-muted-foreground">
{repo.description}
</span>
)}
</Link>
))}
</ProjectGrid>
</div>
</section>
</main>

Expand Down
3 changes: 1 addition & 2 deletions src/app/[repo]/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { firstPageUrl, getSource, repoIds } from "@/lib/source";
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from "fumadocs-ui/layouts/docs/page";
import { notFound, redirect } from "next/navigation";
import { getMDXComponents } from "@/components/mdx";
import { Card, getMDXComponents } from "@/components/mdx";
import type { Metadata } from "next";
import { createRelativeLink } from "fumadocs-ui/mdx";
import { Card } from "fumadocs-ui/components/card";

interface PageData {
title: string;
Expand Down
180 changes: 180 additions & 0 deletions src/app/brand.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/*
* TrickFire Robotics brand layer - source of truth.
*
* Mirrors `website/src/_variables.scss` so the two codebases can't drift. Token
* names match that file one-for-one ($TrickFireGreen -> --tf-green, etc.) so
* porting either direction is a rename, not a redesign.
*
* Everything here traces to style-guide.pdf v1.0 (August 2025). Page refs are
* noted where a rule is prescriptive rather than a judgement call.
*/

/* --- tokens ------------------------------------------------------------- */

:root {
/* palette - style guide p.8. These six are the entire sanctioned set. */
--tf-green: #00fe00; /* TrickFire Green */
--tf-pink: #e93cac; /* Accent Pink */
--tf-eerie-black: #222222; /* Eerie Black */
--tf-white: #ffffff; /* White - links, emphasis */
--tf-dark-white: #cccccc; /* Dark White - body text */
--tf-black: #000000; /* Black */

/* channel forms, for rgb(... / alpha). Tailwind v4 runs Lightning CSS,
which rewrites `color-mix(..., var(--x) N%, transparent)` into a legacy
fallback that drops the percentage - i.e. full-brightness #00fe00.
Plain `rgb(<channels> / <alpha>)` is left alone and works everywhere. */
--tf-green-rgb: 0 254 0;
--tf-pink-rgb: 233 60 172;
--tf-white-rgb: 255 255 255;

/* shades and tints - style guide p.9 licenses these as palette extensions.
Shade = base + black, tint = base + white, tone = base + gray. */
/* Three steps of Eerie Black give the page depth. The style guide's own
layout (p.12) is a near-black field with #222222 boxes sitting on it, so
the page floor goes darkest and surfaces lift off it. Without that gap
everything flattens into one sheet. */
--tf-eerie-deep: #101010; /* page floor, two steps under Eerie Black */
--tf-eerie-raise: #181818; /* in-prose surface, barely off the floor */
--tf-eerie-shade: #1a1a1a; /* recessed surface - inputs */
--tf-eerie-tint: #2e2e2e; /* hover surface, one step over */
--tf-gray-tone: #a3a3a3; /* metadata text - 7:1 on Eerie Black */
--tf-pink-tint: #f27ac7; /* warning, distinct from error's full pink */
--tf-wordmark: #1f1f1f; /* background wordmark - style guide p.12 */

/* type - style guide p.7 */
--tf-font-heading: var(--font-barlow-condensed), "Barlow Condensed", sans-serif;
--tf-font-body: var(--font-overpass), "Overpass", system-ui, sans-serif;
--tf-font-mono: var(--font-roboto-mono), "Roboto Mono", ui-monospace, monospace;

/* The geometric rule is sharp corners, 1px solid white (p.12). At the
density of a marketing page that reads great; across a 2000-word doc
every box at full white turns into noise. So: full white where a box is
a deliberate accent, a dimmed white for the long-form surfaces that just
need an edge. Same rule, two volumes - p.1 licenses the looser reading. */
--tf-border-strong: 1px solid var(--tf-white);
--tf-border: 1px solid rgb(var(--tf-white-rgb) / 0.2);
--tf-offset: 0.55rem; /* hard-shadow offset, scaled from BoxShadowImage */

/* Reading measure, ~75 characters of Overpass at the docs body size.
Deliberately rem and not ch: `ch` resolves against each element's own
font, so condensed Barlow headings would get a cap ~15% wider than the
paragraphs under them and the two would not line up. */
--tf-measure: 45rem;

/* Depth without a blurred ambient shadow: a small hard offset in black,
the same zero-blur idiom as BoxShadowImage, just quiet enough to sit
under every surface on a documentation page. */
--tf-raise: 3px 3px 0 rgb(0 0 0 / 0.55);

/* A flat fill reads as a sticker. A 1px lit top edge plus a shallow sheen
falling off down the face reads as a surface catching light from above -
this is the depth that went missing when the corners went square, not
the rounding. Both are white overlays, so they work on any base fill. */
--tf-panel-sheen: linear-gradient(to bottom, rgb(var(--tf-white-rgb) / 0.035), transparent 55%);
--tf-panel-shadow: inset 0 1px 0 rgb(var(--tf-white-rgb) / 0.07), var(--tf-raise);
}

/* --- brand primitives --------------------------------------------------- */

/* Green -> pink hairline. The website's GradientLine component, minus GSAP -
it wipes in on scroll via an animation-timeline instead of a JS observer. */
.tf-rule {
display: block;
width: 100%;
height: 0.25rem;
border: none;
background-image: linear-gradient(to right, var(--tf-green), var(--tf-pink));
transform-origin: left center;
}

@supports (animation-timeline: view()) {
.tf-rule--reveal {
animation: tf-wipe-in linear both;
animation-timeline: view();
animation-range: entry 10% cover 28%;
}
}

@keyframes tf-wipe-in {
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}

/* Hard offset shadow, zero blur - the website's BoxShadowImage. This is the
brand's hover/depth idiom; ambient blurred shadows are not. */
.tf-offset-frame {
border: var(--tf-border);
box-shadow: var(--tf-offset) var(--tf-offset) 0 var(--tf-green);
}

.tf-offset-frame--pink {
box-shadow: var(--tf-offset) var(--tf-offset) 0 var(--tf-pink);
}

/* Raised panel. Pair with `.tf-lift` for something interactive. */
.tf-panel {
background-image: var(--tf-panel-sheen);
box-shadow: var(--tf-panel-shadow);
}

/* Lift on hover: the panel slides out of its own shadow, which swaps to
green. The lit top edge is kept so the face stays lit while it moves. */
.tf-lift {
transition:
transform 0.15s ease-out,
box-shadow 0.15s ease-out,
background-color 0.15s ease-out;
}

.tf-lift:hover {
transform: translate(-3px, -3px);
box-shadow:
inset 0 1px 0 rgb(var(--tf-white-rgb) / 0.09),
6px 6px 0 var(--tf-green);
}

@media (prefers-reduced-motion: reduce) {
.tf-lift,
.tf-rule--reveal {
transition: none;
animation: none;
}

.tf-lift:hover {
transform: none;
}
}

/* RGB split, style guide p.12. Green up-left, pink down-right, black keyline
so the glyph edge survives both. Prominent elements only, per the guide. */
.tf-glitch {
color: var(--tf-white);
text-shadow:
1px 1px 0 var(--tf-black),
-1px -1px 0 var(--tf-black),
1px -1px 0 var(--tf-black),
-1px 1px 0 var(--tf-black),
4px 4px 0 var(--tf-pink),
-4px -4px 0 var(--tf-green);
}

/* Background wordmark field - style guide p.12. Giant Barlow Condensed italic
bold TRICKFIRE, one letter of offset per row, barely above the surface.
Rows are rendered to overflow the container and clip at its edges, so the
field reads as full-bleed the way it does on the style guide's own page. */
.tf-wordmark-field {
font-family: var(--tf-font-heading);
font-style: italic;
font-weight: 700;
font-size: clamp(3.5rem, 9vw, 5.8rem);
line-height: 0.92;
letter-spacing: 0.02em;
color: var(--tf-wordmark);
white-space: nowrap;
user-select: none;
}
Loading
Loading