Avishkar Patil Design System
Overview
This design system captures a deliberately reductive dark-mode portfolio experience — the visual equivalent of a terminal boot sequence or a system initialization screen. The entire composition rests on a near-black canvas ({colors.surface-dark}) overlaid with a faint dot-grid texture that evokes graph paper, oscilloscope displays, or CRT phosphor patterns. There are no cards, no navigation bars, no footer chrome — only a centered column of typographic and symbolic elements that fade in sequentially, suggesting the page itself is "loading" or coming online.
Brand voltage lives almost entirely in contrast rather than color. With {colors.primary} set to pure white (#ffffff) against the black void, every glyph carries maximum visual weight. The single moment of "color" in the traditional sense is absent; this is a monochrome system where hierarchy is enforced through font family selection, weight deltas, scale jumps, and opacity shifts. The {typography.display-lg} heading in Space Grotesk at 56px/600 weight dominates the viewport like a BIOS banner, while the {typography.mono} status text beneath it ("OPTIMIZING ASSETS...") grounds the composition in a technical, process-oriented voice.
The shape language is binary: either fully circular ({rounded.circle} for icon containers and potential avatar treatments) or minimally rounded ({rounded.sm} at 2px for the loader track). There are no soft cards, no pill buttons, no generous border radii — this system prefers sharp geometry that echoes code editors and command-line interfaces. Spacing follows an asymmetric but intentional rhythm: the hero container breathes with {spacing.xl} (40px) vertical padding while internal elements stack at tighter intervals (20–30px), creating a compressed, information-dense core surrounded by negative space.
Two sub-systems are detectable even from this single screen: the boot-sequence dialect (the current view, with its loading metaphor, monospace status readouts, and sequential fade-in animations) and what appears to be a social-link dialect (the icon row at bottom, which likely expands into a full contact/navigation layer). The transition tokens suggest these states animate smoothly via width/height morphs and opacity crossfades rather than hard cuts.
Key Characteristics:
- Pure dark canvas (
{colors.surface-dark}) with optional dot-grid grain overlay — no gradients, no imagery, no photographic elements. - Monochrome palette:
{colors.ink}/{colors.muted}/{colors.muted-dim}form the only text hierarchy; all UI chrome is white or transparent. - Dual-typeface system: Space Grotesk for display headings ({typography.display-lg}), Space Mono for everything else ({typography.body-md}, {typography.mono}, {typography.button}).
- Technical voice: monospace subheadings use
{typography.mono}at 13px with wide letter-spacing (0.08em), reading as system output. - Minimal rounding vocabulary:
{rounded.circle}(50%) for icons,{rounded.sm}(2px) for micro-elements — nothing softer. - Animation-forward:
fadeInUpentry animations and aloadkeyframe for the progress bar, both timed around {extensions.motion.duration}. - Loader component uses
{colors.loader-track}as background with{colors.loader-fill}animation,{rounded.pill}geometry. - Social icons rendered as inline SVG or icon font, sized to
{component.icon-button}(24px), colored{colors.muted}default /{colors.ink}on hover. - Max content width constrained to
{spacing.container}(670px), centering all hero content in a readable column.
Colors
Brand & Accent
- Primary (
{colors.primary}— #ffffff): The sole brand color — pure white. Used for the hero heading text, loader fill animation, and all hover-state icon treatments. In this monochromatic system, white functions as both "brand color" and "maximum emphasis." - On Primary (
{colors.on-primary}— #000000): Black, used when rendering text or symbols atop white surfaces (inverted contexts, if any exist).
Surface
- Canvas (
{colors.canvas}— #ffffff): The logical "page background" token (pre-assigned). On this dark-mode site, the visible background is{colors.surface-dark}; this token exists for light-mode symmetry or framework compatibility. - Surface Dark (
{colors.surface-dark}— #0a0a0a): The true page background — near-black, slightly warmed from pure#000000to avoid crushing depth entirely. Covers the full viewport behind all content. - Surface Elevated (
{colors.surface-elevated}— #141414): A subtly lighter black for any raised panels, dropdowns, or modal surfaces that might appear in expanded states. Not visible on the current screen but implied by the elevation model. - Surface Glass (
{colors.surface-glass}— rgba(255, 255, 255, 0.06)): A translucent white wash at 6% opacity. Used for subtle overlays, hover highlights on icon containers, or glassmorphic panel backgrounds.
Text
- Ink (
{colors.ink}— #ffffff): Primary text color — pure white for maximum legibility against{colors.surface-dark}. Used for the hero heading and any top-priority copy. - Body (
{colors.body}— #ffffff): Identical to ink in this system; reserved for paragraph-level content if the site expands beyond the boot screen. - Muted (
{colors.muted}— #888888): Mid-gray at ~53% luminance. Used for the status subheading ("OPTIMIZING ASSETS..."), default icon colors, and secondary informational text. - Muted Dim (
{colors.muted-dim}— #555555): Darker gray (~33% luminance) for tertiary text, disabled states, or decorative elements that must recede further. - On Dark (
{colors.on-dark}— #ffffff): Alias for white text on dark backgrounds — semantically identical to{colors.ink}here but named for clarity in mixed-mode contexts. - On Surface (
{colors.on-surface}— #ffffff): Another white alias for text rendered on any surface variant.
Hairlines & Borders
- Hairline (
{colors.hairline}— rgba(255, 255, 255, 0.12)): Subtle divider lines at 12% white opacity. Used for the loader track background, potential separator rules, or input borders. - Hairline Strong (
{colors.hairline-strong}— rgba(255, 255, 255, 0.2)): Slightly more visible borders at 20% opacity for focus rings, active states, or emphasized dividers.
Semantic / Utility
- Loader Track (
{colors.loader-track}— rgba(255, 255, 255, 0.1)): Background channel for the animated progress bar — 10% white, appearing as a faint horizontal rule. - Loader Fill (
{colors.loader-fill}— #ffffff): The animated fill portion of the progress bar — solid white, drawing the eye to the "loading" metaphor.
Typography
Font Family
The system employs a two-typeface pairing that signals "technical portfolio" without cliché:
- Space Grotesk (sans-serif) — Reserved exclusively for display headings. Its geometric construction, slightly squarish proportions, and distinctive lowercase
aandggive it a engineered-yet-personal character. Loaded from Google Fonts at weights 300 and 600 (though only 600 is used on this screen). - Space Mono (monospace) — The workhorse for all non-display text: status readouts, body copy (if added), button labels, captions, and any UI chrome requiring a "system output" voice. Its uniform character width reinforces the terminal/boot-sequence metaphor.
Both fonts are loaded via the Google Fonts CDN in a single request: family=Space+Grotesk:wght@300;600&family=Space+Mono&display=swap. Fallback stacks are sans-serif and monospace respectively.
Hierarchy
| Token | Size | Weight | Line Height | Letter Spacing | Use |
|---|---|---|---|---|---|
| {typography.display-xl} | 72px | 600 | 1.1 | -1.5px | Reserved for future large-screen hero headings (not currently visible) |
| {typography.display-lg} | 56px | 600 | 1.15 | -1px | Main hero heading ("AVISHKAR PATIL") — the dominant typographic element |
| {typography.body-lg} | 18px | 400 | 1.6 | 0.05em | Potential body copy for expanded content sections |
| {typography.body-md} | 16px | 400 | 1.5 | 0.04em | Standard paragraph text (pre-assigned role) |
| {typography.mono} | 13px | 400 | 1.4 | 0.08em | Status subheading ("OPTIMIZING ASSETS..."), system messages, metadata |
| {typography.mono-sm} | 11px | 400 | 1.3 | 0.12em | Micro-copy: timestamps, version strings, debug info |
| {typography.button} | 13px | 400 | 1 | 0.1em | Button labels, nav links, interactive text (all-caps convention) |
Principles
The typography system trusts scale and family as its primary hierarchy signals, not weight. Space Grotesk at 56px ({typography.display-lg}) is visually unmistakable as the page title; dropping to Space Mono at 13px ({typography.mono}) for the status line creates an immediate "heading vs. data" distinction without requiring bold/semibold weights below the display level. All non-display text sits at font-weight: 400 (normal), which feels appropriate for a monospace context — bold monospace can appear harsh or cartoonish at small sizes.
Letter-spacing plays a functional role in the monospace roles: {typography.mono} adds 0.08em tracking, and {typography.button} pushes to 0.1em. This slight expansion improves legibility of uppercase strings (the status text and likely all button labels render in caps) and echoes the "teletype" aesthetic of wide-spaced terminal output. The display heading does the opposite: -1px letter-spacing tightens the geometric Sans to prevent it from feeling too airy at large sizes.
There are no italic variants in use, no underline decorations (links likely use color-only or opacity shifts), and no text-transform rules visible in the CSS (though the screenshot suggests the status text is visually uppercase — possibly authored in caps in the HTML).
Note on Font Substitutes
Both Space Grotesk and Space Mono are freely available on Google Fonts and require no licensing workaround. If substitution were necessary (e.g., for an offline environment):
- Space Grotesk → JetBrains Sans or Inter (geometric alternates); Outfit for a closer match to the square proportions.
- Space Mono → IBM Plex Mono, Fira Code, or Source Code Pro (any modern programming monospace with tabular figures).
Define these as CSS custom properties for easy swapping:
--font-display: 'Space Grotesk', sans-serif;
--font-mono: 'Space Mono', monospace;
Layout
Spacing System
-
Base unit: 4px (inferred from the spacing scale's granularity: 2, 4, 8, 16, 24, 40, 80).
-
Tokens:
{spacing.xxs}(2px): Micro-adjustments, hairline offsets.{spacing.xs}(4px): Icon internal padding, gap between tightly grouped elements.{spacing.sm}(8px): Small gaps between related items (icon-to-icon in the social row).{spacing.md}(16px): Standard element spacing, horizontal padding in the hero container.{spacing.lg}(24px): Margin above the social icons row; comfortable separation between major blocks.{spacing.xl}(40px): Vertical padding in the hero container; significant breathing room.{spacing.section}(80px): Section-to-section vertical rhythm (reserved for multi-section pages).{spacing.container}(670px): Max-width of the centered content column.
-
Section padding (vertical):
{spacing.xl}(40px) — applied to{component.hero-container}, creating top/bottom margins around the centered content block. -
Card internal padding: Not applicable on the current screen (no card surfaces), but future panels would likely use
{spacing.lg}(24px) or{spacing.xl}(40px) internally. -
Gutters: The hero container uses
{spacing.md}(16px) left/right padding within the 670px max-width, ensuring content never touches the viewport edge on mobile.
Grid & Container
- Max content width: 670px (
{spacing.container}). This is narrower than typical marketing sites (usually 1100–1280px) and reflects the portfolio's editorial, reading-focused intent — the page feels like a centered document or a wide column of code. - Density choice: Very low density. The visible screen contains exactly five distinct elements (heading, status, loader, two icons) with generous vertical distribution. This is anti-marketplace, pro-atmosphere.
- Grid behavior: No multi-column grid is active on this screen — everything flows in a single centered column. Future sections (projects list, about text) would likely adopt a 1-column layout within the same 670px constraint, or potentially a 2-column asymmetrical split for desktop (text + image).
- Hero column splits: N/A — the current hero is a single centered column. If an illustration or 3D element were added, it would likely sit to the right of the text in a roughly 60/40 split within the 670px container.
Whitespace Philosophy
Whitespace is the dominant design material here. The system uses negative space not as padding between content but as the content's stage — the black void IS the experience. Roughly 70% of the viewport is empty on a 1920×1080 screen, with all visual matter compressed into the central 670×400px region. This refusal to fill space signals confidence (the developer doesn't need to prove busyness) and directs focus laser-like to the name, status, and social entry points.
Header Architecture
No traditional header exists on this screen. The layout is:
+----------------------------------------------------------+
| [FULL VIEWPORT - {colors.surface-dark}] |
| |
| +------------------------------------+ |
| | [hero-container - 670px max] | |
| | | |
| | AVISHKAR PATIL | |
| | (display-lg, centered) | |
| | | |
| | OPTIMIZING ASSETS... | |
| | (mono, muted, centered) | |
| | | |
| | ============ | |
| | (loader-bar) | |
| | | |
| | [in] [gh] | |
| | (social-icons-row) | |
| +------------------------------------+ |
| |
+----------------------------------------------------------+
Hero Section
The hero is the entire visible page. Its structure is purely vertical and centered:
[VERTICAL STACK - centered horizontally]
│
├─ h1.hero-heading
│ "AVISHKAR PATIL"
│ Font: {typography.display-lg}
│ Color: {colors.ink}
│ Animation: fadeInUp (delay 0ms)
│
├─ div.status-subheading
│ "OPTIMIZING ASSETS..."
│ Font: {typography.mono}
│ Color: {colors.muted}
│ Animation: fadeInUp (delay ~100ms, class: delay-1)
│
├─ div.loader-bar
│ Track: {colors.loader-track}, 2px tall, rounded pill
│ Fill: {colors.loader-fill}, animating via "load" keyframe
│ Animation: fadeInUp (delay ~200ms, class: delay-2)
│
└─ div.social-icons-row
Gap: ~{spacing.lg} between icons
Animation: fadeInUp (delay ~300ms, class: delay-3)
│
├─ a.icon-wrap > icon-button (LinkedIn)
└─ a.icon-wrap > icon-button (GitHub)
Elevation & Depth
| Level | Treatment | Use |
|---|---|---|
| 0 (Flat) | No shadow, direct on {colors.surface-dark} | Page background, text, icons, loader |
| 1 (Hairline) | {colors.hairline} border or {colors.surface-glass} bg | Subtle separators, icon hover backgrounds |
| 2 (Soft glow) | {extensions.shadows.glow-sm} (white 8px blur at 8% opacity) | Focus rings, active icon states |
| 3 (Modal glow) | {extensions.shadows.glow-md} (white 20px blur at 12% opacity) | Potential dropdowns, modals, tooltips |
The depth philosophy is flat-first with optical glow instead of cast shadows. Because the canvas is near-black, traditional dark box-shadows would be invisible. Instead, the system uses white-based glows at low opacity to create elevation — a technique borrowed from dark-mode OS interfaces and gaming HUDs. The {colors.grain-overlay} (a CSS background pattern or canvas-drawn noise) adds tactile depth to the flat planes, preventing the black background from feeling like a void and giving it a subtle film-grain or sensor-noise texture.
If decorative depth exists, it is the dot-grid background — a repeating pattern of 1–2px dots at low opacity (likely {colors.muted-dim} or darker) spaced ~20–30px apart across the entire viewport. This is not a CSS gradient or photo; it is a programmatic texture that gives the eye something to register in the negative space.
Shapes
Border Radius Scale
| Token | Value | Use |
|---|---|---|
| {rounded.sm} | 2px | Loader track, potential micro-badges, tag elements |
| {rounded.DEFAULT} | 4px | Default fallback (not prominently used on current screen) |
| {rounded.md} | 8px | Future card panels, input fields, tooltip containers |
| {rounded.lg} | 12px | Larger panels, image containers (if added) |
| {rounded.pill} | 9999px | Loader bar (full rounding creates a capsule/pill shape) |
| {rounded.circle} | 50% | Icon button containers, avatars, any perfectly round element |
Photography Geometry
No photography is present on the current screen. If images are added in expanded sections (project thumbnails, headshot), they would likely follow one of these conventions based on the system's technical aesthetic:
- Project thumbnails: 16:9 or 4:3 aspect ratio,
{rounded.md}(8px) corners, subtle{colors.hairline}border, possible{colors.surface-glass}overlay on hover. - Avatar/headshot: Circular (
{rounded.circle}), 80–120px diameter, solid{colors.hairline-strong}border to separate from the dark background. - Full-bleed hero imagery: Unlikely given the current minimalist direction, but if used, would employ a dark multiply blend mode or heavy desaturation to maintain the monochrome mood.
Components
No hover states documented. Hover behavior is unreliable to extract from a single screenshot. State variants live as separate entries in the
components:frontmatter (e.g.{component.icon-button-hover},{component.text-input-focus}); add hover styling at implementation time per your stack's conventions.
Core Structure
{component.page-canvas} — The root surface of the entire page. Background {colors.surface-dark} (near-black), text color defaults to {colors.ink} (white). Contains the grain overlay, cursor element, and main content column. No padding, no radius — full viewport coverage.
{component.grain-overlay} — A transparent-background div (or canvas element) positioned fixed over the entire viewport, below the cursor but above the page background. Renders the dot-grid or film-noise texture via CSS background-image (repeating radial gradient) or a <canvas> 2D drawing loop. Adds tactile quality to the flat black surface.
{component.cursor-element} — A custom cursor follower (detected as div.cursor in the DOM). Likely a small circle or dot that trails the mouse position with slight lag, using {extensions.motion.easing} timing. Background is probably {colors.ink} or {colors.surface-glass} at 1–2px size. Enhances the "technical/interactive" feel.
Hero Content
{component.hero-container} — The centered content wrapper. Transparent background, {spacing.xl} vertical padding, {spacing.md} horizontal padding, max-width {spacing.container} (670px), margin: 0 auto for centering. Contains all visible text and interactive elements. Uses display: flex; flex-direction: column; align-items: center; to stack children vertically and center them horizontally.
{component.hero-heading} — The <h1> element displaying "AVISHKAR PATIL". Typography {typography.display-lg} (Space Grotesk, 56px, 600 weight, -1px letter-spacing). Color {colors.ink} (white). Animated with fadeInUp class (no initial delay). text-align: center, margin-bottom: ~20px. This is the most prominent element on the page — the entire visual hierarchy funnels toward it.
{component.status-subheading} — The "OPTIMIZING ASSETS..." text line. Typography {typography.mono} (Space Mono, 13px, 400 weight, 0.08em letter-spacing). Color {colors.muted} (#888888). Rendered in uppercase (authored as caps in HTML or via text-transform). Centered below the heading with margin-bottom: ~30px. Has .fade-in.delay-1 classes for staggered entry animation (~100ms after the heading). Functions as a "system status" readout reinforcing the boot-sequence metaphor.
{component.loader-bar} — The progress indicator container. Background {colors.loader-track} (10% white), height 2px, width ~100–150px, {rounded.pill} (fully rounded ends). Positioned center below the status text with margin-bottom: ~40px. Has .fade-in.delay-2 classes for staggered entry (~200ms delay). The fill animation is handled by a child element or pseudo-element.
{component.loader-bar-fill} — The animated white segment inside the loader. Background {colors.loader-fill} (solid white), height 2px (matches parent), initial width 0%, animates to ~60–80% width via the load keyframe (likely an infinite oscillation or a single fill to a stopping point). Creates the illusion that the page is actively loading assets.
Interactive Elements
{component.social-icons-row} — Container for the social link icons. Transparent background, display: flex; gap: ~{spacing.lg}; justify-content: center;. Padding top of {spacing.lg} (24px) to separate from the loader. Has .fade-in.delay-3 classes for the final entry animation (~300ms delay). Contains two {component.icon-wrap} children.
{component.icon-button} — Individual social icon link (LinkedIn, GitHub). Size 24px ({component.icon-button}), transparent background, color {colors.muted} (gray). The icon itself is likely an inline SVG (custom, per {extensions.icons}). No visible border or shadow in default state. On hover (see {component.icon-button-hover}), color shifts to {colors.ink} (white) and may gain a {colors.surface-glass} background circle or a subtle {extensions.shadows.glow-sm} white glow.
{component.icon-button-hover} — Hover state for social icons. Background remains transparent or shifts to {colors.surface-glass} (6% white) in a circular {rounded.circle} shape around the icon. Text/icon color becomes {colors.ink} (full white). Transition uses the global {extensions.motion.duration} (300ms) with {extensions.motion.easing} (cubic-bezier(0.19, 1, 0.22, 1)) — a slightly bouncy ease-out that feels responsive without being playful.
Decorative / Ambient
{component.dot-grid-bg} — The background pattern layer. Implemented either as a CSS background-image using radial-gradient repeats or as a canvas-drawn dot matrix. Dot color is likely {colors.muted-dim} (#555555) or darker at very low opacity (5–10%), spaced approximately 24–30px apart in both axes. Covers the full viewport, positioned below all content (z-index: 0 or negative).
Do's and Don'ts
Do
- Do use
{typography.display-lg}(Space Grotesk, 56px, 600 weight) for the primary page heading — it is the sole display typeface and should be reserved for the most important text (name, project titles). - Do set all monospace text (status lines, metadata, buttons) in
{typography.mono}(Space Mono, 13px) with letter-spacing ≥0.08emto maintain the teletype aesthetic. - Do keep the page background as
{colors.surface-dark}(#0a0a0a) — never introduce gradients, images, or lighter tints that break the void-like canvas. - Do apply
{rounded.pill}(9999px) to any progress indicator or loading bar to match the{component.loader-bar}geometry. - Do use
{colors.muted}(#888888) for secondary text (status lines, default icons) and reserve{colors.ink}(#ffffff) for primary headings and hover states. - Do animate entry sequences with
fadeInUpand staggered delays (0ms, ~100ms, ~200ms, ~300ms) to recreate the "boot sequence" loading effect. - Do constrain content width to
{spacing.container}(670px) and center it — the narrow column is a deliberate editorial choice, not a limitation. - Do add the dot-grid or grain texture as a subtle overlay (
{component.grain-overlay}) to prevent the black background from feeling empty. - Do use
{extensions.shadows.glow-sm}or{glow-md}(white-based blurs) for any focus rings or elevated elements — traditional dark shadows are invisible on this canvas. - Do keep social icons at 24px (
{component.icon-button}) in{colors.muted}by default, shifting to{colors.ink}on interaction.
Don't
- Don't introduce a brand color other than
{colors.primary}(white) — the monochrome palette is intentional and defines the aesthetic. - Don't use font weights above 600 (the
{typography.display-lg}weight) — there is no bold/700+ in this system; hierarchy comes from size and family, not weight. - Don't add drop shadows with dark colors (
#000000orrgba(0,0,0,x)) — they will be invisible against{colors.surface-dark}. Use white glows instead. - Don't expand beyond the 670px content width for text-heavy sections — if wider layouts are needed for project grids, treat them as a separate "gallery" subsystem.
- Don't use rounded corners larger than
{rounded.lg}(12px) for any rectangular element — the shape language is sharp or circular, never "soft app-card." - Don't remove the letter-spacing from monospace elements — the expanded tracking (
0.08em–0.12em) is essential to the technical voice. - Don't add a traditional navigation bar, footer, or sidebar to the boot-sequence screen — this view is purposefully minimal and atmospheric.
- Don't use serif or script typefaces anywhere — the dual sans-serif/monospace pairing is the complete font vocabulary.
- Don't make the loader bar taller than 2px or change its
{rounded.pill}geometry — it is a deliberate minimalist detail. - Don't place multiple calls-to-action or dense text blocks on the hero screen — the current composition (heading, status, loader, 2 icons) is the maximum density for this view.
Motion & Animation
Transition Tokens
--transition-base: all 0.3s cubic-bezier(0.19, 1, 0.22, 1);
--transition-dimensions: width 0.3s cubic-bezier(0.19, 1, 0.22, 1),
height 0.3s cubic-bezier(0.19, 1, 0.22, 1),
background 0.3s,
border 0.3s;
--transition-text-shadow: text-shadow 0.3s ease;
--transition-opacity: opacity 0.3s ease;
The dominant easing curve is cubic-bezier(0.19, 1, 0.22, 1) — an ease-out with a slight overshoot (the second value 1 exceeds 1.0, creating a momentary acceleration past the endpoint before settling). This produces a snappy, responsive feel that stops just short of bouncy. Duration is consistently 300ms across all detected transitions.
Keyframe Animations
fadeInUp— Entry animation for hero elements. Translates Y from ~20–30px below final position to0while fading opacity from0to1. Applied to heading (delay 0), status (delay-1), loader (delay-2), and icons (delay-3) with incremental delays creating the staggered "boot" sequence.load— Progress bar fill animation. Animates thewidthproperty of{component.loader-bar-fill}from0%to a target percentage (likely 60–80%) over ~1.5–2 seconds. May loop infinitely or play once and hold, depending on whether the "loading" state is perpetual or resolves to a reveal.
Interaction Patterns
- Staggered fade-in on load: The four hero elements (heading, status, loader, icons) enter sequentially with ~100ms gaps, creating a cascading "system initializing" effect.
- Progress bar induction: The
{component.loader-bar-fill}animates continuously (or for a set duration) to suggest background asset loading, even if the page is statically delivered. - Custom cursor tracking: The
div.cursorelement follows the mouse pointer with a slight positional lag (likely implemented via JSmousemoveevents withrequestAnimationFrameand a lerp/ease function), adding a subtle interactive layer. - Icon hover brightening: Social icons shift from
{colors.muted}to{colors.ink}on hover, possibly accompanied by a{colors.surface-glass}circle background fade-in and a subtle scale transform (1.0 → 1.05–1.1). - Potential scroll-triggered reveals: Though not visible on a single screen, the presence of
fadeInUpsuggests that additional content below the fold would use the same animation triggered by Intersection Observer on scroll-enter.
Imagery Style
- Photographic imagery: None present on the current screen. If introduced in expanded sections, imagery would likely be treated as high-contrast black-and-white photography, heavily desaturated color, or abstract generative graphics to maintain the monochrome discipline.
- Illustration style: None visible. Given the technical aesthetic, any illustrations would likely be wireframe, blueprint-style line art, isometric technical diagrams, or code-editor screenshots — all rendered in white/gray on dark background.
- 3D / WebGL: The presence of a
<canvas>element in the DOM (alongside agraindiv andcursordiv) suggests potential WebGL or Canvas2D usage — possibly for the dot-grid rendering, particle effects, or a 3D object that loads as the "asset" referenced in the status text. - Gradient usage: None detected. The system avoids gradients entirely; all surfaces are flat
{colors.surface-dark}or transparent. - Abstract / generative: The dot-grid background qualifies as generative abstraction — a mathematical pattern rather than a photographic or illustrated element. It provides visual interest without introducing figurative content.
- Role of imagery: In the current view, imagery is absent by design. The "image" IS the typography and the spatial arrangement — the page relies on type-as-image and negative-space composition rather than visual media.
- Color treatment of future imagery: Any added imagery should be desaturated, high-contrast, and likely treated with a
mix-blend-mode: screenoroverlayto integrate with the dark canvas without creating visual dissonance. - Signature technique: The combination of
<canvas>-rendered grain/dot-grid + custom cursor follower + CSS-animated loader creates a "living" technical atmosphere without traditional imagery.
Icon System
- Library: Custom SVG (detected as
iconLibs: []in framework analysis — no external icon library loaded). Icons are inline SVGs or SVG sprites embedded directly in the HTML. - Specific icons observed:
- LinkedIn — The standard LinkedIn "in" logo (boxed or text form), rendered as a path within the first
icon-wrapdiv. - GitHub — The GitHub Octocat silhouette or the GitHub mark (outline style), rendered in the second
icon-wrapdiv.
- LinkedIn — The standard LinkedIn "in" logo (boxed or text form), rendered as a path within the first
- Treatment:
- Style: Stroke-based or filled-outline (appears as a thin-stroke or lightweight filled icon in the screenshot, consistent with the minimal aesthetic).
- Color:
currentColorinherited from parent — defaults to{colors.muted}(#888888), switches to{colors.ink}(#ffffff) on hover. - Size: 24px × 24px (matching
{component.icon-button}size), though the visible render may be slightly smaller (18–20px) with padding within the 24px hit area. - Alignment: Vertically centered with adjacent text (if any) or centered within the
icon-wrapcontainer. Theicon-wrapdivs are likelydisplay: flex; align-items: center; justify-content: center;to center the SVG.
Recommended Frontend Stack
- Framework: Vanilla HTML/CSS/JS or Astro (for static portfolio)
- Styling: Vanilla CSS or CSS Modules (no Tailwind detected;
transitions and keyframes are hand-authored)
- Fonts: Google Fonts: Space Grotesk (wght 300;600) + Space Mono
CSS variables: --font-display, --font-mono
- Animation: Vanilla CSS @keyframes (fadeInUp, load) +
JS requestAnimationFrame for cursor tracking
- Icons: Custom inline SVG (LinkedIn, GitHub)
- Component lib: None (hand-authored components)
- Build tool: Vite or Astro (if static); otherwise plain HTML
Responsive Behavior
Breakpoints
| Name | Width | Key Changes |
|---|---|---|
| Mobile | < 640px | Hero heading scales down (possibly to 36–40px), container padding reduces to {spacing.md} (16px), icons may stack vertically or reduce gap |
| Tablet | 640px – 1024px | Full layout maintained; heading may stay at 48–52px (slight reduction from 56px) |
| Desktop | 1024px – 1440px | As designed: 56px heading, 670px container, all spacings at specified values |
| Wide | > 1440px | Container remains 670px centered; additional negative space on sides; dot-grid may expand spacing |
Touch Targets
{component.icon-button}: 24px × 24px visible icon, but theicon-wrapcontainer likely extends to 44px × 44px minimum (WCAG AAA touch target) with transparent padding. Verify hit area meets 44×44px minimum for mobile.{component.loader-bar}: Non-interactive decorative element; no touch requirements.{component.hero-heading}/{component.status-subheading}: Text elements; no specific touch targets, but ensure line height prevents tap overlap on mobile.
Collapsing Strategy
- Navigation: No traditional nav exists on this screen. If a menu were added for mobile, it would likely be a hamburger-triggered overlay or a slide-up sheet, consistent with the technical aesthetic.
- Hero columns: Currently single-column centered; no collapse needed. If a two-column layout (text + illustration) is added for desktop, mobile would stack to single column with the illustration above or below the text.
- Social icons row: On very narrow screens (< 360px), the gap between icons may reduce from
{spacing.lg}(24px) to{spacing.md}(16px) or{spacing.sm}(8px) to prevent overflow. Icons will not wrap to a second line (the row uses flex withflex-wrap: nowrapimplied). - Dot-grid background: Maintains full coverage at all breakpoints. Dot spacing could theoretically increase on larger screens for visual consistency, but a fixed 24–30px spacing works across all viewports.
- Cursor element: Should be hidden on touch devices (
@media (hover: none)orpointer: coarse) since custom cursor followers are irrelevant and potentially confusing on mobile/touch.
Image Behavior
- Hero illustrations (future): If a 3D canvas element or image is added to the right of the hero text, it should hide on mobile (
display: nonebelow 768px) to preserve the single-column centered layout, or move above/below the text with reduced dimensions. - Project thumbnails (future): Would adopt a responsive grid (1 column on mobile, 2 columns on tablet, 3 columns on desktop) with aspect-ratio-maintained images (
aspect-ratio: 16/9or4/3) and{rounded.md}corners.
Iteration Guide
-
Start with the canvas. Set
background-color: {colors.surface-dark}onbody, add the{component.grain-overlay}as aposition: fixed; inset: 0; pointer-events: none;div with a repeating radial gradient for dots, and initialize the{component.cursor-element}(a 20px circle,position: absolute, hidden on touch devices). -
Build the hero container. Create a
max-width: {spacing.container}(670px),margin: 0 auto,padding: {spacing.xl} {spacing.md}flex column centered withalign-items: center. This is{component.hero-container}— every visible child goes inside. -
Implement the typography cascade. Add the
<h1>with{typography.display-lg}(Space Grotesk, 56px, 600, -1px tracking, white), then the status<div>with{typography.mono}(Space Mono, 13px, 0.08em tracking, {colors.muted}). Ensure Google Fonts are loaded before painting to avoid FOUT/FOIT. -
Create the loader. Build
{component.loader-bar}as a 2px-tall, 120px-wide,{rounded.pill}div with{colors.loader-track}background. Inside, add a pseudo-element or child for{component.loader-bar-fill}(white, 2px, animated via@keyframes loadfromwidth: 0towidth: 70%). -
Add social icons. Insert the
{component.social-icons-row}flex container with two{component.icon-wrap}children. Place inline SVGs for LinkedIn and GitHub inside, sized to 24px, colored{colors.muted}. Add:hoverstyles for{component.icon-button-hover}(color becomes{colors.ink}, optional{colors.surface-glass}circle background). -
Apply staggered animations. Define
@keyframes fadeInUp(transform translateY 20px → 0, opacity 0 → 1). Apply to heading, status, loader, and icons with increasinganimation-delay(0s, 0.1s, 0.2s, 0.3s). Use{extensions.motion.duration}(300ms) and{extensions.motion.easing}for the timing function. -
Wire the custom cursor. Attach a
mousemovelistener todocument, update the{component.cursor-element}styleleft/topwith a lerp (linear interpolation) for smooth following. Usetransform: translate(-50%, -50%)for centering on the pointer. -
Test at mobile widths. Reduce viewport to 375px. Verify the heading remains readable (may need a media query to reduce to 36–42px), icons don't overflow, and padding compresses gracefully. Hide the custom cursor on touch devices.
-
Validate all token references. Run
npx @google/design.md lint DESIGN.mdafter completion. Check forbroken-ref(every{token.path}in prose must match frontmatter),orphaned-tokens(unused tokens), andcontrast-ratiowarnings (white on #0a0a0a passes AAA at large sizes). -
Font setup for local development. Define CSS custom properties:
:root { --font-display: 'Space Grotesk', sans-serif; --font-mono: 'Space Mono', monospace; }Load via
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;600&family=Space+Mono&display=swap" rel="stylesheet">. Both fonts are free and require no API key.
Known Gaps
- Hover state specifics: While
{component.icon-button-hover}is documented structurally, the exact background treatment (transparent vs.{colors.surface-glass}circle), scale transform (if any), and transition properties are inferred from the system's motion tokens, not observed directly. - Loading completion state: It is unclear whether the
{component.loader-bar-fill}animation loops infinitely (perpetual "loading" aesthetic) or completes and triggers a page transition/reveal. The screenshot shows it partially filled with no obvious end-state. - Cursor element styling: The
div.cursoris detected in the DOM but its exact appearance (size, color, border, mix-blend-mode) cannot be determined from CSS alone without seeing it in motion. - Grain/dot-grid implementation: Whether the background pattern is a CSS
background-image(repeating-radial-gradient), an SVG data-URI, or a Canvas2D drawing loop is ambiguous. The visual result is clear (evenly spaced dots), but the implementation path affects performance and resolution-independence. - Below-fold content: The screenshot captures only the initial boot-sequence screen. No information is available about project galleries, about sections, contact forms, or additional pages that may exist on the site.
- Focus ring styles: No explicit
:focus-visiblestyles are detectable. Keyboard users' focus indicators (outlines on icons, focus ring on any future interactive elements) must be designed from scratch following WCAG guidelines. - Reduced-motion preferences: The
prefers-reduced-motionmedia query handling is not visible in the extracted CSS. Users who disable animations should see all elements immediately visible (nofadeInUpdelays) and a static loader bar. - JavaScript dependencies: The
<script>tag content is truncated in the DOM extract. It likely contains the canvas grain renderer, cursor tracking logic, and possibly intersection observers for scroll animations — all critical to the visual experience but opaque to static analysis. - Form validation states: No forms are visible, so error/success/warning states (and their corresponding semantic colors) are unobserved. The frontmatter includes no
error,success, orwarningcolor tokens because they have no grounding in the current screenshot.