I design products you feel before you understand them. This is how I design: what I decide, why, and how it looks.

design language v2.0 · October 2026 modes light + dark for AI llms.txt · brand.md
verdantExplore a city on a map that blurs at the edges.
tallySend money from a glass sheet that floats over your balance.
solaceRest between sets with a timer you can read from the bench.
examples

Same language, any product. Fictional apps, real rules.

Each screen is built at real iPhone size with the tokens and patterns on this page, then scaled into the frame. Names and data are made up; the decisions aren't.

closet · item detected

Point the camera, and the item lifts out of the room.

floating glasslayered depthcontact shadowone sticker

atlas · trip planner

A trip planner that answers in words that arrive, with one accent where the money is.

words arriveshimmerprogressive blurone accent

boarding · live activity

Your flight, live on the lock screen, in the island and on glass.

islandlive activitynumber heroatmosphere

pulse · onboarding

First launch: one object, two lines, one button.

full atmospherebrand objecttwo-tone headline
philosophy

People don't read interfaces. They feel them.

Seven beliefs that guide everything I design. When I'm torn between two options, I come back here.

The detail is the product

Two apps with the same features don't feel the same. The difference lives in 200 milliseconds, in a 6-pixel blur, in a button that shrinks when you touch it.

That's where I spend most of my time.

Quiet frame, product in front

Neutral backgrounds, restrained type and almost no color around the screen.

The quieter the frame, the louder the product.

Depth with light, not lines

I separate layers with blur, transparency and soft shadows. Borders and boxes divide; blur brings order without cutting the image.

A layered interface makes sense without explaining it.

Motion explains

I animate to show where something comes from and where it goes. The sheet rises from the bottom because it lives at the bottom; the check grows out of the button that asked for it.

If an animation doesn't answer a question, I cut it.

One color per story

My brand lives in black, white and greys. Each project picks a single color and keeps it across every piece.

One color held steady gets remembered. Five colors get forgotten.

Light and dark from day one

I design both modes in parallel. I don't invert colors: each mode gets its own decisions for shadow, glass and contrast.

The mode belongs to whoever uses the app. It isn't mine.

Words are design too

Short copy, active voice, zero jargon. Names go lowercase and flows get an arrow.

If a button needs explaining, the button is wrong.

decisions

Every decision has a reason. If I can't explain it, it's out.

What I always do, why, and the concrete rule that comes out of it.

Buttons are always pills

They read as tappable right away, sit comfortably under the thumb and echo the curve of the phone.

radius 999 · height 40 or 52

Small two-tone headlines

Confidence doesn't need size. Grey builds the hierarchy and leaves large sizes free for numbers.

line 1 fg · line 2 fg-2 · same weight

Huge numbers

Time, money and scores are what people came to see. They have to read at a glance.

600 · tabular · tracking −4.5%

One sans

Inter Display has optical sizing and tabular figures, and it looks like SF Pro: the design and the iPhone speak the same way.

Inter Display · Geist Mono only in labels

Pure black in dark

On OLED, black disappears, the device melts into the page and glows gain contrast.

bg #000 in dark

Light grey, not white, in light

Pure white is tiring and keeps cards from separating. On light grey, a white card floats on its own.

bg #F4F4F4 · cards #FFFFFF

Blur instead of borders

Glass lets the context show through and separates layers without cutting the image behind.

blur 20 · saturate 180% · 1 px light on top

Floating, concentric sheets

Set off the edge, it reads as a layer. With a concentric radius, it looks like part of the hardware.

inset 12 · radius = outer − inset

Ease-out by default

It responds to the touch right away and slows down like a real object. Nothing starts slow.

cubic-bezier(.22, 1, .36, 1)

Close faster than open

When someone closes something, they already decided. I don't make them wait.

open 420 ms · close 280 ms

One atmosphere per project

The color identifies the project. It isn't decoration. Repeated across every piece, it becomes memory.

pick 1 of 4 · never mix

Front-facing mockups, no hands

Perspective and hands distort and shrink the screen, and the screen is what matters.

device ≤ 60% of shot height
light + dark

Light and dark on equal footing. Same decisions, different light.

Both modes use the same tokens, with values chosen for each one. Try the switch up top: the whole page changes except this comparison.

light mode

Transfer sent.$1,240 to Studio account.

DoneShare receipt
CompletedNov 12
● Sent · $1,240
dark mode

Transfer sent.$1,240 to Studio account.

DoneShare receipt
CompletedNov 12
● Sent · $1,240
what changes between modes
aspectlightdark
background#F4F4F4#000000
cardsWhite, with a soft, long shadow.#111111 with a 1 px thread of light on top.
separationShadow.Surface step and hairline. Almost no shadows: on black they look dirty.
glassWhite at 68% + blur 20.White at 12% + blur 20.
primary buttonBlack with light text.White with black text.
secondary text#6B6B6B#8F8F8F
atmospheresPastel, with a saturated glow.Deep, with a bright glow.
grain5%12%
device stage#E8E8E8#EDEDED: the stage stays light in dark mode.
how I design both modes
always
  • I design both modes in parallel, in the same file and the same week.
  • Every token has a value chosen per mode. Nothing gets inverted automatically.
  • In light I separate with shadow; in dark, with surface and light.
  • I check AA contrast in both before I call anything done.
  • By default I follow the system and let people choose: system, light or dark.
never
  • Mid grey as a dark background "so it's not so black".
  • Large dark shadows in dark mode.
  • One mode finished and the other "later".
  • The same glass in both modes: light needs more opacity.
  • Icons or illustrations that only work on one background.
system

Black, white and twelve greys. Color is earned project by project.

The base scale is the same in both modes; what changes is which tone plays each role. Tap a tone to copy its hex.

roles by mode
tokenlightdarkuse
--bg#F4F4F4#000000Page background.
--surface-1#FFFFFF#111111Cards.
--surface-2#F0F0F0#1F1F1FRows, inputs, elements inside cards.
--sheet-bg#FFFFFF#1F1F1FOpaque sheets.
--fg#0A0A0A#FFFFFFMain text and primary button.
--fg-2#6B6B6B#8F8F8FSecond headline line, descriptions.
--fg-3#A1A1A1#5C5C5CHints, muted labels, starting point for reveals.
--btn-2#E6E6E6#1F1F1FSecondary button and chips.
--glasswhite 68%white 12%Blurred glass surfaces.
atmospheres · one per project

Radial gradient from the top, glow in the center and grain. Each one has a light and a dark version: switch the theme and watch them adapt.

forest

Sport, outdoors, focus

ember
0:30

Time, energy, rest

tide
● Sent

Money, trust, chat

rouge

Social, location, alerts

typography

Inter Display for everything, at 600 for titles and 400 to 500 for text. Geist Mono only in small labels, uppercase and grey.

display · 56 · 600
tracking −3%
Design that ships
h2 · 28 · 600
tracking −1.5%
Onboarding → first payment
body · 16 · 400
color fg-2
I design mobile products end to end, from the first flow to the last micro-interaction, and hand off files engineers can build from.
label · mono 11
caps · +6%
sitemap · social · contact
numbers · 600
tabular
$1,240
shape and space

The more something floats, the rounder it gets. When one surface sits inside another, the inner radius is the outer radius minus the margin.

r-xs · 8
stage
r-md · 16
thumbs, inputs
r-lg · 24
cards
r-xl · 32
sheets
r-pill
buttons, chips
concentric
36 − 12 = 24
s-1 · 4px
s-2 · 8px
s-3 · 12px
s-4 · 16px
s-5 · 24px
s-6 · 32px
s-7 · 48px
s-8 · 64px
s-9 · 96px
s-10 · 160px
micro

What nobody sees, everybody feels. Micro-blurs and micro-animations.

This is the layer I care about most. None of these details stands out on its own; together they're the difference between a correct screen and one that feels expensive. General rule: blur never goes past 10 px outside glass, and no micro-animation lasts longer than 420 ms.

Main account$25,482
Savings$3,120
Travel fund$880
Rent$214
Groceries$1,906
Emergency fund$742
Joint account$5,310
Taxes$96

Progressive blur

Edges of lists, navigation bars and tab bars. Scroll the list.

Content fades out gradually instead of cutting off hard, like in iOS.

layers
4 · blur 1, 2, 4, 8 px
masks
100%, 75%, 50%, 25% of the height
height
72 px + background color fade

Edge blur

Maps, photos and camera backgrounds behind the UI.

The center stays sharp and the edges fall away, like depth of field: the eye goes straight to what matters.

blur
10 px · saturate 110%
mask
radial · sharp up to 40%, full blur at 100%
Item detectedAir Max 1 · added to your closet

Floating glass

Sheets and cards over camera, photo or color.

Set off the edge, it reads as a layer; with a concentric radius, it looks like part of the hardware.

surface
blur 32 px · saturate 160% · 55% tint
edge
1 px inner light on top + hairline
position
inset 10–12 px · radius = outer − inset
$12,480
Studio account−$1,240
Mara Diaz+$560
Confirm transfer

$1,240 to Studio account

Receding background

When a sheet opens, whatever is behind it blurs and moves back a little.

It adds depth without blacking everything out, and the focus stays on the task.

background
blur 0 → 10 px · scale 1 → 0.96 · opacity 1 → 0.6
timing
420 ms ease-out on open · 280 ms on close

Blur swap

Buttons and labels that change state: send, sending, sent.

The old state blurs out while the new one comes into focus. The eye reads continuity instead of a jump.

out
opacity → 0 · blur → 6 px · scale → 0.96
in
the reverse · 240 ms ease-out, at the same time

I turned your three sketches into one flow you can actually test.

Arriving text

AI replies, confirmations and new messages.

Each word comes into focus as it arrives. It feels written live, with no blinking cursor.

word
opacity 0.15 → 1 · blur 4 → 0 · y 4 → 0
timing
420 ms ease-out · 30 ms between words
Thinking about your portfolio~4 s

Thinking text

Loading states with text: "thinking", "searching", "processing".

A shine moving across the text says "I'm working" with no spinner or bar.

gradient
fg-3 → fg → fg-3 · 300% width
timing
2.2 s linear · loop (the only loop allowed in UI)
NEW

Layered depth

Product screens, detected objects and brand heroes.

Big blurred text behind, a sharp object in front, a contact shadow below: three planes that read as real space.

back text
700 · opacity 14% · blur 2.5 px
shadow
70% ellipse · blur 4 px · 35% black
sticker
only one per screen · rotated −4°

Growing pill

Live activities, calls, timers, players. Tap the pill.

The content grows from where it already was, without opening another screen.

shape
width, height and radius together · 420 ms ease-in-out
content
blur swap · 240 ms · 120 ms delay

Morphing icon

Add ↔ close, copy → copied. Tap both.

The icon changes in place and confirms the action without a toast.

+ → ×
rotate 45° · 240 ms spring
copy
blur swap · resets after 1.4 s

Elastic switch

Toggles. Hold it down before you let go.

The knob stretches under your finger like something soft. It's a detail you feel before you see it.

pressed
width 28 → 36 px
travel
240 ms spring · color 240 ms
Live · 1,204 watching Pending approval Recording

Live dot

States happening right now: live, pending, recording.

A soft pulse says "this is moving" without asking for attention.

ring
scale 1 → 2.6 · opacity 0.55 → 0
timing
1.6 s ease-out · loops only while the state lasts
motion

Fast in, soft landing. Three curves, six durations, eight patterns.

The rules of motion at screen scale. Everything comes from the tokens in tokens.css.

Respond instantly

Every touch gets a visual response in under 100 ms. If the action takes time, the button changes state before the result arrives.

Enter fast, slow down soft

Almost everything uses ease-out. What opens takes 420 ms; what closes, 280 ms.

Nothing appears out of nowhere

Elements come in from where they start: the sheet from the bottom, the toast from the edge, the check from the button.

One thing at a time

Things that enter together get staggered: 120 ms between lines, 50 ms between items (6 max), 30 ms between words.

Text doesn't dance

Text reveals and then stays still. It never starts invisible, never bounces and never moves while someone reads it.

curves
ease-out · defaultcubic-bezier(.22, 1, .36, 1)

Entrances, responses, reveals.

ease-in-out · travelcubic-bezier(.65, 0, .35, 1)

Something crossing the screen, morphs, closing.

spring · confirmcubic-bezier(.34, 1.56, .64, 1)

Small things only: check, chip, bounce on release.

durations
tokenmsused for
--dur-1120Press, hover, label fades.
--dur-2240Chips, toggles, segmented, color, blur swaps, toast exit.
--dur-exit280Closing sheets, modals and screens.
--dur-3420Opening sheets, card and toast entrances, morphs.
--dur-count600Rolling numbers.
--dur-4800Headline reveals and the hero entrance.
catalog · tap each demo

Press

Everything tappable. On mobile it comes with a light haptic.

on press
scale 1 → 0.97 · 120 ms ease-out
on release
0.97 → 1 · 240 ms spring
haptic
impact light

Roll a number

Balances, amounts, scores and timers when they change.

digit
vertical wheel + 1.5 px blur while it moves
timing
600 ms ease-out · 40 ms between digits
font
always tabular-nums

Change selection

Segmented controls, tabs and filters. The indicator travels instead of jumping.

indicator
translateX · 240 ms ease-in-out
text
color · 240 ms ease-out
haptic
selection

Confirm

Payments, transfers and any action with a result. The button turns into the answer.

1 · label
opacity → 0 + blur 4 · 120 ms
2 · shape
→ 52 px circle · 420 ms ease-in-out
3 · check
scale 0.6 → 1 + stroke · 240 ms spring · delay 420
haptic
notification success
Main account$25,482
Savings$3,120
Travel fund$880
Rent$214

List entrance

New content that arrives after an action.

item
opacity 0 → 1 · y 12 → 0 · blur 2 → 0
timing
420 ms ease-out · 50 ms between items, 6 max
Saved to drafts

Notify

Confirmations with no decision. If there's a decision to make, it goes in a sheet.

in
y 16 → 0 · blur 4 → 0 · 420 ms ease-out
stays
1600 ms
out
240 ms ease-in-out
Accounts
$12,480

Studio account · updated now

Change screens

Forward and back navigation. Tap an account.

new
x 100% → 0 · 420 ms ease-out
previous
x 0 → −30% · brightness 0.8
back
reverse · 280 ms ease-in-out
The new theme reveals in a circle from the point you tapped.

Change theme

Going from light to dark and back.

reveal
clip-path circle from the tap · 520 ms ease-out
fallback
color crossfade · 420 ms
screen transitions
transitionwhat movesmscurve
pushNew x 100% → 0. Previous x 0 → −30% and dims to 80%.420ease-out
backThe reverse. With an edge gesture, it follows the finger.280ease-in-out
modalSheet from the bottom. What's behind recedes: blur 10, scale 0.96.420ease-out
tabCrossfade with a 4 px blur, no movement.240ease-out
shared elementCard → full screen: position, size and radius interpolate together.420ease-in-out
what animates and what doesn't
yes
  • The response to every touch.
  • State changes: loading, sent, error.
  • New content that arrives after an action.
  • Transitions between screens and sheets.
  • Numbers that change value.
no
  • Text while it's being read.
  • Parallax or scroll that hijacks the page.
  • Infinite loops in UI, except loading and live states.
  • Bounces on large elements.
  • Load animations nobody asked for.
reduced motion

With prefers-reduced-motion or "Reduce Motion" on iOS: no movement, no scale and no blur. State changes become a 120 ms crossfade, numbers show the final value and loops stop. Haptics stay.

code
/* CSS · with tokens.css */
.sheet {
  transform: translateY(100%);
  transition: transform var(--dur-exit)
              var(--ease-in-out);
}
.sheet.open {
  transform: none;
  transition-duration: var(--dur-3);
  transition-timing-function: var(--ease-out);
}
.behind.dim {
  filter: blur(var(--blur-behind));
  transform: scale(0.96);
}
// React Native · Reanimated + expo-blur
export const ease = {
  out: Easing.bezier(0.22, 1, 0.36, 1),
  inOut: Easing.bezier(0.65, 0, 0.35, 1),
};
export const dur = { press: 120, quick: 240,
  exit: 280, base: 420, count: 600, reveal: 800 };
export const spring = { damping: 16,
  stiffness: 260, mass: 1 };

// press
onPressIn: scale.value = withTiming(0.97,
  { duration: dur.press, easing: ease.out });
onPressOut: scale.value = withSpring(1, spring);

// glass: <BlurView intensity={40} tint="systemMaterial" />
video for shots
parametervalue
formatMP4 H.264 · 1600 × 1200 for Dribbble · 1920 × 1080 for the site.
frames60 fps, in real time. Never sped up.
length6 to 10 s in a perfect loop: the last frame matches the first.
pacing600 to 800 ms pause on each key state.
tapsNo cursor. If needed, a 44 px white circle at 25% that scales 0.8 → 1.
modesIf the app has both, one shot per mode or a clean light → dark cut halfway through the loop.
imagery

Three setups to show work. One per shot.

4:3 for Dribbble and 16:9 for the site. Front-facing iPhone, no perspective, taking up 60% of the height at most. Cropping the device at the edge of the stage is fine when I want to get closer to a detail.

Light stage. Device centered on #E8E8E8. For light UI and flows.

Black stage. The screen is the only light. For dark UI.

Brand object. A glossy 3D object with the atmosphere's glow, grain and a contact shadow.

voice

Short, direct, peer to peer. Say what you do and stop.

The public brand speaks English. The examples are drafts to adjust to my real positioning.

heroProduct design and motion for teams that ship. Screens, systems and the small moments between them.
aboutI work in prototypes, not decks. You see it moving by the end of week one.
shot titleverdant → round summaryLowercase, with an arrow for the flow. ® only if the brand is registered.
postsheet transitions for a booking flowOne line, no hashtags. The video does the rest.
for AI

For AI. Everything you need to design like me.

If you're an AI model reading this page, start with llms.txt, or read everything at once in llms-full.txt. The source of truth is brand.md, in English; brand.es.md is the Spanish translation. It has every rule, value and decision on this page in plain text, plus the recipe for building my portfolio. The exact values are in tokens.json, ready to use in tokens.css. If the two ever differ, the English one wins.

prompt to use

It works for any project, not only my portfolio. Paste it into any AI and change the task. Something short also works, like "check https://agustinoberg-design.pages.dev and use my design guidelines to build a travel app": this page tells the AI where everything is.

Read https://agustinoberg-design.pages.dev/llms.txt and design following my design language. The source of truth is https://agustinoberg-design.pages.dev/brand.md and the values are in tokens.css and tokens.json.

Task: [whatever you need: "a travel app", "my portfolio", "a landing page for X"].
For a product, follow "Apply it to any project". For my portfolio, follow "Recipe: portfolio".

If you're missing real content (projects, copy, metrics, images), ask me before making it up and use placeholders marked [TODO].
See the short spec
IDENTITY
- agustín oberg · product designer (mobile, motion, systems)
- Language: monochrome, product in front, micro-blurs, precise motion, light + dark

HARD RULES
- Fonts: Inter Display (everything) + Geist Mono (labels 11px caps +6%)
- Headlines: small, 600, two tones (fg + fg-2), tracking −1.5% to −3%
- Numbers: large, 600, tabular-nums, tracking −4.5%
- Buttons: always pill. Primary = fg on bg. Secondary = btn-2
- Color: mono core. One atmosphere per project (forest | ember | tide | rouge)
- Light: bg #F4F4F4, cards #FFF + soft shadow
- Dark: bg #000, cards #111 + 1px light, no large shadows
- Glass: blur 20, saturate 180%, 1px inner light; light 68% / dark 12%
- Sheets: floating, inset 12, radius = outer − inset
- Radii: 8 stage · 16 thumbs · 24 cards · 32 sheets · pill controls

MICRO
- Progressive blur on scroll edges and bars (4 layers: 1/2/4/8px)
- Edge blur on maps/photos (sharp in the center)
- Receding background when a sheet opens: blur 10, scale .96, opacity .6
- Blur state change: 6px, 240ms
- Arriving words: blur 4 → 0, 30ms between words
- Shimmer for "thinking"; live dot with a pulse for ongoing states
- Depth: big blurred text behind, sharp object, contact shadow

MOTION
- ease-out (.22,1,.36,1) default · ease-in-out (.65,0,.35,1) travel · spring (.34,1.56,.64,1) small things only
- 120 press · 240 chips/blur · 280 close · 420 open · 600 numbers · 800 headlines
- Press: scale .97. Always close faster than open
- Reduced motion: no movement, scale or blur; 120ms crossfade

NEVER
- Purple-blue gradients, perspective mockups, hands, emojis as icons
- Square corners on buttons, two atmospheres together, large shadows in dark
- Agency copy, lorem ipsum, made-up projects or metrics

That's how I design.If something here doesn't show in the result, it isn't finished yet.