From 704c44146ef8c92d2d3563d8736f13aa1734745e Mon Sep 17 00:00:00 2001 From: Sulakshan Chandra Ghimire Date: Sat, 27 Jun 2026 08:59:33 +0545 Subject: [PATCH] feat(examples): add Ink & Code developer portfolio design system --- examples/ink-and-code/DESIGN.md | 211 ++++++++++ examples/ink-and-code/README.md | 13 + examples/ink-and-code/design_tokens.json | 466 +++++++++++++++++++++++ examples/ink-and-code/tailwind.config.js | 83 ++++ 4 files changed, 773 insertions(+) create mode 100644 examples/ink-and-code/DESIGN.md create mode 100644 examples/ink-and-code/README.md create mode 100644 examples/ink-and-code/design_tokens.json create mode 100644 examples/ink-and-code/tailwind.config.js diff --git a/examples/ink-and-code/DESIGN.md b/examples/ink-and-code/DESIGN.md new file mode 100644 index 00000000..481d9ff4 --- /dev/null +++ b/examples/ink-and-code/DESIGN.md @@ -0,0 +1,211 @@ +--- +name: Ink & Code +description: A minimal developer portfolio design system. Typographic precision meets terminal-native clarity — sharp, confident, and built for developers who let their work speak. +colors: + primary: "#E8E6E1" + secondary: "#A8A29E" + tertiary: "#9A3412" + surface: "#0C0A09" + surface-dim: "#080705" + surface-bright: "#1C1917" + surface-container-lowest: "#050403" + surface-container-low: "#111010" + surface-container: "#1C1917" + surface-container-high: "#292524" + surface-container-highest: "#3A3633" + on-surface: "#E8E6E1" + on-surface-variant: "#A8A29E" + outline: "#57534E" + outline-variant: "#292524" + background: "#0C0A09" + on-background: "#E8E6E1" + primary-container: "#1C1917" + on-primary-container: "#E8E6E1" + tertiary-container: "#431407" + on-tertiary-container: "#FDBA74" + error: "#F87171" + on-error: "#450A0A" + error-container: "#7F1D1D" + on-error-container: "#FECACA" +typography: + display-lg: + fontFamily: Geist + fontSize: 72px + fontWeight: "700" + lineHeight: 80px + letterSpacing: -0.03em + headline-lg: + fontFamily: Geist + fontSize: 36px + fontWeight: "600" + lineHeight: 44px + letterSpacing: -0.02em + headline-md: + fontFamily: Geist + fontSize: 24px + fontWeight: "500" + lineHeight: 32px + letterSpacing: -0.01em + body-lg: + fontFamily: Geist + fontSize: 18px + fontWeight: "400" + lineHeight: 28px + body-md: + fontFamily: Geist + fontSize: 16px + fontWeight: "400" + lineHeight: 26px + label-mono: + fontFamily: Geist Mono + fontSize: 13px + fontWeight: "400" + lineHeight: 20px + letterSpacing: 0.02em + label-sm: + fontFamily: Geist Mono + fontSize: 11px + fontWeight: "500" + lineHeight: 16px + letterSpacing: 0.08em +rounded: + sm: 2px + md: 4px + lg: 6px + xl: 8px + full: 9999px +spacing: + xs: 4px + sm: 8px + md: 16px + lg: 24px + xl: 40px + section: 80px + max-width: 1200px +components: + card-project: + backgroundColor: "{colors.surface-container}" + textColor: "{colors.on-surface}" + rounded: "{rounded.lg}" + padding: "{spacing.lg}" + card-project-hover: + backgroundColor: "{colors.surface-container-high}" + button-primary: + backgroundColor: "{colors.tertiary}" + textColor: "{colors.primary}" + typography: "{typography.label-mono}" + rounded: "{rounded.md}" + height: 40px + padding: 0 20px + button-primary-hover: + backgroundColor: "{colors.surface-container-highest}" + button-ghost: + backgroundColor: "transparent" + textColor: "{colors.on-surface}" + typography: "{typography.label-mono}" + rounded: "{rounded.md}" + height: 40px + padding: 0 20px + button-ghost-hover: + textColor: "{colors.primary}" + tag-skill: + backgroundColor: "{colors.surface-container-high}" + textColor: "{colors.on-surface-variant}" + typography: "{typography.label-sm}" + rounded: "{rounded.sm}" + padding: 2px 8px + nav-link: + textColor: "{colors.secondary}" + typography: "{typography.label-mono}" + nav-link-active: + textColor: "{colors.primary}" + input-field: + backgroundColor: "{colors.surface-container-low}" + textColor: "{colors.on-surface}" + typography: "{typography.body-md}" + rounded: "{rounded.md}" + padding: 12px 16px + height: 44px + input-field-focus: + backgroundColor: "{colors.surface-container}" +--- + +## Brand & Style + +Ink & Code is built on the philosophy that a developer's portfolio is a product, not a resume. The aesthetic is **terminal-native minimalism** — the kind of UI that could exist in a well-crafted CLI tool or a documentation site, yet feels completely at home in a modern browser. + +The design communicates confidence through restraint. There are no gradients, no decoration for decoration's sake. Every element earns its place. The single accent color — a warm, decisive deep burnt orange — acts as a signal rather than decoration: it marks what matters most. + +The dual typeface system pairs **Geist** (clean geometric sans-serif) for reading with **Geist Mono** (its monospace sibling) for labels, tags, and UI chrome. This mirrors how developers think: prose for explanation, monospace for precision. + +## Colors + +The palette is anchored in near-black warm tones — not cold grays, which feel sterile, but deep stone tones that feel like a well-worn terminal. + +- **Primary (#E8E6E1):** Warm off-white. Used for headlines and primary body text. Slightly warmer than pure white to reduce eye strain on dark backgrounds. +- **Secondary (#A8A29E):** Muted warm gray. Used for metadata, timestamps, secondary labels, and nav items in their resting state. +- **Tertiary (#C2410C):** Deep burnt orange. The sole interactive accent. Used exclusively for primary CTAs and active states. It draws the eye without overwhelming. +- **Surface (#0C0A09):** Deep warm black — the canvas. Not pure black (`#000`) which can feel harsh, but a rich stone-dark that feels grounded. + +Surface layers use subtle warm-dark steps (`surface-container` through `surface-container-highest`) to create soft depth between cards and backgrounds without resorting to shadows or borders. + +## Typography + +Two fonts, one family. **Geist** and **Geist Mono** are designed as a matched pair, ensuring visual harmony between prose and code/UI labels. + +- **Headlines:** Geist at high weight with tight negative letter spacing. `display-lg` is reserved for the hero name or opening statement — it should dominate the viewport. +- **Body:** Geist Regular at 16–18px with a generous line-height (1.6×) for comfortable reading of longer project descriptions. +- **Labels & Tags:** Geist Mono exclusively. Every skill tag, nav item, date string, and section marker uses monospace. This creates a clear semantic split: human prose is sans-serif, UI chrome is monospace. +- **Uppercase labels:** `label-sm` is used with `text-transform: uppercase` for section headings (e.g., `PROJECTS`, `EXPERIENCE`) — never for body copy. + +## Layout & Spacing + +The layout uses a single centered column that expands to a max-width of `1200px`, with generous outer padding to ensure the dark background breathes around the content. + +- **Base grid:** 8px. All spacing values are multiples of this unit. +- **Section rhythm:** `80px` between top-level sections (`section` spacing token) creates clear breathing room and scroll pacing. +- **Project grid:** A 2-column responsive grid with `24px` gaps on desktop. Single column on mobile. Cards use internal `24px` padding (`spacing.lg`). +- **Hero zone:** The name/headline block occupies the full viewport height on load, centered vertically, with the primary CTA buttons below it. + +## Elevation & Depth + +This design system avoids box shadows entirely. Depth is communicated through **background color steps** and **surface contrast alone**. + +- **Layer 0 (Canvas):** `surface` / `background` — the page base. +- **Layer 1 (Cards):** `surface-container` — project cards, info blocks. +- **Layer 2 (Hover / Active):** `surface-container-high` — the hover state of a card lifts it visually by stepping up the background one level. + +This approach keeps the UI flat, fast, and readable — no rendering overhead from blurs or large shadow spreads. + +## Shapes + +Shape language is deliberately conservative and **code-adjacent**. + +- **Cards and containers:** `rounded-lg` (6px) — enough to feel modern, not so much it feels playful. +- **Buttons:** `rounded-md` (4px) — tighter than cards, reinforcing that buttons are precision controls. +- **Tags and badges:** `rounded-sm` (2px) — nearly square. Evokes a CLI flag or terminal token. +- **Avatars and circular elements:** `rounded-full` (9999px). + +No decorative shapes, no blobs, no abstract geometric backgrounds. Whitespace and typography carry the visual weight. + +## Components + +### Project Cards + +Cards use `surface-container` as the base and step up to `surface-container-high` on hover. Internally, projects display: a monospace tag cluster (skill tags), a sans-serif title at `headline-md`, body description in `body-md`, and a row of ghost links (`View`, `GitHub`) in `label-mono`. + +### Buttons + +Two variants only. **Primary** (`button-primary`): burnt orange background with warm off-white text, used once per section for the single most important action. **Ghost** (`button-ghost`): transparent fill, used for secondary actions like "View source" or "Read more." Both buttons use Geist Mono for their labels to maintain the monospace UI chrome convention. + +### Skill Tags + +Monospace, near-square (2px radius), muted background. Tags should never use the orange accent — they are informational, not interactive. Use `on-surface-variant` text color to keep them subordinate to project titles and descriptions. + +### Navigation + +A slim top bar with the name/logo on the left (Geist, `headline-md` weight) and nav links on the right in `label-mono`. Nav links default to `secondary` color and transition to `primary` on hover/active — no underlines, no background fills. The active section link uses `primary` color. + +### Contact / Input Fields + +Input fields use `surface-container-low` as the background to sit subtly recessed against the page. The background steps up to `surface-container` on focus — providing a clear and accessible focus signal through tonal shift rather than a colored border. \ No newline at end of file diff --git a/examples/ink-and-code/README.md b/examples/ink-and-code/README.md new file mode 100644 index 00000000..90c93e74 --- /dev/null +++ b/examples/ink-and-code/README.md @@ -0,0 +1,13 @@ +# Ink & Code + +A minimal developer portfolio design system. Typographic precision meets terminal-native clarity such as sharp, confident, and built for developers who let their work speak. + +The aesthetic pairs **Geist** (geometric sans-serif) for prose with **Geist Mono** for all UI chrome, labels, and tags by mirroring the way developers think. A single burnt orange accent on a deep warm-black canvas. No gradients, no decorative shadows. Depth through tonal surface layers alone. + +## Files + +| File | Description | +|------|-------------| +| `DESIGN.md` | The complete design system specification in DESIGN.md format, including both structured YAML design tokens (frontmatter) and human-readable style guidance (markdown body). | +| `tailwind.config.js` | A Tailwind CSS v3 theme configuration derived from the design tokens in the DESIGN.md frontmatter. Covers colors, typography, border-radius, and spacing. Component tokens are intentionally excluded — Tailwind's utility-first approach handles component styling through composition of these primitives. | +| `design_tokens.json` | A [Design Tokens Community Group](https://www.designtokens.org/) JSON file containing all design tokens from the DESIGN.md frontmatter, including component-level tokens. This format is interoperable with tools like Figma, Style Dictionary, and other token pipelines. | \ No newline at end of file diff --git a/examples/ink-and-code/design_tokens.json b/examples/ink-and-code/design_tokens.json new file mode 100644 index 00000000..d4b5f54f --- /dev/null +++ b/examples/ink-and-code/design_tokens.json @@ -0,0 +1,466 @@ +{ + "$schema": "https://www.designtokens.org/schemas/2025.10/format.json", + "$description": "A minimal developer portfolio design system. Typographic precision meets terminal-native clarity — sharp, confident, and built for developers who let their work speak.", + "color": { + "$type": "color", + "primary": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.91, + 0.902, + 0.882 + ], + "hex": "#e8e6e1" + } + }, + "secondary": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.659, + 0.635, + 0.62 + ], + "hex": "#a8a29e" + } + }, + "tertiary": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.604, + 0.204, + 0.071 + ], + "hex": "#9a3412" + } + }, + "surface": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.047, + 0.039, + 0.035 + ], + "hex": "#0c0a09" + } + }, + "surface-dim": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.031, + 0.027, + 0.02 + ], + "hex": "#080705" + } + }, + "surface-bright": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.11, + 0.098, + 0.09 + ], + "hex": "#1c1917" + } + }, + "surface-container-lowest": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.02, + 0.016, + 0.012 + ], + "hex": "#050403" + } + }, + "surface-container-low": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.067, + 0.063, + 0.063 + ], + "hex": "#111010" + } + }, + "surface-container": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.11, + 0.098, + 0.09 + ], + "hex": "#1c1917" + } + }, + "surface-container-high": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.161, + 0.145, + 0.141 + ], + "hex": "#292524" + } + }, + "surface-container-highest": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.227, + 0.212, + 0.2 + ], + "hex": "#3a3633" + } + }, + "on-surface": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.91, + 0.902, + 0.882 + ], + "hex": "#e8e6e1" + } + }, + "on-surface-variant": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.659, + 0.635, + 0.62 + ], + "hex": "#a8a29e" + } + }, + "outline": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.341, + 0.325, + 0.306 + ], + "hex": "#57534e" + } + }, + "outline-variant": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.161, + 0.145, + 0.141 + ], + "hex": "#292524" + } + }, + "background": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.047, + 0.039, + 0.035 + ], + "hex": "#0c0a09" + } + }, + "on-background": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.91, + 0.902, + 0.882 + ], + "hex": "#e8e6e1" + } + }, + "primary-container": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.11, + 0.098, + 0.09 + ], + "hex": "#1c1917" + } + }, + "on-primary-container": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.91, + 0.902, + 0.882 + ], + "hex": "#e8e6e1" + } + }, + "tertiary-container": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.263, + 0.078, + 0.027 + ], + "hex": "#431407" + } + }, + "on-tertiary-container": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.992, + 0.729, + 0.455 + ], + "hex": "#fdba74" + } + }, + "error": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.973, + 0.443, + 0.443 + ], + "hex": "#f87171" + } + }, + "on-error": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.271, + 0.039, + 0.039 + ], + "hex": "#450a0a" + } + }, + "error-container": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.498, + 0.114, + 0.114 + ], + "hex": "#7f1d1d" + } + }, + "on-error-container": { + "$value": { + "colorSpace": "srgb", + "components": [ + 0.996, + 0.792, + 0.792 + ], + "hex": "#fecaca" + } + } + }, + "spacing": { + "$type": "dimension", + "xs": { + "$value": { + "value": 4, + "unit": "px" + } + }, + "sm": { + "$value": { + "value": 8, + "unit": "px" + } + }, + "md": { + "$value": { + "value": 16, + "unit": "px" + } + }, + "lg": { + "$value": { + "value": 24, + "unit": "px" + } + }, + "xl": { + "$value": { + "value": 40, + "unit": "px" + } + }, + "section": { + "$value": { + "value": 80, + "unit": "px" + } + }, + "max-width": { + "$value": { + "value": 1200, + "unit": "px" + } + } + }, + "rounded": { + "$type": "dimension", + "sm": { + "$value": { + "value": 2, + "unit": "px" + } + }, + "md": { + "$value": { + "value": 4, + "unit": "px" + } + }, + "lg": { + "$value": { + "value": 6, + "unit": "px" + } + }, + "xl": { + "$value": { + "value": 8, + "unit": "px" + } + }, + "full": { + "$value": { + "value": 9999, + "unit": "px" + } + } + }, + "typography": { + "display-lg": { + "$type": "typography", + "$value": { + "fontFamily": "Geist", + "fontSize": { + "value": 72, + "unit": "px" + }, + "fontWeight": 700, + "letterSpacing": { + "value": -0.03, + "unit": "em" + }, + "lineHeight": 80 + } + }, + "headline-lg": { + "$type": "typography", + "$value": { + "fontFamily": "Geist", + "fontSize": { + "value": 36, + "unit": "px" + }, + "fontWeight": 600, + "letterSpacing": { + "value": -0.02, + "unit": "em" + }, + "lineHeight": 44 + } + }, + "headline-md": { + "$type": "typography", + "$value": { + "fontFamily": "Geist", + "fontSize": { + "value": 24, + "unit": "px" + }, + "fontWeight": 500, + "letterSpacing": { + "value": -0.01, + "unit": "em" + }, + "lineHeight": 32 + } + }, + "body-lg": { + "$type": "typography", + "$value": { + "fontFamily": "Geist", + "fontSize": { + "value": 18, + "unit": "px" + }, + "fontWeight": 400, + "lineHeight": 28 + } + }, + "body-md": { + "$type": "typography", + "$value": { + "fontFamily": "Geist", + "fontSize": { + "value": 16, + "unit": "px" + }, + "fontWeight": 400, + "lineHeight": 26 + } + }, + "label-mono": { + "$type": "typography", + "$value": { + "fontFamily": "Geist Mono", + "fontSize": { + "value": 13, + "unit": "px" + }, + "fontWeight": 400, + "letterSpacing": { + "value": 0.02, + "unit": "em" + }, + "lineHeight": 20 + } + }, + "label-sm": { + "$type": "typography", + "$value": { + "fontFamily": "Geist Mono", + "fontSize": { + "value": 11, + "unit": "px" + }, + "fontWeight": 500, + "letterSpacing": { + "value": 0.08, + "unit": "em" + }, + "lineHeight": 16 + } + } + } +} \ No newline at end of file diff --git a/examples/ink-and-code/tailwind.config.js b/examples/ink-and-code/tailwind.config.js new file mode 100644 index 00000000..928528d0 --- /dev/null +++ b/examples/ink-and-code/tailwind.config.js @@ -0,0 +1,83 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @type {import('tailwindcss').Config} */ +module.exports = { + darkMode: "class", + theme: { + extend: { + colors: { + "primary": "#e8e6e1", + "secondary": "#a8a29e", + "tertiary": "#9a3412", + "surface": "#0c0a09", + "surface-dim": "#080705", + "surface-bright": "#1c1917", + "surface-container-lowest": "#050403", + "surface-container-low": "#111010", + "surface-container": "#1c1917", + "surface-container-high": "#292524", + "surface-container-highest": "#3a3633", + "on-surface": "#e8e6e1", + "on-surface-variant": "#a8a29e", + "outline": "#57534e", + "outline-variant": "#292524", + "background": "#0c0a09", + "on-background": "#e8e6e1", + "primary-container": "#1c1917", + "on-primary-container": "#e8e6e1", + "tertiary-container": "#431407", + "on-tertiary-container": "#fdba74", + "error": "#f87171", + "on-error": "#450a0a", + "error-container": "#7f1d1d", + "on-error-container": "#fecaca", + }, + fontFamily: { + "display-lg": "['Geist']", + "headline-lg": "['Geist']", + "headline-md": "['Geist']", + "body-lg": "['Geist']", + "body-md": "['Geist']", + "label-mono": "['Geist Mono']", + "label-sm": "['Geist Mono']", + }, + fontSize: { + "display-lg": "['72px', {'lineHeight': '80px', 'letterSpacing': '-0.03em', 'fontWeight': '700'}]", + "headline-lg": "['36px', {'lineHeight': '44px', 'letterSpacing': '-0.02em', 'fontWeight': '600'}]", + "headline-md": "['24px', {'lineHeight': '32px', 'letterSpacing': '-0.01em', 'fontWeight': '500'}]", + "body-lg": "['18px', {'lineHeight': '28px', 'fontWeight': '400'}]", + "body-md": "['16px', {'lineHeight': '26px', 'fontWeight': '400'}]", + "label-mono": "['13px', {'lineHeight': '20px', 'letterSpacing': '0.02em', 'fontWeight': '400'}]", + "label-sm": "['11px', {'lineHeight': '16px', 'letterSpacing': '0.08em', 'fontWeight': '500'}]", + }, + borderRadius: { + "sm": "2px", + "md": "4px", + "lg": "6px", + "xl": "8px", + "full": "9999px", + }, + spacing: { + "xs": "4px", + "sm": "8px", + "md": "16px", + "lg": "24px", + "xl": "40px", + "section": "80px", + "max-width": "1200px", + }, + }, + }, +}; \ No newline at end of file