Lucas Teixeira

The Working Drawing

Design system for lucastexr-site

DESIGN.md, refreshed 7 October 2026

Light mode only

Overview

The site reads like an engineer's sheet that a designer drew. Black ink on near white paper, hairline wires, numbered stages, and a single orange mark that shows what is moving or where you are. Nothing is decorated. The page earns attention through scale: an 80px headline beside an 11px uppercase label, a full width case study cover beside a quiet facts column. That jump in size is the brutalism here, not boxes, rules or heavy borders.

The drawing metaphor is literal on the home page. The process diagram is an animated system figure in the same ink and the same orange, built from the IEEE 1016 design description model and the SyRS data flow shape. The candidate home at /next turns the same figure into a small isometric model in three.js: same topology, same 12 second signal, same tokens. Everything else on the site borrows its restraint: monochrome neutrals with zero chroma, flat surfaces, pill actions, and photographs as the only full color on the page.

Density is low and the rhythm is generous. One shell width aligns every section. Light mode only: there is no dark theme and no dark: variant anywhere in the shipped components.

  • Ink on paper. Every neutral has zero chroma.
  • One warm accent, Signal Orange, at 5% of any page at most.
  • Inter only, nine type tokens, emphasis by size jump.
  • Flat: every shadow token resolves to none, no blur, no gradients.
  • Pill actions and tags, softly rounded image tiles, hairline dividers.
  • Headings stand alone. No label ever sits above a heading.
  • Motion is small and functional, and the diagram stills completely under reduced motion.
  • Work is the only full color. Case study covers and galleries carry the page; the frame around them stays grey.

Colors

7 tokens, oklch

A greyscale drafting palette with one fired orange held in reserve.

Signal Orange

primary · signal

oklch(0.646 0.184 45)

(--chart-1, exposed as --color-signal): the only warm color on the site. It marks three things and nothing else: what moves in the process diagram (the travelling dot, the drawn segment, the lit stage), keyboard focus on every page (2px outline, 3px offset), and position (the active nav underline and the case study Next arrow). It sits in a chart slot so a tweakcn theme paste can never leave the diagram colorless.

Drawing Ink

neutral · ink

oklch(0.1908 0 0)

(--foreground, also --primary): headlines, body text, diagram wires, primary pill fill, text selection background.

Drafting Paper

neutral · paper

oklch(0.9911 0 0)

(--background): the page, input fields, and the knockout discs inside the diagram.

Vellum

neutral · vellum

oklch(0.9601 0 0)

(--secondary and --muted): the contact form panel, empty image tiles, and the hover fill of outline pills.

Graphite

neutral · graphite

oklch(0.4386 0 0)

(--muted-foreground): taglines, secondary copy, FAQ answers, inactive nav labels, footer links. Roughly 7.5:1 on Drafting Paper.

Hairline

neutral · hairline

oklch(0.9189 0 0)

(--border): section dividers, the footer rule, FAQ row rules, outline pill borders.

Field Stroke

neutral · field-stroke

oklch(0.62 0 0)

(--input): input and textarea borders only. Set at 0.62 lightness so a field edge clears 3:1 on both Drafting Paper and Vellum.

The One Signal Rule

Signal Orange covers 5% of any page at most. It marks motion, focus or position. It never fills a button, never colors body text, never decorates.

The Zero Chroma Rule

Every neutral is pure grey (chroma 0). Warmth comes from photographs and the signal, never from tinted paper or tinted text.

The One Block Rule

Colors change only inside the TWEAKCN BLOCK markers in src/styles/global.css. No component hardcodes a color.

Typography

Inter, nine sizes

Display Font: Inter Variable (with ui-sans-serif, system-ui, sans-serif)

Body Font: Inter Variable (same stack)

Label Font: Inter Variable, uppercase and tracked

Character: One neutral grotesque doing every job, so hierarchy has to come from size, tracking and case. Display sizes run tight (negative tracking down to -0.035em, line height under 1); the tagline runs wide (0.14em) and small.

Class merging. cn in src/lib/utils.ts declares the nine tokens as font sizes. Without that, the merge reads text-h6 as a color and drops it beside text-primary-foreground.

h1

400 · clamp(2.75rem, 6.5vw, 5rem) · lh 0.94 · ls -0.035em

Director of Design.

page openers, the home hero, case study titles, the mobile menu items, CTA headings, stat values.

h2

400 · clamp(2rem, 4vw, 3.25rem) · lh 0.98 · ls -0.03em

Container Alliance

section headings, the featured work card title, essay rows, photo series names.

h3

500 · clamp(1.5rem, 2.4vw, 2rem) · lh 1.1 · ls -0.02em

Tânia, 50 anos

work card titles, the footer email, case study summaries, h2 inside long form text.

h4

500 · 1.375rem · lh 1.2 · ls -0.015em

How long does a project take?

FAQ questions and blockquotes.

h5

500 · 1.0625rem · lh 1.35 · ls -0.01em

Approach

h3 inside long form text.

h6

500 · 0.9375rem · lh 1.4 · ls 0em

See the work

every pill label, hero collage rows, company names.

body-lg

400 · 1.1875rem · lh 1.6 · ls -0.005em

Lucas Teixeira is Director of Design at Fetchly Labs, leading 14 designers across Brazil and Latin America.

intros, long form case study and essay text (held to max-w-3xl, about 48rem), form field text.

body

400 · 0.9375rem · lh 1.65 · ls 0em

Case studies in product design, discovery, DesignOps and Webflow.

default text, FAQ answers, service lists, case study facts.

tagline

500 · 0.6875rem · lh 1 · ls 0.14em

Brasília

meta rows under a heading, field and fact labels, nav links, badges, figure captions.

The Nine Sizes Rule

Only these nine tokens exist. Each one carries its own size, line height, tracking and weight, so text-h2 is the whole decision. No arbitrary text-[...] sizes, no font-bold.

The Semibold Ceiling Rule

Weights stop at 600, and the shipped tokens use only 400 and 500. font-synthesis-weight: none keeps the browser from faking anything heavier.

The Scale Jump Rule

Emphasis is a jump in size, never a box, a rule or a color. An h1 beside a tagline is the signature contrast.

The Bare Heading Rule

Nothing sits above a heading: no eyebrow, no kicker, no section label. Meta goes below the heading, beside it in a facts column, or into the copy.

Layout

One shell, 86rem

One container governs every section: the shell, centered, 86rem wide at most, with a 1.25rem gutter that grows to 2rem from 768px. Sections stack with 3.5rem of vertical padding, 5rem from 640px; the closing CTA band gets 6rem, then 8rem. The sticky header is 5rem tall, and anchor scrolling leaves the same 5rem of room.

Grids are simple and content led. Work cards run one column, then two from 768px, under a full width 16:9 feature card. Services run one, two, then three columns. Case studies split into a 16rem sticky facts column and a reading column from 1024px. The home hero puts copy beside a three column photo collage that stretches to the copy height from 1024px. Breakpoints are the Tailwind defaults: 640, 768, 1024, 1280px.

The process diagram keeps a 900px minimum width and scrolls sideways inside its own frame on narrow screens, with the scrollbar hidden. That is a known gap: on a phone the right half of the figure is cut off with no cue that it scrolls, and the frame is not keyboard reachable. The 2026-10-07 audit tracks it for /impeccable adapt. The /next model has no such problem: it scales inside a 4:3 box at any width.

Spacing tokens, drawn to scale

  • unit0.25rem
  • gutter1.25rem
  • gutter-md2rem
  • section3.5rem
  • section-sm5rem
  • cta6rem
  • cta-sm8rem
  • nav-height5rem
  • shell-max86rem, the width of every section86rem

Breakpoints

  • 640pxsm
  • 768pxmd
  • 1024pxlg
  • 1280pxxl

The One Shell Rule

Every section uses the shell utility. Nothing sets its own max width or side padding, so every left edge lines up.

Elevation & Depth

Flat

Flat. Every shadow token in the theme resolves to none, and there is no blur or backdrop filter anywhere. Depth comes from tone and content: Vellum panels and tiles sit on Drafting Paper, photographs carry their own depth, and the sticky header separates from content by being opaque paper, not by a shadow.

The Flat Sheet Rule

Surfaces never lift. A state change is a fill swap, an opacity step or a 2px nudge, never a shadow.

Shapes

Three radii

Three radii and nothing else. Actions and badges are full pills (9999px). Image tiles, case study covers and the form panel use a soft 14px corner (rounded-xl, the 10px base radius plus 4px). Input fields and the small photo grid tiles use the 10px base (rounded-lg). Diagram inputs and the output node are pills too, so the figure and the page share one silhouette. Rules are 1px hairlines, drawn with the Separator component or a Hairline border; the only thicker line is the 2px signal underline on the active nav link and the 2px rule beside long form blockquotes.

See the work
Pill · 9999px · anything you press or tag
Tile · 0.875rem · anything you look at
you@company.com
Field · 0.625rem · anything you type into

The Three Radii Rule

Pills for anything you press or tag, 14px for anything you look at, 10px for anything you type into.

Components

10 live samples

Quiet and exact. Flat ink pills, hairline borders, motion only as a small nudge. Nothing competes with the headline.

Primary Pill

button · button-primary

Ink pill for the one main action of a section.

Outline Pill

button · button-outline

Hairline pill for secondary actions; fills with Vellum on hover.

Round Jump

button · button-round

Circle with an arrow that jumps to the process section; fills with ink on hover.

Text Field

input · input

Paper field with a Field Stroke border and a tagline label; border turns ink on focus.

Main Navigation

nav · nav-link

Tagline links; the active page gets a 2px Signal Orange underline.

DesignOpsCRM designSEO migration

Badge

chip · badge

Vellum pill with tagline text for services; no border, so it never reads as a button.

Where is your work history?

On the About page, newest role first.

Do you work with US teams?

Yes, remotely from Brasília.

FAQ Row

custom · label

Native details row between Hairline rules; the plus turns into a cross when open.

0102DiscoveryDomain and flows

Process Stage

custom · signal

Two stages of the signature diagram: ink rings and wires, the active stage lit in Signal Orange.

Systems Scene Poster

custom · signal

The /next hero before WebGL loads, copied from SystemsScene.astro: three input blocks, five stage blocks, one output block, a dashed feedback arc, and the signal in Signal Orange. The three.js model fades in over it on idle.

Specifications

Buttons

  • Source: the shadcn Button in src/components/ui/button.tsx, restyled to the pill system. React blocks use <Button asChild> around an anchor; Astro pages put buttonVariants() on the a or button directly, because asChild cannot wrap Astro children.
  • Shape: full pill (9999px), 3rem tall, 2rem side padding, h6 label.
  • Primary: Drawing Ink fill, Drafting Paper label, optional 16px arrow icon after the label. Used for the main action of a section: "See the work", the CTA, the form submit.
  • Hover / Focus: primary drops to 85% opacity and its arrow nudges 2px right. Focus is the global 2px Signal Orange outline at 3px offset.
  • Outline: transparent with a Hairline border and an ink label; hover fills it with Vellum. Used for secondary actions such as "Get in touch", "All work", "The five steps in detail".
  • Round (variant="round" size="icon"): a 3.5rem circle with a Hairline border and a 20px arrow; hover fills it with ink and turns the arrow paper. Used once, in the home hero, to jump to the process.
  • Focus: the button sets no ring and no outline-none, so the global Signal Orange outline always shows.

Badges

  • Source: the shadcn Badge in src/components/ui/badge.tsx, restyled.
  • Style: a 1.5rem pill, Vellum fill, no border, Graphite tagline text. The fill and the missing border keep it from reading as an outline button.
  • Use: services on work cards and in the case study facts column. Three per card at most.

Separators

The shadcn Separator: a decorative 1px Hairline rule. It opens the footer and sits above the case study Next link.

Cards / Containers

  • Work card: an image tile (Vellum fill under the photo, 14px corner, 4:3 or 16:9 for the feature) over an h3 title (h2 for the feature) with a tagline year at the right and service badges below. No border, no background, no shadow. Hover scales the photo 3% over 500ms ease out and underlines the title.
  • Form panel: Vellum, 14px corner, 2rem padding (2.5rem from 640px). The only filled container on the site.
  • Essay row: a 3:2 image tile beside an h2 title, a Graphite summary and the date below it, same hover as the work card.

Inputs / Fields

  • Style: Drafting Paper fill, 1px Field Stroke border, 10px corner, 3rem tall, body-lg text, Graphite placeholder. A tagline label sits above each field.
  • Focus: the border turns Drawing Ink, plus the global Signal Orange focus outline.
  • Error / Disabled: not designed. The form relies on native required validation.

Navigation

  • Desktop: the monogram at left, tagline links at right with 2rem gaps. Inactive links are Graphite and turn ink on hover. The active link is ink with a 2px Signal Orange underline at 6px offset.
  • Mobile: a 44px "Menu" text button opens a full screen paper panel listing each page at h1 size, one per line. The active page sits at 40% opacity. Escape closes it and returns focus to the button.
  • Footer: the email address at h3 with an underline, tagline column headers, Graphite links, then the full width wordmark.

FAQ

Native details rows between Hairline rules. The question is h4 with a 20px plus icon at 1.5 stroke that turns 45 degrees into a cross when open. The answer is Graphite body text, 42rem wide at most. It opens without JavaScript.

Stats

A value at h1 over a tagline label, built as dt/dd pairs. One column, then two from 640px.

Process Diagram (signature)

An inline SVG system figure: three pill inputs wire into five numbered ring stages, ending in a pill output, with a dashed feedback loop back to the start. Wires are 1px ink. One 12 second linear loop sends a Signal Orange dot along the spine. Each stage lights orange and pulses as the dot arrives, and a return dot rides the loop. No JavaScript. Under reduced motion every segment shows drawn and nothing moves. A background variant drops the labels and sits at 50% opacity behind copy.

Systems Scene (/next hero)

  • Source: src/components/three/SystemsScene.astro (poster and loader) and src/components/three/systems-scene.ts (the scene). No framework runtime.
  • Model: three small input blocks, five stage blocks, one larger output block, a dashed arc from review back to discovery. Orthographic camera at a fixed isometric angle. Flat MeshLambertMaterial faces with ink edge lines; one ambient and one directional light. No textures, blur or gradient fills.
  • Color: every color is read from the tokens at mount (--foreground, --secondary, --muted-foreground, --chart-1), so a theme paste reaches the scene.
  • Loading: the poster is an inline SVG of the same figure, drawn before any script runs. A plain script waits for requestIdleCallback (2s timeout, setTimeout fallback), then imports three.js and the scene as their own chunk. The poster fades out over 700ms once the canvas has drawn, and stays if WebGL is missing.
  • Motion: the signal travels the line on the 12 second loop of the SVG diagram, and each stage scales up as it passes. The camera sways slowly. Pointer drag turns the model within limits (yaw ±1.2, pitch ±0.3 radians) and eases back on release. The loop runs only while the scene is on screen (IntersectionObserver), and the pixel ratio is capped at 2.
  • Reduced motion: one still pose with the signal parked mid line. No loop. Drag still turns it and snaps back on release.
  • Accessibility: the host is role="img" with a label that describes the figure; the poster and canvas are hidden from assistive tech.

Images

  • Source: src/components/Img.astro for Astro pages and src/components/Image.tsx for React blocks, both built on sized and imgProps in src/lib/img.ts.
  • Pipeline: files live in /public/images so the CMS can write to them. In production every URL goes through the Netlify Image CDN (/.netlify/images?url=...&w=...&q=72) with a srcset of 480, 768, 1080, 1440 and 1920px and a sizes hint. There is no fm parameter: the CDN picks AVIF or WebP from the Accept header. In dev the original file is served.
  • Netlify only: on any other host the CDN path 404s. Moving hosts means swapping sized for that host's resizer, in one place.
  • Priority by position: whatever is in the first viewport loads eager with fetchpriority="high": the first home collage tile, the first two cards on /work, the case study cover, the first photograph. Everything else is lazy with decoding="async". A component never decides this for itself; the page passes it.
  • No layout shift: every image gets real width and height or sits in a fixed aspect box.
  • Case study assets: covers are 2400 by 1600 with the subject centered, because cards crop them to 4:3 and the feature card to 16:9. Gallery images keep their own ratio, and each image's alt doubles as its figure caption in tagline style.

Motion

  • Hover: an 85% opacity step on primary pills, a Vellum fill on outline pills, a 2px arrow nudge, a 3% photo zoom over 500ms ease out.
  • Loops: only the process diagram (12 seconds, linear, CSS only) and the /next model on the same clock. Nothing else animates on its own.
  • Reduced motion: every loop has a designed still state. The diagram shows every segment drawn with the dot at rest; the model holds one pose.

Links

Inline links in long form text and contact details are ink with a 40% ink underline at 4px offset; hover darkens the underline to full ink.

The Poster First Rule

Anything heavy draws a real HTML or SVG poster first and loads its script on idle. The site ships no framework runtime.

The Position Priority Rule

The page, not the component, decides image priority. Only the first viewport loads eager with fetchpriority="high".

Do's and Don'ts

Do

  • Do wrap every section in the shell utility (86rem max, 1.25rem gutter, 2rem from 768px).
  • Do use the nine type tokens and nothing else. Pick text-h2, not a size plus a weight plus a tracking.
  • Do build every action from Button or buttonVariants: a 3rem pill with an h6 label; ink fill for the primary, Hairline outline for the rest.
  • Do reserve Signal Orange for motion, focus and position, and keep it under 5% of the page.
  • Do put photos in Vellum tiles with a 14px corner, and pass real width and height to Img.
  • Do keep hover small: an 85% opacity step, a Vellum fill, a 2px arrow nudge, or a 3% photo zoom over 500ms.
  • Do give every animation a still state under prefers-reduced-motion.
  • Do change colors, radius and fonts only inside the TWEAKCN BLOCK in src/styles/global.css.
  • Do set image priority from the page: eager and high priority for the first viewport only.
  • Do keep heavy scripts off the critical path. Draw a real HTML or SVG poster first, then load the script on idle.
  • Do crop case study covers to 2400 by 1600 with the subject centered, and write each gallery alt as a caption.

Don't

  • Don't add shadows, blur, backdrop filters or gradient fills. Every shadow token is none on purpose.
  • Don't add a dark theme or any dark: variant. The site is light mode only.
  • Don't introduce a second accent, tinted neutrals, or the Fetchly palette and fonts (Marjorie, Malibu cyan, Spring Green). This is the personal Lucas Teixeira brand. No neon green.
  • Don't use boxes, heavy rules or colored borders for emphasis. Use a size jump.
  • Don't set a weight above 600, use font-bold, or use any typeface other than Inter.
  • Don't hand roll a pill with raw classes, and don't add outline-none or a ring to a control.
  • Don't put an eyebrow, kicker or section label above a heading.
  • Don't fill a button or color body text with Signal Orange.
  • Don't add a framework island for something a plain script can do. The site ships no React runtime.
  • Don't force a format (fm) on CDN image URLs, or mark an image eager inside a shared component.