Pixel Pakt · Frontend

Styleguide

Design-Token und Layout-Primitives aus Schritt 1 der Spec. Jede Komponente mit Live-Beispiel und Aufruf. Diese Seite ist selbst nur aus den Primitives und Token gebaut.

Brand

Die Marke als Komponente: Wortmarke als Bild, wo Platz ist, sonst die Textfassung in der Display-Font – Regenbogen auf „Pixel“, Weiß auf „Pakt“, Strays in derselben Farbe (Font-Feature ss03, strays-text). Nur auf dunklen Flächen.

Varianten

Props: variant (auto = Bild ab md, Text darunter | image | text), size (sm | md | lg), to (Default /, null ohne Link).

image mdPixel Pakt
text sm Pakt
text md Pakt
text lg Pakt
<Brand />                       /* auto: Fenster schmaler ziehen */
<Brand variant="image" size="md" />
<Brand variant="text" size="lg" to={null} />

Farben

Alle Farben sind Token in app.css. Utilities: bg-*, text-*, border-*. Es gibt keine Standard-Tailwind-Palette und keine arbitrary values.

Flächen

Zwei Stufen je Seite. Cards haben dieselbe Fläche wie die Seite und heben sich nur über den Rahmen ab; paper-muted ist für Chips, Panel-Innenflächen und Code. Auf Dunkel gibt es nur ink und die Rahmenfarbe.

paper
paper-muted
paper-border
ink
ink-border
<div className="bg-paper">…</div>
<span className="bg-paper-muted">Chip</span>
<header className="bg-ink text-fg-on-dark">…</header>

Text

Zwei Stufen je Seite: fg für Headlines, Namen und Links, fg-muted für Fließtext, Labels und Chips (6,0:1 auf Paper). Auf Dunkel fg-on-dark und fg-on-dark-muted (9,3:1 auf Ink) für Sublines, Footer-Links und Copyright.

fg
fg-muted
fg-on-dark
fg-on-dark-muted
<h1 className="text-fg">Headline</h1>
<p className="text-fg-muted">Fließtext</p>
<footer className="bg-ink text-fg-on-dark-muted">…</footer>

Brand

brand auf Paper erreicht nur ~4,2:1 – für kleinen Fließtext brand-text nehmen.

brand
brand-hot
brand-soft
brand-text
<span className="text-brand-text">Link</span>
<button className="bg-brand-hot text-fg-on-dark">Beitreten</button>

Kategorie-Akzente

Neon-Grün und Cyan nur als Fläche auf Dunkel oder als Icon-Füllung. Für Text auf Hell die *-text-Varianten.

news
news-deep
news-text
community
community-deep
community-text
events
events-deep
events-text
games
games-deep
games-text
events-badge
/* direkt – nur in Ausnahmen, sonst über data-accent (nächster Abschnitt) */
<span className="text-news-text">Releases</span>

Status

online
success
link-green
<span className="size-2 bg-online" aria-hidden />

Akzent-System

data-accent am Elternteil setzt --accent, --accent-deep und --accent-text. Primitives nutzen nur bg-accent, text-accent-text, border-accent – und wissen nichts von Kategorien.

data-accent

news

text-accent-text

community

text-accent-text

events

text-accent-text

games

text-accent-text

<article data-accent="news">
  <span className="bg-accent px-2 text-ink">Badge</span>
  <h3 className="text-accent-text">Titel</h3>
  <button className="border-2 border-accent">→</button>
</article>

data-surface

Das Gegenstück für Flächen: data-surface=dark setzt Text (text-copy, text-copy-muted), Rahmen (border-rule, divide-rule), Fläche (bg-surface) und den lesbaren Akzent (text-accent-copy) um. Card setzt es bei tone=dark selbst; dunkle Sektionen bekommen es am Wrapper. Komponenten brauchen so kein tone-Prop.

text-copy auf Paper

text-copy-muted


text-accent-copy = games-text

text-copy auf Dark

text-copy-muted


text-accent-copy = games
<section className="bg-ink" data-surface="dark">
  <h2 className="text-copy">Headline</h2>
  <p className="text-copy-muted">Subline</p>
  <hr className="border-rule" />
  <div data-accent="games"><a className="text-accent-copy">Link</a></div>
</section>

Ohne data-accent

Default-Akzent ist Brand-Rot.

Brand als Fallback

<div className="border-2 border-accent">…</div>

Gradients

bg-grad-* für Flächen, text-grad-* für Headline-Zeilen. Gradient-Text bleibt echter Text; ohne background-clip-Support fällt er auf --accent zurück.

Flächen

bg-grad-cta
bg-grad-warm
bg-grad-cool
<button className="bg-grad-cta px-5 py-3 text-fg-on-dark">Jetzt Teil des Pakts werden</button>

Text

Spec: GAMES. in grad-warm, ONE PAKT. in grad-cool.

Different Games.
One Pakt.

<h1 className="font-display text-hero">
  Different <span className="text-grad-warm">Games.</span>
  <span className="text-grad-cool">One Pakt.</span>
</h1>

Typografie

font-display ist die eigene PixelPakt-Font: COLRv1, jede Zelle ein schattierter Pixel-Würfel, die Buchstaben nehmen die Textfarbe. Kleinbuchstaben nutzen die Großbuchstaben-Glyphen. font-body ist Inter mit System-Fallback. Die Root-Schriftgröße ist fluid, alles in rem skaliert mit.

Display

Different Games.

Aktuelle News 0123456789

Community Hub · Spielwelten

<h1 className="font-display text-hero leading-tight">Different Games. One Pakt.</h1>

Strays: lose Pixel an Wortgrenzen

OpenType-Feature der Font. ss01 (strays) reserviert Platz neben dem Wort, ss02 (strays-overhang) lässt die Pixel ohne Vorschub überhängen – in Boxen mit overflow: hidden braucht ss02 Padding. Am Textanfang und -ende sitzen mehr Pixel als an Leerzeichen.

ohne

Different Games. One Pakt.

strays (ss01)

Different Games. One Pakt.

strays-overhang (ss02)

Different Games. One Pakt.

<h2 className="font-display text-3xl strays">Different Games.</h2>
<h2 className="font-display text-3xl strays-overhang">Different Games.</h2>

Stray-Farbe

Die Strays haben einen eigenen Paletteneintrag und lassen sich per font-palette getrennt von den Buchstaben färben. strays-accent folgt data-accent, Default ist Brand-Rot. Feste Paletten: strays-brand, -news, -community, -events, -games, -ink, -paper.

Brand als Default

news Strays

community Strays

events Strays

games Strays

<article data-accent="events">
  <h3 className="font-display strays strays-accent">Pixel Pakt Night</h3>
</article>

<h3 className="font-display strays strays-games">…</h3>

Strays in der Textfarbe

strays-text (ss03) und strays-text-overhang (ss04) malen die Strays in der Textfarbe statt aus der Palette. Damit folgen sie Gradient-Text und currentColor.

Pakt

One Pakt.

Grün mit grünen Strays

<span className="text-grad-logo strays-text">Pixel</span>
<span className="text-fg-on-dark strays-text">Pakt</span>
<p className="text-news strays-text">Grün mit grünen Strays</p>

Auf Dunkel

Buchstaben in Textfarbe, Strays in der Palette. Für einfarbige Strays strays-paper oder strays-ink.

Werde Teil des Pakts

Werde Teil des Pakts

Unsere Spielwelten

<div className="bg-ink text-fg-on-dark">
  <h2 className="font-display strays strays-accent">Werde Teil des Pakts</h2>
  <h2 className="font-display strays strays-paper">Werde Teil des Pakts</h2>
</div>

Gradient + Strays

Gradient-Text färbt nur die Buchstaben (die Font nutzt dafür die Textfarbe), die Strays behalten ihre Palette.

Different Games.
One Pakt.

<h1 className="font-display text-hero leading-tight strays strays-accent">
  Different <span className="text-grad-warm">Games.</span>
</h1>

Schatten und Glow

Dieselben Utilities wie beim Logo. Der harte Versatz ist in em und wächst mit der Schrift, etwa eine Pixelzelle. Strays werfen mit.

Aktuelle News

Pixel Pakt Night

Neue Releases

<h2 className="font-display strays pixel-shadow">Aktuelle News</h2>
<div data-accent="events">
  <h2 className="font-display strays strays-accent glow">Pixel Pakt Night</h2>
</div>

Mehrzeilig

font-display hat eine kompakte Zeilenbox, Strays der Nachbarzeile können sich berühren. font-display-strays nutzt die nativen Metriken der Font mit Platz für die Stray-Zone. Für mehrzeilige Headlines mit Strays die zweite Familie nehmen.

font-display (kompakt)

Spiele
verbinden
Menschen

font-display-strays (native Zeilenbox)

Spiele
verbinden
Menschen

<h2 className="font-display-strays text-3xl strays">
  Spiele verbinden<br />Menschen
</h2>

Zeichenvorrat

A–Z, Ziffern, Umlaute, ß und die Satzzeichen .,!?:;-+=/()_*. Kein Gedankenstrich, kein Halbgeviertstrich – die fallen auf die Systemschrift zurück. Satzzeichen sind kleiner skaliert und bekommen am Wortende keine eigenen Strays.

ABCDEFGHIJKLM NOPQRSTUVWXYZ

ÄÖÜß 0123456789

Hallo, Welt! (Pakt) 20:00 Uhr - Co-op?

lowercase wird zu uppercase

<p className="font-display">ÄÖÜß 0123456789 .,!?:;-+=/()</p>

Skala

text-xs … text-3xl plus text-hero (clamp). Zeilenhöhen: leading-tight für Headlines, leading-body für Text.

text-xsPixel Pakt – Different Games, One Pakt.0.75rem
text-smPixel Pakt – Different Games, One Pakt.0.875rem
text-mdPixel Pakt – Different Games, One Pakt.1rem
text-lgPixel Pakt – Different Games, One Pakt.1.125rem
text-xlPixel Pakt – Different Games, One Pakt.1.5rem
text-2xlPixel Pakt – Different Games, One Pakt.2rem
text-3xlPixel Pakt – Different Games, One Pakt.2.75rem
eyebrowImmer up to date
<p className="text-lg leading-body">…</p>
<p className="eyebrow text-brand">Immer up to date</p>

Spacing

Neun Stufen, alle in rem. Dazu gutter (fluid, 1–4rem) und touch (2.75rem = 44px Mindest-Touchziel). Komponenten setzen keine Außenabstände – der Elternteil verteilt über Stack, Cluster, Grid.

Skala

1
0.25rem
2
0.5rem
3
0.75rem
4
1rem
5
1.5rem
6
2rem
7
3rem
8
4rem
9
6rem
gut
gutter · clamp(1rem, 4vw, 4rem)
tch
touch · 2.75rem
<div className="p-4 gap-5">…</div>   /* 1rem padding, 1.5rem gap */
<main className="px-gutter">…</main>
<button className="min-h-touch">…</button>

Breakpoints

Mobile-first. Media Queries nur in Widgets und Pages für Spaltenlogik, Komponenten reagieren per Container Query (@xs … @2xl) auf ihre eigene Breite.

Prefixe

xs: ≥ 480px
sm: ≥ 768px
md: ≥ 1024px
lg: ≥ 1440px
xl: ≥ 1920px
2xl: ≥ 2560px

Aktive Stufe: base

<div className="grid-cols-1 sm:grid-cols-2 md:grid-cols-3">…</div>
<div className="@container"><p className="@sm:text-lg">…</p></div>

Container

Zentrierter Seitenrahmen: volle Breite bis max-w-site (3072px), seitlicher Gutter fluid. Das einzige Primitive, das Seitenbreite kennt.

Container

Props: as (section, main, …), className (Layout-Primitive dürfen className durchreichen).

Inhalt bis max-w-site, Gutter links und rechts
<Container as="section" className="py-7">
  …
</Container>

Stack

Vertikaler Fluss mit einheitlichem Abstand. Ersetzt jede Form von margin-bottom.

gap

Props: gap (1–9, Default 4), align (start | center | end | stretch), as.

gap={2}
eins
zwei
drei
gap={4}
eins
zwei
drei
gap={6}
eins
zwei
drei
<Stack gap={3}>
  <Box />
  <Box />
  <Box />
</Stack>

align

align="start"
kurz
etwas länger
align="center"
kurz
etwas länger
align="end"
kurz
etwas länger
<Stack gap={2} align="start">…</Stack>

Cluster

Horizontale Gruppe, die umbricht: Buttons, Chips, Meta-Zeilen, Navigation.

gap, justify

Props: gap (Default 3), align (Default center), justify (start | center | end | between), wrap (Default true), as.

RPGCo-opIndieCozyStreamsStrategyShooter
links
rechts
hoch
align=end
<Cluster gap={2}>
  <Chip>RPG</Chip><Chip>Co-op</Chip><Chip>Indie</Chip>
</Cluster>

<Cluster justify="between">
  <Logo /> <Nav />
</Cluster>

Grid

Spaltenraster mit Token-Gap. Feste Spalten je Breakpoint, oder auto-fill nach Mindestbreite – letzteres nur wo auch mehr Inhalt existiert (News-Übersicht, Server-Liste).

cols

Mobile-first Objekt: base, xs, sm, md, lg, xl mit 1–6 Spalten.

1
2
3
<Grid cols={{ base: 1, sm: 2, md: 3 }} gap={5}>
  <ArticleCard /> ×3
</Grid>

min (auto-fill)

So viele Spalten wie passen, jede mindestens min breit. Fenster schmaler ziehen.

Server 1
Server 2
Server 3
Server 4
Server 5
Server 6
Server 7
<Grid min="12rem" gap={4}>
  <ServerCard /> ×n
</Grid>

Card

Fläche mit Pixel-Ecken (quadratische Kerben, Größe --pixel-notch). Die Kerben leben nur hier. Zwei geclippte Ebenen: außen Rahmenfarbe, innen um --border-w eingerückt die Füllung.

tone

Props: tone (paper | dark), padding (none | sm | md | lg), interactive, as. Kein className – Abstand setzt der Elternteil.

tone="paper"

News-Cards, Hub-Panels, Spotlight.

tone="dark"

Quick-Links, Spielwelten.

<Card>Paper</Card>
<Card tone="dark">Dark</Card>

interactive + data-accent

Bei Hover wird der Rahmen zum aktuellen Akzent. Nur unter (hover: hover).

news

Hover mich.

community

Hover mich.

events

Hover mich.

games

Hover mich.

<Grid cols={{ base: 2, md: 4 }}>
  <div data-accent="news"><Card tone="dark" interactive>…</Card></div>
  …
</Grid>

padding

none
sm
md
lg
<Card padding="none"><CoverImage /></Card>
<Card padding="lg">…</Card>

Notch-Größe

--pixel-notch ist in rem und skaliert mit der Root-Schrift. Hier lokal überschrieben, um die Wirkung zu zeigen.

0.25rem
0.5rem
1rem
/* nur Demo – im Produkt bleibt der Token global */
<div style={{ '--pixel-notch': '1rem' }}><Card>…</Card></div>

Divider

Trennlinie in der Rahmenfarbe der aktuellen Fläche.

Divider

Keine Props. Die Farbe folgt data-surface.

paper


<Divider />
<section data-surface="dark" className="bg-ink"><Divider /></section>

VisuallyHidden

Text nur für Screenreader, etwa Labels auf Icon-Buttons.

VisuallyHidden

<button>
  <Icon name="arrow-right" />
  <VisuallyHidden>Alle News anzeigen</VisuallyHidden>
</button>

Icon

Eigene Pixel-Icons auf einem 16×16-Raster, als ein <path> in currentColor mit crispEdges gerendert – kein Sprite-File, keine Library. Neue Icons kommen als Rasterzeichnung in shared/ui/Icon/icons.ts dazu.

Alle Icons

Props: name, size (em folgt der Schriftgröße, sm/md/lg = Token 4/5/6), label (macht das Icon zugänglich, sonst aria-hidden).

arrow-right
chevron-right
chevron-down
plus
close
menu
search
news
community
events
games
comment
clock
crown
trophy
discord
youtube
instagram
twitch
arrow-left
chevron-left
chevron-up
x
<Icon name="arrow-right" />                 /* 1em, dekorativ */
<Icon name="search" size="md" label="Suche" />

Größen und Farbe

Icons erben die Textfarbe. In Fließtext folgt size=em der Schrift.

sm
md
lg

Mehr erfahren

<p className="text-brand-text">Mehr <Icon name="arrow-right" /></p>

Eyebrow

Kleines Uppercase-Label mit Pixel-Marker über Sektionsüberschriften. Marker und Text folgen data-accent und data-surface, Default Brand.

Eyebrow

Props: as (p | span | div). Auf Paper nutzt der Text die *-text-Stufe des Akzents, auf data-surface=dark den reinen Akzent.

Immer up to date

Gemeinsam mehr erleben

Von AAA bis Indie

Gaming · Community · Events · Für alle Spielwelten

<Eyebrow>Immer up to date</Eyebrow>
<div data-accent="events"><Eyebrow>Gemeinsam mehr erleben</Eyebrow></div>
<header className="bg-ink" data-surface="dark"><Eyebrow>Gaming · Community · Events</Eyebrow></header>

Heading & Text

Heading trennt semantische Ebene (as) von der Größe. xs und sm sind Body-Font für Card- und Panel-Titel, md bis hero Display-Font für Sektionen und Seiten. Text ist Fließtext. Beide nehmen die Textfarbe der Fläche.

Heading

Props: as (h1–h4, p, span), size (xs | sm | md | lg | hero), gradient (warm | cool), strays.

Different Games.

Aktuelle News

Community Hub

Die spannendsten Releases des Monats

Nächste Events

Games.

One Pakt.

Pixel Pakt Night

<Heading as="h2" size="lg" strays>Aktuelle News</Heading>
<Heading as="h1" size="hero">Different <span>Games.</span></Heading>
<Heading as="h3" size="sm">Die spannendsten Releases</Heading>

Text

Props: as (p | span | div), size (xs | sm | md | lg), tone (default | muted).

Pixel Pakt ist die Gaming-Community für alle, die Spiele lieben.

Unabhängig von Genre, Plattform oder Spielstil. Gemeinsam spielen, gemeinsam mehr erleben.

Aktuelle Entwicklungen, Releases und mehr.

28. Nov. 2024 · 64 Kommentare

Pixel Pakt ist die Gaming-Community für alle, die Spiele lieben.

Aktuelle Entwicklungen, Releases und mehr.

<Text>Pixel Pakt ist die Gaming-Community für alle.</Text>
<Text size="sm" tone="muted">Aktuelle Entwicklungen, Releases und mehr.</Text>

Button

Button rendert <button>, ButtonLink einen React-Router-Link – beide teilen buttonStyles({ variant, size }). outline und ghost nehmen die Textfarbe des Kontexts, der Gradient-Hover ist ein Overlay mit opacity (Gradients lassen sich nicht animieren).

Varianten

primary | accent | gradient | outline | ghost. accent folgt data-accent (Default Brand). Mindesthöhe 2.75rem auf Touch-Geräten.

Jetzt beitreten
<Button>Jetzt Teil des Pakts werden</Button>
<div data-accent="games"><Button variant="accent">Spielwelten</Button></div>
<ButtonLink to="/community" variant="gradient" trailingIcon="arrow-right">Jetzt beitreten</ButtonLink>
<Button variant="outline">Login</Button>
<Button variant="ghost" leadingIcon="search">Suche</Button>

Abgebrochene Pixel

chipped schneidet unregelmäßige Bruchstellen in die Kante, in em – sie skalieren mit der Schriftgröße. Bei outline folgt der Rahmen der Bruchkante über zwei Ebenen; die Innenfläche nimmt die Farbe der Fläche aus data-surface.

Jetzt beitreten
<Button chipped>Jetzt Teil des Pakts werden</Button>
<ButtonLink to="/community" variant="gradient" chipped trailingIcon="arrow-right">Jetzt beitreten</ButtonLink>
<Button variant="outline" chipped>Login</Button>
<header className="bg-ink" data-surface="dark"><Button variant="outline" chipped>Mehr erfahren</Button></header>

Größen und Zustände

<Button size="sm">Klein</Button>
<Button size="lg" trailingIcon="arrow-right">Groß</Button>
<Button disabled>Deaktiviert</Button>

IconTile

Quadrat in der Akzentfarbe mit Icon. Sitzt in Quick-Link-Cards und Panel-Headern, ist dekorativ – die Überschrift daneben trägt die Bedeutung.

IconTile

Props: icon, size (sm = 2rem, md = 3rem), glow.

Community

Triff Gleichgesinnte, sei Teil des Pakts.

Nächste Events

<div data-accent="news"><IconTile icon="news" /></div>
<IconTile icon="events" size="sm" glow />

ArrowButton

Quadratischer Icon-Button in der Akzentfarbe, in jeder Card. ArrowButton rendert <button>, ArrowLink einen Link. label ist Pflicht, weil kein Text sichtbar ist.

ArrowButton

Props: label, icon (Default arrow-right), size (sm = 2rem, auf Touch 2.75rem | md = 2.75rem), chipped. Hover: accent-deep.

Releases

Die spannendsten Releases des Monats

28. Nov. 202464 Kommentare
<ArrowLink to="/news/release" label="Artikel lesen" />
<ArrowButton label="Schließen" icon="close" size="md" onClick={…} />

Badge & Chip

Badge ist das gefüllte Kategorie-Label in der Akzentfarbe (RELEASES, COMMUNITY, EVENTS). Chip ist das kleine Outline-Tag (RPG, Co-op, Indie).

Badge

Keine Props außer children. Farbe über data-accent.

Releases
Community
Events
Brand
<div data-accent="news"><Badge>Releases</Badge></div>

Chip

RPGCo-opIndieCozyStreams
RPGCo-opIndie
<Cluster gap={2}><Chip>RPG</Chip><Chip>Co-op</Chip><Chip>Indie</Chip></Cluster>

MetaItem & CountBadge

MetaItem ist Icon + Text für Meta-Zeilen (Datum, Uhrzeit, Kommentare), mehrere in einem Cluster. CountBadge ist Icon + Zahl mit unsichtbarer Einheit für Screenreader.

MetaItem

Props: icon, children.

28. Nov. 202420:00 Uhr64 Kommentare
<Cluster gap={4}>
  <MetaItem icon="events">28. Nov. 2024</MetaItem>
  <MetaItem icon="comment">64 Kommentare</MetaItem>
</Cluster>

CountBadge

Props: count, icon (Default comment), label (Pflicht, Einheit für Screenreader).

24 Antworten3 Teilnehmer12 Events
<CountBadge count={24} label="Antworten" />

Avatar & DateBlock

Avatar ist quadratisch (Pixel-Stil, keine Rundung) mit Initialen-Fallback und optionaler Krone. DateBlock zeigt Tag groß und Monat klein in der Akzentfarbe.

Avatar

Props: name, src, size (sm | md | lg), decoration (crown).

LNK
A
Pixel Pakt
<Avatar name="Lunara" src={lunara} size="lg" decoration="crown" />
<Avatar name="Kael" size="sm" />  /* Initialen-Fallback */

DateBlock

Props: date (Date | ISO-String). Rendert ein time-Element mit vollem Datum als Label.

<DateBlock date="2024-11-15T20:00:00+01:00" />

Stat

Eine Kennzahl mit Label, optional mit Icon. box stapelt, row setzt alles in eine Zeile. Mehrere Stats in Grid, Stack oder Cluster.

Stat

Props: value, label, icon, layout (box | row).

2.437Mitglieder insgesamt
1.127Mitglieder online
48Neue Posts (24h)
3Nächste Events
2.437Mitglieder1.127online
3Nächste Events
<Grid cols={{ base: 2 }} gap={4}>
  <Stat icon="community" value="2.437" label="Mitglieder insgesamt" />
</Grid>
<Stat layout="row" icon="events" value="3" label="Nächste Events" />

CoverImage

Bildbox mit festem Seitenverhältnis, Lazy Loading, optionalem Fokuspunkt für den Beschnitt und einem Overlay-Slot mit dunklem Verlauf für Text. Die Mock-Cover sind generierte Pixel-Muster.

CoverImage

Props: src, alt, srcSet, sizes, ratio (16/9 | 4/3 | 3/2 | 1/1), focus, overlay, priority (LCP), children (Overlay).

Pixel-Muster
Pixel-Muster

Overlay-Titel

mit Verlauf

Pixel-Muster
Releases
<CoverImage src={cover} alt="…" ratio="4/3" overlay>
  <Badge>Releases</Badge>
</CoverImage>

SocialIcon & LinkList

SocialIcon ist der quadratische Icon-Link zu einem Netzwerk, öffnet in neuem Tab. LinkList ist Überschrift plus Linkliste für Footer-Spalten und Sidebars. Die Netzwerke und URLs kommen aus shared/config/site.

SocialIcon

Props: network (discord | youtube | instagram | x | twitch), href, label.

import { site } from '@/shared/config'

<Cluster gap={2}>
  {site.social.map(s => <SocialIcon key={s.network} network={s.network} href={s.href} label={s.label} />)}
</Cluster>

LinkList

Props: title, links ({ label, to, external? }).

<LinkList title="Rechtliches" links={[{ label: 'Impressum', to: '/impressum' }, { label: 'Datenschutz', to: '/datenschutz' }]} />

SectionHeader

Eyebrow + Heading + Text + optionaler Link. Mit size=lg wird daraus der PageHeader jeder Unterseite (h1, hero). Akzent und Fläche kommen aus dem Kontext.

Sektion

Props: eyebrow, title, text, link ({ to, label }), size (md | lg), as (h1 | h2), strays.

Immer up to date

Aktuelle News

Hier findest du die neuesten Inhalte aus der Pixel Pakt Community – Spiele-News, Community-Highlights, Event-Ankündigungen und vieles mehr.

Alle News anzeigen

Von AAA bis Indie

Unsere Spielwelten

Egal ob kompetitiv, kooperativ oder entspannt – bei uns findest du immer die passende Spielwelt und Mitspieler.

Alle Spielwelten

Gemeinsam mehr erleben

Community Hub

Tausch dich aus, finde Mitspieler, nimm an Events teil.

Alle Events
<SectionHeader
  eyebrow="Immer up to date"
  title="Aktuelle News"
  text="Hier findest du die neuesten Inhalte aus der Pixel Pakt Community."
  link={{ to: '/news', label: 'Alle News anzeigen' }}
  strays
/>

PageHeader (size=lg)

News

Aktuelle News

Spiele-News, Community-Highlights, Event-Ankündigungen und vieles mehr.

<SectionHeader size="lg" eyebrow="News" title="Aktuelle News" text="Spiele-News, Community-Highlights, Event-Ankündigungen." strays />

Panel

Card mit Header-Zeile aus IconTile, Titel und optionalem Link, darunter freier Inhalt. Die vier Hub-Boxen, später Sidebar-Boxen.

Panel

Props: icon, title, link, tone (paper | dark), as (section | div | aside), children.

Nächste Events

Alle Events
  • Community Game Night
    20:00 Uhr · Discord
  • Syndikat Cup: Valorant
    19:00 Uhr · Turnier
  • Co-op Abend
    20:00 Uhr · Discord

Community Stats

2.437Mitglieder insgesamt
1.127Mitglieder online
48Neue Posts (24h)
3Nächste Events
<Panel icon="events" title="Nächste Events" link={{ to: '/events', label: 'Alle Events' }}>
  <Stack as="ul" gap={0} className="divide-y divide-rule">
    <ListRow … />
  </Stack>
</Panel>

ListRow

Eine Zeile mit den Slots leading, body (title + subline) und trailing. Event-Zeilen, Forum-Themen und Server-Listen sind strukturell identisch. Trennlinien setzt die Liste über divide-y divide-rule.

Slots

Props: as (li | div), leading, title, subline, trailing.

  • N
    Welches Spiel hat euch zuletzt gefesselt?
    von Nekro · vor 2 Std.
    24 Antworten
  • K
    Suche Mitspieler für Elden Ring
    von Kael · vor 5 Std.
    31 Antworten
  • L
    Bestes Indie-Game 2024?
    von Lunara · vor 9 Std.
    19 Antworten
  • Minecraft Survival
    mc.pixelpakt.org · 12/40
  • Valheim
    valheim.pixelpakt.org · 4/10
  • Satisfactory
    offline
<Stack as="ul" gap={0} className="divide-y divide-rule">
  <ListRow leading={<Avatar />} title={<Link to="/t/1">Welches Spiel hat euch zuletzt…</Link>} subline="von Nekro · vor 2 Std." trailing={<CountBadge>24</CountBadge>} />
</Stack>

FeatureCard

Quick-Link-Card: IconTile, Titel, Text und Pfeil. Setzt ihren data-accent selbst. Die ganze Card ist ein Link (gestreckter Titel-Link), der Pfeil ist dekorativ.

QuickLinks

Props: accent, icon, title, text, to, tone (Default dark).

News

Aktuelle Entwicklungen, Releases und mehr.

Community

Triff Gleichgesinnte, sei Teil des Pakts.

Events

Gemeinsame Sessions, Turniere und mehr.

Games

Von AAA bis Indie – unsere Spielwelten.

News

Auch auf Paper, ohne Glow.

Games

Von AAA bis Indie – unsere Spielwelten.

<Grid cols={{ base: 1, xs: 2, md: 4 }} gap={4}>
  <FeatureCard accent="news" icon="news" title="News" text="Aktuelle Entwicklungen, Releases und mehr." to="/news" />
  …
</Grid>

Entity: Article

entities/article – Typ Article, Mapping Kategorie → data-accent (releases → news), ArticleCard und ArticleMeta. Daten aus mockArticles.

ArticleCard

Props: article. Cover mit Badge, Titel als gestreckter Link, Teaser, Meta, Pfeil.

Pixel-Muster in Pink und Violett
Events

Event-Rückblick: Pixel Pakt Night

Volle Server, starke Matches und eine großartige Community – das war die Pixel Pakt Night. Hier sind die besten Momente!

48 Kommentare
import { ArticleCard, mockArticles } from '@/entities/article'

<Grid cols={{ base: 1, sm: 2, md: 3 }} gap={5}>
  {mockArticles.map(a => <ArticleCard key={a.id} article={a} />)}
</Grid>

Entity: Event

entities/event – Typ Event mit Plattform (Discord, Turnier, Ingame), EventRow aus ListRow + DateBlock, EventPlatform. Daten aus mockEvents.

EventRow im Panel

Nächste Events

Alle Events

Nächste Events

import { EventRow, mockEvents } from '@/entities/event'

<Panel icon="events" title="Nächste Events" link={{ to: '/events', label: 'Alle Events' }}>
  <Stack as="ul" gap={0} className="divide-y divide-rule">
    {mockEvents.map(e => <EventRow key={e.id} event={e} />)}
  </Stack>
</Panel>

Entity: Thread

entities/thread – Typ Thread, ThreadRow aus ListRow + Avatar + CountBadge, relative Zeit über shared/lib. Daten aus mockThreads mit festem Bezugszeitpunkt, damit SSR und Client dasselbe rendern.

ThreadRow im Panel

Letzte Forum-Themen

Alle Themen

Letzte Forum-Themen

import { ThreadRow, mockThreads, mockNow } from '@/entities/thread'

<Panel icon="comment" title="Letzte Forum-Themen" link={{ to: '/community', label: 'Alle Themen' }}>
  <Stack as="ul" gap={0} className="divide-y divide-rule">
    {mockThreads.map(t => <ThreadRow key={t.id} thread={t} now={mockNow} />)}
  </Stack>
</Panel>

Entity: Game

entities/game – Typ GameCategory mit eigenem Akzent, GameCategoryCard aus Card dark + CoverImage mit Overlay + Icon + Pfeil, Rahmen in der Akzentfarbe. Daten aus mockGameCategories.

GameCategoryCard

Pixel-Muster in Grau und Grün

Shooter

Action. Reaktion. Teamwork.

Pixel-Muster in Braun und Gold

MMO

Große Welten. Starke Community.

Pixel-Muster in Violett und Pink

Strategy

Planen. Bauen. Erobern.

Pixel-Muster in Blau und Cyan

Co-op

Zusammen mehr erleben.

Pixel-Muster in Grün

Indie

Kreativ. Anders. Besonders.

import { GameCategoryCard, mockGameCategories } from '@/entities/game'

<Grid cols={{ base: 2, md: 5 }} gap={4}>
  {mockGameCategories.map(c => <GameCategoryCard key={c.slug} category={c} />)}
</Grid>

Regeln

Kurzfassung aus CLAUDE.md und Spec §1.

  • Nur Token. Keine arbitrary values (text-[#…], p-[13px]), kein Hex außerhalb von app.css.
  • Kein margin an der Komponentenwurzel. Abstände setzt der Elternteil über Stack, Cluster, Grid.
  • Keine festen Breiten. Komponenten füllen ihren Container.
  • className nur bei Layout-Primitives (Container, Stack, Cluster, Grid).
  • Varianten als Union-Props, ins DOM als data-variant. Slots statt Flags.
  • Kategorie-Akzente über data-accent, dunkle Flächen über data-surface="dark" am Elternteil. Primitives nutzen nur accent-*, copy, rule, surface.
  • Pixel-Kerben nur in Card, Bruchkanten nur über chipped bei Buttons. Keine rounded-*-Radien – es gibt keine.
  • Sondereffekte, die als Utilities unleserlich wären, als Name.css neben der Komponente.