howdy-jekyll-theme 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/AGENTS.md +49 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.md +431 -0
- data/_includes/analytics.html +19 -0
- data/_includes/blog-pagination.html +31 -0
- data/_includes/comments.html +46 -0
- data/_includes/dark-mode-toggle.html +18 -0
- data/_includes/head.html +137 -0
- data/_includes/hero-carousel.html +80 -0
- data/_includes/logo.html +5 -0
- data/_includes/navigation.html +24 -0
- data/_includes/newsletter.html +10 -0
- data/_includes/share-buttons.html +70 -0
- data/_includes/social-links.html +37 -0
- data/_includes/toc.html +29 -0
- data/_layouts/autopage_collection.html +43 -0
- data/_layouts/blog.html +42 -0
- data/_layouts/default.html +86 -0
- data/_layouts/home.html +5 -0
- data/_layouts/page.html +33 -0
- data/_layouts/post.html +76 -0
- data/_layouts/project.html +61 -0
- data/_plugins/sort_projects.rb +6 -0
- data/_plugins/user_colors.rb +68 -0
- data/_posts/2026-01-01-beyond-pixels.md +21 -0
- data/_posts/2026-01-02-collaboration.md +25 -0
- data/_posts/2026-01-03-design-feeling.md +25 -0
- data/_posts/2026-01-04-finding-inspiration.md +25 -0
- data/_posts/2026-01-05-freebies.md +35 -0
- data/_posts/2026-01-06-ux-research-methods.md +25 -0
- data/_posts/2026-01-07-color-theory.md +25 -0
- data/_posts/2026-01-08-responsive-design.md +25 -0
- data/_posts/2026-01-09-web-performance.md +25 -0
- data/_posts/2026-01-10-mobile-first.md +25 -0
- data/_posts/2026-04-15-crafting-visual-hierarchy.md +27 -0
- data/_posts/2026-04-16-building-design-systems.md +27 -0
- data/_posts/2026-04-18-accessibility-matters.md +25 -0
- data/_posts/2026-04-19-motion-design.md +29 -0
- data/_posts/2026-04-20-typography-basics.md +25 -0
- data/_posts/2026-04-22-product-design-best-practices.md +239 -0
- data/_projects/atlas.md +26 -0
- data/_projects/luminous.md +26 -0
- data/_projects/nova.md +31 -0
- data/_projects/osaka.md +26 -0
- data/_sass/_base.scss +181 -0
- data/_sass/_components.scss +767 -0
- data/_sass/_dark-mode.scss +39 -0
- data/_sass/_layout.scss +1033 -0
- data/_sass/_typography.scss +394 -0
- data/_sass/_user-colors.scss +1 -0
- data/_sass/_variables.scss +165 -0
- data/about.md +62 -0
- data/assets/css/main.scss +10 -0
- data/assets/css/swiper-bundle.min.css +13 -0
- data/assets/fonts/ChaumontScript-Regular.otf +0 -0
- data/assets/fonts/DMSans-Italic-Variable.ttf +0 -0
- data/assets/fonts/DMSans-Variable.ttf +0 -0
- data/assets/illustrations/analytics.svg +218 -0
- data/assets/illustrations/business-strategy.svg +161 -0
- data/assets/illustrations/designer.svg +267 -0
- data/assets/illustrations/email.svg +123 -0
- data/assets/illustrations/friends-taking-selfie.svg +189 -0
- data/assets/illustrations/launch.svg +230 -0
- data/assets/illustrations/love-animals.svg +83 -0
- data/assets/illustrations/meeting.svg +292 -0
- data/assets/illustrations/mobile-shopping.svg +113 -0
- data/assets/illustrations/online-shopping.svg +148 -0
- data/assets/illustrations/oops-something-went-wrong.svg +97 -0
- data/assets/illustrations/podcast.svg +199 -0
- data/assets/illustrations/presentation.svg +138 -0
- data/assets/illustrations/programmer.svg +240 -0
- data/assets/illustrations/task-management.svg +174 -0
- data/assets/illustrations/tasks-complete.svg +161 -0
- data/assets/illustrations/travel-booking-hotel.svg +214 -0
- data/assets/illustrations/video-call.svg +178 -0
- data/assets/images/apple-touch-icon.png +0 -0
- data/assets/images/favicon-dark.png +0 -0
- data/assets/images/favicon-light.png +0 -0
- data/assets/images/howdy-theme-dark.png +0 -0
- data/assets/images/howdy-theme-light.png +0 -0
- data/assets/images/og-image.png +0 -0
- data/assets/js/hero-carousel.js +36 -0
- data/assets/js/mobile-nav.js +62 -0
- data/assets/js/swiper-bundle.min.js +13 -0
- data/assets/js/swiper-bundle.min.js.map +1 -0
- data/assets/js/theme-toggle.js +54 -0
- data/assets/resume.pdf +683 -0
- data/contact.md +74 -0
- data/howdy-jekyll-theme.gemspec +25 -0
- data/lib/howdy-jekyll-theme.rb +19 -0
- metadata +245 -0
data/_layouts/post.html
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<section class="two-column">
|
|
6
|
+
<div class="left-section">
|
|
7
|
+
<div class="left-container">
|
|
8
|
+
<div class="image-wrapper">
|
|
9
|
+
<div class="hero-content">
|
|
10
|
+
{% include hero-carousel.html %}
|
|
11
|
+
<div class="logo-overlay">{% include logo.html %}</div>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="right-section">
|
|
18
|
+
<div class="content-wrapper">
|
|
19
|
+
{% include navigation.html %}
|
|
20
|
+
<div class="content-area">
|
|
21
|
+
{% if page.category or page.date %}
|
|
22
|
+
<div class="detail-meta">
|
|
23
|
+
{% if page.category %}
|
|
24
|
+
<span class="post-category category-{{ page.category | downcase }}">{{ page.category }}</span>
|
|
25
|
+
{% endif %}
|
|
26
|
+
{% if page.date %}
|
|
27
|
+
<span class="detail-date">{{ page.date | date: "%b %d, %Y" }}</span>
|
|
28
|
+
{% endif %}
|
|
29
|
+
{% if site.reading_time %}
|
|
30
|
+
{% assign words = content | number_of_words %}
|
|
31
|
+
{% assign read_time = words | divided_by: 200 | at_least: 1 %}
|
|
32
|
+
<span class="detail-read-time">{{ read_time }} min read</span>
|
|
33
|
+
{% endif %}
|
|
34
|
+
</div>
|
|
35
|
+
{% endif %}
|
|
36
|
+
|
|
37
|
+
<h1>{{ page.title }}</h1>
|
|
38
|
+
|
|
39
|
+
{% if site.table_of_contents.enabled and page.table_of_contents != false %}
|
|
40
|
+
{% include toc.html content=content min_heading=site.table_of_contents.min_heading max_heading=site.table_of_contents.max_heading %}
|
|
41
|
+
{% endif %}
|
|
42
|
+
|
|
43
|
+
<div class="detail-content">
|
|
44
|
+
{{ content }}
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
{% include share-buttons.html %}
|
|
48
|
+
|
|
49
|
+
<!-- Post navigation -->
|
|
50
|
+
{% if page.previous.url or page.next.url %}
|
|
51
|
+
<div class="detail-nav detail-nav-post">
|
|
52
|
+
{% if page.previous.url %}
|
|
53
|
+
<a href="{{ page.previous.url | relative_url }}" class="btn btn-secondary">
|
|
54
|
+
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true" class="btn-arrow">
|
|
55
|
+
<path d="M9 3L4 8L9 13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
56
|
+
</svg>
|
|
57
|
+
<span class="btn-label">{{ page.previous.title }}</span>
|
|
58
|
+
</a>
|
|
59
|
+
{% endif %}
|
|
60
|
+
{% if page.next.url %}
|
|
61
|
+
<a href="{{ page.next.url | relative_url }}" class="btn btn-secondary post-nav-next">
|
|
62
|
+
<span class="btn-label">{{ page.next.title }}</span>
|
|
63
|
+
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true" class="btn-arrow">
|
|
64
|
+
<path d="M7 3L12 8L7 13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
65
|
+
</svg>
|
|
66
|
+
</a>
|
|
67
|
+
{% endif %}
|
|
68
|
+
</div>
|
|
69
|
+
{% endif %}
|
|
70
|
+
|
|
71
|
+
{% include newsletter.html %}
|
|
72
|
+
{% include comments.html %}
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</section>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<section class="two-column">
|
|
6
|
+
<div class="left-section">
|
|
7
|
+
<div class="left-container">
|
|
8
|
+
<div class="image-wrapper">
|
|
9
|
+
<div class="hero-content">
|
|
10
|
+
{% include hero-carousel.html %}
|
|
11
|
+
<div class="logo-overlay">{% include logo.html %}</div>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="right-section">
|
|
18
|
+
<div class="content-wrapper">
|
|
19
|
+
{% include navigation.html %}
|
|
20
|
+
<div class="content-area">
|
|
21
|
+
{% if page.category or page.year %}
|
|
22
|
+
<div class="detail-meta">
|
|
23
|
+
{% if page.category %}
|
|
24
|
+
<span class="project-category">{{ page.category }}</span>
|
|
25
|
+
{% endif %}
|
|
26
|
+
{% if page.year %}
|
|
27
|
+
<span class="detail-year">{{ page.year }}</span>
|
|
28
|
+
{% endif %}
|
|
29
|
+
</div>
|
|
30
|
+
{% endif %}
|
|
31
|
+
|
|
32
|
+
<h1>{{ page.title }}</h1>
|
|
33
|
+
|
|
34
|
+
{% if page.subtitle %}
|
|
35
|
+
<p class="body-large detail-subtitle">{{ page.subtitle }}</p>
|
|
36
|
+
{% endif %}
|
|
37
|
+
|
|
38
|
+
<div class="detail-content">
|
|
39
|
+
{{ content }}
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="detail-nav detail-nav-project">
|
|
43
|
+
<a href="{{ '/projects' | relative_url }}" class="btn btn-secondary">
|
|
44
|
+
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true" class="btn-arrow">
|
|
45
|
+
<path d="M9 3L4 8L9 13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
46
|
+
</svg>
|
|
47
|
+
Back to Projects
|
|
48
|
+
</a>
|
|
49
|
+
{% if page.next %}
|
|
50
|
+
<a href="{{ page.next.url | relative_url }}" class="btn btn-secondary project-nav-next">
|
|
51
|
+
<span class="btn-label">{{ page.next.title }}</span>
|
|
52
|
+
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true" class="btn-arrow">
|
|
53
|
+
<path d="M7 3L12 8L7 13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
54
|
+
</svg>
|
|
55
|
+
</a>
|
|
56
|
+
{% endif %}
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</section>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Generates _sass/_user-colors.scss from site.colors config
|
|
2
|
+
# This allows users to override theme colors via _config.yml
|
|
3
|
+
|
|
4
|
+
Jekyll::Hooks.register :site, :after_init do |site|
|
|
5
|
+
colors = site.config["colors"] || {}
|
|
6
|
+
colors = {} unless colors.is_a?(Hash)
|
|
7
|
+
dark = colors["dark"] || {}
|
|
8
|
+
dark = {} unless dark.is_a?(Hash)
|
|
9
|
+
|
|
10
|
+
# Map config keys to CSS variable names
|
|
11
|
+
var_map = {
|
|
12
|
+
"text_primary" => "--howdy-text-primary",
|
|
13
|
+
"text_secondary" => "--howdy-text-secondary",
|
|
14
|
+
"text_muted" => "--howdy-text-muted",
|
|
15
|
+
"text_red" => "--howdy-text-red",
|
|
16
|
+
"bg_light_gray" => "--howdy-bg-light-gray",
|
|
17
|
+
"bg_white" => "--howdy-bg-white",
|
|
18
|
+
"bg_dark_gray" => "--howdy-bg-dark-gray",
|
|
19
|
+
"bg_cream" => "--howdy-bg-cream",
|
|
20
|
+
"bg_semi_white" => "--howdy-bg-semi-white",
|
|
21
|
+
"bg_green_tint" => "--howdy-bg-green-tint",
|
|
22
|
+
"bg_red_tint" => "--howdy-bg-red-tint",
|
|
23
|
+
"bg_orange_tint" => "--howdy-bg-orange-tint",
|
|
24
|
+
"bg_blue_tint" => "--howdy-bg-blue-tint",
|
|
25
|
+
"bg_purple_tint" => "--howdy-bg-purple-tint",
|
|
26
|
+
"accent_green" => "--howdy-accent-green",
|
|
27
|
+
"accent_orange" => "--howdy-accent-orange",
|
|
28
|
+
"accent_blue" => "--howdy-accent-blue",
|
|
29
|
+
"accent_purple" => "--howdy-accent-purple",
|
|
30
|
+
"border" => "--howdy-border",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
sass_dir = File.join(site.source, "_sass")
|
|
34
|
+
output_path = File.join(sass_dir, "_user-colors.scss")
|
|
35
|
+
|
|
36
|
+
lines = ["// Auto-generated from site.colors in _config.yml — do not edit"]
|
|
37
|
+
|
|
38
|
+
# Light mode overrides (grouped into single :root block)
|
|
39
|
+
light_props = []
|
|
40
|
+
var_map.each do |key, var|
|
|
41
|
+
val = colors[key]
|
|
42
|
+
light_props << " #{var}: #{val};" if val
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
if light_props.any?
|
|
46
|
+
lines << ""
|
|
47
|
+
lines << ":root {"
|
|
48
|
+
lines.concat(light_props)
|
|
49
|
+
lines << "}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Dark mode overrides (grouped into single html.dark-mode block)
|
|
53
|
+
dark_props = []
|
|
54
|
+
var_map.each do |key, var|
|
|
55
|
+
val = dark[key]
|
|
56
|
+
dark_props << " #{var}: #{val};" if val
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
if dark_props.any?
|
|
60
|
+
lines << ""
|
|
61
|
+
lines << "html.dark-mode, html.dark-mode body, html.dark-mode .main-container {"
|
|
62
|
+
lines.concat(dark_props)
|
|
63
|
+
lines << "}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
lines << ""
|
|
67
|
+
File.write(output_path, lines.join("\n"))
|
|
68
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "Beyond Pixels: Thinking in Systems"
|
|
4
|
+
date: 2026-01-01
|
|
5
|
+
category: "Inspiration"
|
|
6
|
+
image: /assets/illustrations/presentation.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
The best product designers I know don't think in screens. They think in systems: the invisible structures that hold everything together.
|
|
10
|
+
|
|
11
|
+
## What Systems Thinking Looks Like
|
|
12
|
+
|
|
13
|
+
**Everything is connected.** A change to the spacing scale affects every component. A new color token ripples through every state. Understanding these connections is what separates senior designers from juniors.
|
|
14
|
+
|
|
15
|
+
**Design the edges, not just the happy path.** What happens when there's no data? When the API fails? When the user has 200 items instead of 3? The happy path is 10% of the work.
|
|
16
|
+
|
|
17
|
+
**Constraints are your friend.** The most creative solutions emerge from the tightest constraints. Limited color palette? Fewer components? Tighter timeline? Good. Now you have to make real decisions.
|
|
18
|
+
|
|
19
|
+
<!--more-->
|
|
20
|
+
|
|
21
|
+
The goal isn't to design every screen perfectly. It's to design a system that makes it impossible to build a bad screen.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "The Art of Design Collaboration"
|
|
4
|
+
date: 2026-01-02
|
|
5
|
+
category: "Inspiration"
|
|
6
|
+
image: /assets/illustrations/video-call.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Great design doesn't happen in a vacuum. It emerges from collaboration: the messy, iterative, sometimes uncomfortable process of working with people who think differently than you.
|
|
10
|
+
|
|
11
|
+
## Working with Engineers
|
|
12
|
+
|
|
13
|
+
The best designer-engineer relationships are partnerships, not handoffs. When engineers are involved early, they catch edge cases you missed and suggest technical approaches that unlock new design possibilities.
|
|
14
|
+
|
|
15
|
+
## Working with Product
|
|
16
|
+
|
|
17
|
+
Product managers and designers often have tension: PMs want to ship fast, designers want to get it right. The secret is shared context. When both sides understand the user problem equally, the debate shifts from "what should we build?" to "how do we solve this best?"
|
|
18
|
+
|
|
19
|
+
## Working with Researchers
|
|
20
|
+
|
|
21
|
+
Research isn't a phase. It's a practice. Embed researchers in your team, not in a separate org. The closer research is to design decisions, the more impact it has.
|
|
22
|
+
|
|
23
|
+
<!--more-->
|
|
24
|
+
|
|
25
|
+
Collaboration isn't about consensus. It's about building something together that none of you could have built alone.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "Design Is a Feeling"
|
|
4
|
+
date: 2026-01-03
|
|
5
|
+
category: "Inspiration"
|
|
6
|
+
image: /assets/illustrations/mobile-shopping.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
The most memorable products aren't remembered for their features. They're remembered for how they made you feel.
|
|
10
|
+
|
|
11
|
+
## Emotional Design
|
|
12
|
+
|
|
13
|
+
**Delight is earned, not manufactured.** Confetti animations and micro-interactions are nice, but real delight comes from a product that understands you and makes you feel capable.
|
|
14
|
+
|
|
15
|
+
**Friction has a purpose.** Not all friction is bad. A confirmation dialog before deleting something important isn't a UX problem; it's a safety feature. The question is whether the friction is intentional or accidental.
|
|
16
|
+
|
|
17
|
+
**Trust is built in moments.** Every time a product does what you expect, trust increases. Every time it surprises you negatively, trust decreases. You're always building or destroying trust.
|
|
18
|
+
|
|
19
|
+
## The Feeling of Good Design
|
|
20
|
+
|
|
21
|
+
Good design feels like the product was made for you. It anticipates your needs, respects your time, and doesn't make you think about the interface. You just do what you came to do.
|
|
22
|
+
|
|
23
|
+
<!--more-->
|
|
24
|
+
|
|
25
|
+
If your user finishes a task and thinks "that was nice," you've done okay. If they finish and don't think about it at all, you've done great.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "Finding Design Inspiration in the Real World"
|
|
4
|
+
date: 2026-01-04
|
|
5
|
+
category: "Inspiration"
|
|
6
|
+
image: /assets/illustrations/online-shopping.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
The best product design ideas don't come from Dribbble. They come from paying attention to how people interact with the world.
|
|
10
|
+
|
|
11
|
+
## Where I Look
|
|
12
|
+
|
|
13
|
+
**Physical products.** How does a well-designed door handle communicate its function? That's affordance. The same principles apply to digital interfaces.
|
|
14
|
+
|
|
15
|
+
**Transit systems.** Wayfinding, information hierarchy, and real-time feedback. Airports and train stations solve many of the same UX problems we do.
|
|
16
|
+
|
|
17
|
+
**Restaurants.** Menu design is information architecture. The pacing of a meal is user flow. The check-out experience is conversion optimization.
|
|
18
|
+
|
|
19
|
+
## Building an Inspiration Habit
|
|
20
|
+
|
|
21
|
+
Keep a running document of things that work well. Not screenshots, but observations. "The elevator lobby had three lights showing which car was closest. Simple, effective, reduced anxiety." That's a design pattern waiting to be applied.
|
|
22
|
+
|
|
23
|
+
<!--more-->
|
|
24
|
+
|
|
25
|
+
Inspiration isn't something you find. It's something you notice. And you notice things you're looking for.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "Free Resources for Product Designers"
|
|
4
|
+
date: 2026-01-05
|
|
5
|
+
category: "Freebies"
|
|
6
|
+
image: /assets/illustrations/podcast.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
A curated collection of tools, templates, and resources that every product designer should have in their toolkit.
|
|
10
|
+
|
|
11
|
+
## Figma Community Files
|
|
12
|
+
|
|
13
|
+
**Design System Starter** A minimal but complete design system with tokens, components, and documentation pages.
|
|
14
|
+
|
|
15
|
+
**Accessibility Checklist** A ready-to-use checklist for WCAG 2.1 AA compliance, embedded directly in your Figma files.
|
|
16
|
+
|
|
17
|
+
**AI Design Patterns Library** A collection of common AI interaction patterns: progressive disclosure, confidence indicators, draft states, and suggested prompts.
|
|
18
|
+
|
|
19
|
+
## Reading List
|
|
20
|
+
|
|
21
|
+
- *Thinking in Systems* by Donella Meadows
|
|
22
|
+
- *The Design of Everyday Things* by Don Norman
|
|
23
|
+
- *About Face* by Alan Cooper
|
|
24
|
+
- *Refactoring UI* by Adam Wathan & Steve Schoger
|
|
25
|
+
|
|
26
|
+
## Tools
|
|
27
|
+
|
|
28
|
+
- **Figma** Design and prototyping
|
|
29
|
+
- **FigJam** Whiteboarding and collaboration
|
|
30
|
+
- **Stark** Accessibility testing
|
|
31
|
+
- **LottieFiles** Animation library
|
|
32
|
+
|
|
33
|
+
<!--more-->
|
|
34
|
+
|
|
35
|
+
The best resources are the ones you actually use. Pick two, master them, then expand.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "UX Research Methods That Actually Work"
|
|
4
|
+
date: 2026-01-06
|
|
5
|
+
category: "Tutorials"
|
|
6
|
+
image: /assets/illustrations/task-management.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Not all research is created equal. After years of trial and error, these are the methods I return to again and again.
|
|
10
|
+
|
|
11
|
+
## The Three I Use Most
|
|
12
|
+
|
|
13
|
+
**Contextual inquiry.** Watch people use your product in their actual environment. Not a usability lab, but their desk, their phone, their commute. You'll learn more in 30 minutes of observation than 10 hours of interviews.
|
|
14
|
+
|
|
15
|
+
**Task analysis.** Break down a user goal into its component steps. Then ask: which steps can be eliminated? Which can be automated? Which are creating unnecessary cognitive load?
|
|
16
|
+
|
|
17
|
+
**Diary studies.** Have users log their experiences over a week or two. Patterns emerge that single-session research misses entirely.
|
|
18
|
+
|
|
19
|
+
## What I've Stopped Doing
|
|
20
|
+
|
|
21
|
+
**A/B testing for big decisions.** A/B tests optimize local maxima. They tell you whether a green button beats a blue one. They don't tell you whether you're solving the right problem.
|
|
22
|
+
|
|
23
|
+
<!--more-->
|
|
24
|
+
|
|
25
|
+
Research isn't about validating your ideas. It's about discovering what you didn't know you didn't know.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "The Psychology of Color in Interfaces"
|
|
4
|
+
date: 2026-01-07
|
|
5
|
+
category: "Inspiration"
|
|
6
|
+
image: /assets/illustrations/tasks-complete.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Color in product design isn't about aesthetics. It's about information architecture. Your color system is a map: it tells users where they are, what's important, and what actions are available.
|
|
10
|
+
|
|
11
|
+
## Building a Color System
|
|
12
|
+
|
|
13
|
+
**Start with semantics.** Name your colors by their purpose, not their appearance. `--color-success`, `--color-error`, `--color-warning`. This makes your system resilient to rebranding.
|
|
14
|
+
|
|
15
|
+
**Limit your palette.** Three primary colors, three semantic colors, and a grayscale scale. That's enough for 95% of interfaces.
|
|
16
|
+
|
|
17
|
+
**Dark mode isn't an inversion.** You need to rethink contrast, saturation, and elevation. Shadows don't work in dark mode. Use overlays instead.
|
|
18
|
+
|
|
19
|
+
## The Green Problem
|
|
20
|
+
|
|
21
|
+
Green means success, go, and positive change. But in financial contexts, green means money going up. In environmental contexts, it means sustainability. Context matters.
|
|
22
|
+
|
|
23
|
+
<!--more-->
|
|
24
|
+
|
|
25
|
+
The best color system is the one that tells a consistent story across every surface. When users see a color, they should know exactly what it means.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "Responsive Design Beyond Breakpoints"
|
|
4
|
+
date: 2026-01-08
|
|
5
|
+
category: "Tutorials"
|
|
6
|
+
image: /assets/illustrations/friends-taking-selfie.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Responsive design isn't about choosing breakpoints. It's about building layouts that flow naturally across any viewport.
|
|
10
|
+
|
|
11
|
+
## The Fluid Approach
|
|
12
|
+
|
|
13
|
+
**Use `clamp()` for typography.** `clamp(1rem, 2vw + 0.5rem, 1.5rem)` gives you smooth scaling between min and max sizes without media queries.
|
|
14
|
+
|
|
15
|
+
**Flex and Grid are your foundation.** Stop setting fixed widths. Let content determine the layout, and use `minmax()` and `auto-fit` to handle the edges.
|
|
16
|
+
|
|
17
|
+
**Test on real devices.** Browser resize isn't enough. Touch targets, hover states, and scrolling behavior differ fundamentally between input methods.
|
|
18
|
+
|
|
19
|
+
## What I've Changed My Mind About
|
|
20
|
+
|
|
21
|
+
I used to design mobile-first and scale up. Now I design content-first: start with the information hierarchy, then let the layout adapt. Mobile and desktop are just different ways of consuming the same structure.
|
|
22
|
+
|
|
23
|
+
<!--more-->
|
|
24
|
+
|
|
25
|
+
The best responsive designs don't feel responsive. They feel like they were made exactly for the screen you're holding.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "Performance Is a Feature"
|
|
4
|
+
date: 2026-01-09
|
|
5
|
+
category: "Tutorials"
|
|
6
|
+
image: /assets/illustrations/meeting.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Users don't forgive slow products. No amount of beautiful design can compensate for an interface that feels sluggish. Performance isn't an engineering concern; it's a design concern.
|
|
10
|
+
|
|
11
|
+
## The Perception of Speed
|
|
12
|
+
|
|
13
|
+
What users feel isn't the same as what actually happens. A 200ms perceived delay feels instant. A 500ms delay feels noticeable. Anything over 1 second feels broken.
|
|
14
|
+
|
|
15
|
+
**Optimistic UI.** Update the interface immediately, then confirm with the server. This makes products feel instant even when they're not.
|
|
16
|
+
|
|
17
|
+
**Skeleton screens.** Better than spinners because they show the user what's coming, reducing perceived wait time.
|
|
18
|
+
|
|
19
|
+
## Design Decisions That Impact Performance
|
|
20
|
+
|
|
21
|
+
Every image, every animation, every custom font you add costs something. The question isn't "can we afford this?" It's "is this worth the trade-off?"
|
|
22
|
+
|
|
23
|
+
<!--more-->
|
|
24
|
+
|
|
25
|
+
The fastest interface is the one that doesn't load at all. Progressive enhancement means your core experience works before your enhancements arrive.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "Mobile-First Is Dead. Content-First Lives On."
|
|
4
|
+
date: 2026-01-10
|
|
5
|
+
category: "Tutorials"
|
|
6
|
+
image: /assets/illustrations/love-animals.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
The mobile-first movement served its purpose, but it's an outdated heuristic for a world where users fluidly move between devices, screens, and input methods.
|
|
10
|
+
|
|
11
|
+
## The Problem with Mobile-First
|
|
12
|
+
|
|
13
|
+
Starting with the smallest screen forces you to prioritize, which is good. But it also forces you to design for constraints that may not exist on other surfaces, leading to experiences that feel compromised rather than adapted.
|
|
14
|
+
|
|
15
|
+
## Content-First Design
|
|
16
|
+
|
|
17
|
+
Start with the information. What is the user trying to accomplish? What data do they need? What decisions do they need to make? Then let the layout serve the content, not the device.
|
|
18
|
+
|
|
19
|
+
**Information hierarchy is device-agnostic.** A user's need to understand their data doesn't change between mobile and desktop. Only the presentation changes.
|
|
20
|
+
|
|
21
|
+
**Interaction patterns adapt.** Touch vs. mouse, portrait vs. landscape, single-task vs. multi-window. These are interaction concerns, not content concerns.
|
|
22
|
+
|
|
23
|
+
<!--more-->
|
|
24
|
+
|
|
25
|
+
Don't design for a screen size. Design for a human need, then let the interface adapt.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "The Case for Visual Hierarchy"
|
|
4
|
+
date: 2026-04-15
|
|
5
|
+
category: "Tutorials"
|
|
6
|
+
image: /assets/illustrations/travel-booking-hotel.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Every interface is a conversation between the product and the user. Visual hierarchy is how you control what gets said first, what gets emphasized, and what stays quiet.
|
|
10
|
+
|
|
11
|
+
## The Four Levers
|
|
12
|
+
|
|
13
|
+
**Size.** Larger elements attract attention first. But size alone is blunt. Use it sparingly.
|
|
14
|
+
|
|
15
|
+
**Weight.** Bold text creates emphasis without changing the spatial layout. It's the most surgical tool in your hierarchy toolkit.
|
|
16
|
+
|
|
17
|
+
**Color.** High-contrast colors draw the eye. Muted tones recede. Use color to signal importance, not decoration.
|
|
18
|
+
|
|
19
|
+
**Spacing.** White space is the most underused hierarchy tool. More space around an element makes it feel more important. Less space groups related items together.
|
|
20
|
+
|
|
21
|
+
## Common Mistakes
|
|
22
|
+
|
|
23
|
+
Making everything important makes nothing important. If every element is bold, large, and colorful, you've created noise, not hierarchy.
|
|
24
|
+
|
|
25
|
+
<!--more-->
|
|
26
|
+
|
|
27
|
+
Good hierarchy doesn't need to be explained. Users should instinctively know where to look and what to do next. If you have to tell them, the hierarchy has failed.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "Building Design Systems That Scale"
|
|
4
|
+
date: 2026-04-16
|
|
5
|
+
category: "Tutorials"
|
|
6
|
+
image: /assets/illustrations/presentation.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
A design system isn't a Figma file with components. It's a living agreement between design and engineering about how products should be built.
|
|
10
|
+
|
|
11
|
+
## The Architecture
|
|
12
|
+
|
|
13
|
+
**Tokens are the foundation.** Colors, spacing, typography scales, radii, shadows: these are your primitives. Everything else is composed from them.
|
|
14
|
+
|
|
15
|
+
**Primitives are simple components.** Buttons, inputs, badges. They map directly to HTML elements and are consumed by patterns.
|
|
16
|
+
|
|
17
|
+
**Patterns solve recurring problems.** Form layouts, data tables, empty states. These are where design system maturity really shows.
|
|
18
|
+
|
|
19
|
+
**Product components are custom.** Not everything belongs in the system. Your unique product features should be built on top of the system, not inside it.
|
|
20
|
+
|
|
21
|
+
## What I've Learned
|
|
22
|
+
|
|
23
|
+
The biggest mistake teams make is over-building the system before anyone uses it. Start with what hurts the most. If everyone is building their own button, start there.
|
|
24
|
+
|
|
25
|
+
<!--more-->
|
|
26
|
+
|
|
27
|
+
The best design system I've ever worked on started with three tokens and a button. Everything else grew from actual need, not hypothetical completeness.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "Accessibility Is a Design Constraint, Not a Feature"
|
|
4
|
+
date: 2026-04-18
|
|
5
|
+
category: "Freebies"
|
|
6
|
+
image: /assets/illustrations/mobile-shopping.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Too often, accessibility gets treated as a checklist item at the end of a project. "We'll add alt text later." "Let's check contrast before launch." This approach guarantees mediocrity.
|
|
10
|
+
|
|
11
|
+
## Accessibility from Day One
|
|
12
|
+
|
|
13
|
+
When you design with accessibility as a constraint from the start, you end up with better products for everyone. Curb cuts were designed for wheelchair users, yet everyone benefits.
|
|
14
|
+
|
|
15
|
+
**Color isn't information.** Never rely on color alone to convey meaning. Pair color with icons, labels, or patterns. Your red/green status indicators are meaningless to 8% of men.
|
|
16
|
+
|
|
17
|
+
**Keyboard-first thinking.** Design every interaction to work without a mouse. This forces you to think about focus states, tab order, and logical grouping. It improves the experience for everyone.
|
|
18
|
+
|
|
19
|
+
## The Business Case
|
|
20
|
+
|
|
21
|
+
Accessible products reach more users. They perform better in search. They're more resilient to edge cases. And they avoid legal risk. There is no scenario where ignoring accessibility is the right call.
|
|
22
|
+
|
|
23
|
+
<!--more-->
|
|
24
|
+
|
|
25
|
+
If you're designing a product that isn't accessible to everyone, you're not designing a product. You're designing an exclusion.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "Designing with Motion"
|
|
4
|
+
date: 2026-04-19
|
|
5
|
+
category: "Inspiration"
|
|
6
|
+
image: /assets/illustrations/online-shopping.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Motion in product design serves a purpose: it communicates relationships, directs attention, and makes interactions feel natural. When done well, users don't notice it. When done poorly, everything feels broken.
|
|
10
|
+
|
|
11
|
+
## The Rules I Follow
|
|
12
|
+
|
|
13
|
+
**Duration.** Transitions should be between 150ms and 300ms. Under 150ms feels jarring. Over 300ms feels sluggish. Page transitions can go to 400ms.
|
|
14
|
+
|
|
15
|
+
**Easing.** Linear motion feels robotic. Use `cubic-bezier(0.22, 1, 0.36, 1)` for entrances; it feels natural and responsive. For exits, ease-out is your friend.
|
|
16
|
+
|
|
17
|
+
**Transform, not layout.** Always animate `transform` and `opacity`. Never animate `width`, `height`, `margin`, or `padding`. They trigger layout recalculation and feel choppy.
|
|
18
|
+
|
|
19
|
+
## Where Motion Matters Most
|
|
20
|
+
|
|
21
|
+
**State changes.** When a card expands into a detail view, the transition should maintain spatial continuity. Shared element transitions make this possible.
|
|
22
|
+
|
|
23
|
+
**Loading states.** Replace spinners with skeleton screens that mimic the actual content structure. Add a subtle shimmer: not too bright, not too fast.
|
|
24
|
+
|
|
25
|
+
**Feedback.** Micro-interactions like button presses, toggle switches, and checkboxes should provide tactile confirmation of the action.
|
|
26
|
+
|
|
27
|
+
<!--more-->
|
|
28
|
+
|
|
29
|
+
Motion is the glue between interface states. Without it, your product feels like a series of disconnected snapshots. With it, everything flows.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: post
|
|
3
|
+
title: "Typography in Product Design"
|
|
4
|
+
date: 2026-04-20
|
|
5
|
+
category: "Tutorials"
|
|
6
|
+
image: /assets/illustrations/podcast.svg
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Typography in product design isn't about choosing beautiful typefaces. It's about building a system that scales across every surface, supports multiple languages, and remains readable at every density.
|
|
10
|
+
|
|
11
|
+
## The Product Designer's Typographic System
|
|
12
|
+
|
|
13
|
+
**Scale, not sizes.** Use a modular scale with defined ratios. I prefer 1.25 (major third) for dense interfaces and 1.333 (perfect fourth) for content-heavy pages.
|
|
14
|
+
|
|
15
|
+
**Weights over families.** A single well-chosen type family with 5-7 weights gives you more flexibility than switching between families. DM Sans, Inter, and SF Pro are workhorses for a reason.
|
|
16
|
+
|
|
17
|
+
**Line length matters.** 60-75 characters per line is the sweet spot for readability. In dense dashboards, you might go shorter, but never below 40.
|
|
18
|
+
|
|
19
|
+
## Dark Mode Considerations
|
|
20
|
+
|
|
21
|
+
Text in dark mode isn't just inverted white-on-black. Reduce contrast slightly to prevent eye strain. I use `#E5E5E5` on `#1A1A1A` instead of pure white on pure black.
|
|
22
|
+
|
|
23
|
+
<!--more-->
|
|
24
|
+
|
|
25
|
+
The best typography system is the one users never notice. When reading feels effortless, the system is working.
|