Agent skill
visual-style
Use when creating or modifying UI components, styling, themes, or layouts in peek-stash-browser. Follow these visual conventions exactly.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/visual-style
SKILL.md
Visual Style Guide
Color System
Colors are defined as CSS custom properties, set by the theme provider. Never use hardcoded colors.
Core Variables
--bg-primary /* Page background (#0a0a0b dark) */
--bg-secondary /* Nav, buttons, controls (#1d1d20) */
--bg-card /* Cards, modals (#19191b) */
--bg-tertiary /* Skeleton loaders, subtle backgrounds */
--text-primary /* Main text (white) */
--text-secondary /* Secondary text (15% dimmer) */
--text-muted /* De-emphasized text (30% dimmer) */
--accent-primary /* Primary accent (theme-dependent) */
--accent-secondary /* Secondary accent */
--border-color /* Borders (#2a2a32) */
--focus-ring-color /* Keyboard focus ring */
--focus-ring-shadow /* Focus ring shadow */
--selection-color /* Hover/selection outlines */
--selection-bg /* Selection background (10% accent) */
Status Colors
--status-success: #0F7173 /* Teal */
--status-error: #FD6B86 /* Pink */
--status-info: #3993DD /* Blue */
--status-warning: #FA8C2A /* Orange */
/* Each has -bg (10% opacity) and -border (30% opacity) variants */
Themes
Five built-in themes defined in client/src/themes/themes.js. Custom themes supported via API. All themes use the same CSS variable interface, only values change.
Tailwind Patterns
Breakpoints
Standard Tailwind plus custom large-screen breakpoints:
| Breakpoint | Width | Use |
|---|---|---|
sm |
640px | Small tablets |
md |
768px | Tablets |
lg |
1024px | Desktop |
xl |
1280px | Large desktop |
2xl |
1536px | Wide monitors |
3xl |
1920px | Full HD |
4xl |
2560px | QHD/1440p |
5xl |
3840px | 4K UHD |
Common Class Patterns
// Card container
"flex flex-col rounded-lg border p-2"
style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-color)" }}
// Hover effects on cards
"hover:shadow-lg hover:scale-[1.02] transition-all"
// Card outlines on hover
"hover:outline hover:outline-2 hover:outline-[var(--selection-color)] hover:outline-offset-2"
// Text styling
"text-primary" /* var(--text-primary) */
"text-secondary" /* var(--text-secondary) */
"text-muted" /* var(--text-muted) */
// Buttons
"btn" /* Base: p-2 px-4 rounded-lg border transition-all 0.2s */
"btn-primary" /* Accent bg, white text, opacity hover */
Grid System
Grid Densities
Three density levels (small/medium/large) with responsive column counts. Defined in client/src/constants/grids.js.
Standard grid (performers, studios, tags) — uses sm: breakpoint:
| Density | base | sm | lg | xl | 2xl | 3xl | 4xl | 5xl |
|---|---|---|---|---|---|---|---|---|
| Small | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 14 |
| Medium | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 12 |
| Large | 1 | 2 | 2 | 3 | 3 | 4 | 5 | 8 |
Scene grid (uses md: breakpoint, different column counts for 16:9):
| Density | base | md | lg | xl | 2xl | 3xl | 4xl | 5xl |
|---|---|---|---|---|---|---|---|---|
| Small | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 12 |
| Medium | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 |
| Large | 1 | 2 | 2 | 3 | 3 | 4 | 5 | 6 |
Grid gap is always gap-4 (1rem).
Card Density Scaling
CSS custom properties scale text and spacing per density. Applied via density-{level} class on the grid container.
| Property | Small | Medium | Large |
|---|---|---|---|
--card-title-size |
13px | 15px | 16px |
--card-subtitle-size |
12px | 13px | 14px |
--card-padding |
6px | 8px | 10px |
--card-image-margin |
8px | 12px | 14px |
--card-rating-icon-size |
14px | 18px | 20px |
Card Component Architecture
Cards use a composable primitive system defined in client/src/components/ui/CardComponents.jsx:
CardContainer - Outer wrapper (border, bg, hover effects)
CardImage - Aspect-ratio image with lazy loading
CardTitle - MarqueeText with auto-scroll on overflow
CardSubtitle - Secondary text line
CardDescription - ExpandableDescription (3-line clamp default)
CardIndicators - Relationship counts (performers, tags, etc.)
CardRatingRow - Rating + O-counter + favorite + menu
CardMenuRow - Entity-specific action buttons
BaseCard in client/src/components/ui/BaseCard.jsx composes these primitives via render slots. Entity-specific cards (SceneCard, PerformerCard, etc.) pass their content to BaseCard.
Aspect Ratios by Entity
| Entity | Ratio | CSS |
|---|---|---|
| Scene | 16:9 | aspect-[16/9] |
| Performer | 2:3 | aspect-[2/3] |
| Gallery | 3:4 | aspect-[3/4] |
| Studio | 16:9 | aspect-[16/9] |
| Tag | 16:9 | aspect-[16/9] |
Animation & Transitions
Standard Transitions
- Card hover:
transition-all 0.2s ease - Button states:
transition-all 0.15s ease
Keyboard Focus
.keyboard-focus {
outline: 3px solid var(--focus-ring-color);
box-shadow: var(--focus-ring-shadow), 0 8px 24px rgba(0,0,0,0.4);
transform: scale(1.05);
z-index: 10;
}
Pulse animation on focused card (2s infinite, subtle scale 1.0-1.02).
Mouse vs Keyboard
.mouse-user *:focus {
outline: none !important;
box-shadow: none !important;
}
Focus rings only show for keyboard/TV navigation, not mouse clicks.
MarqueeText
Card titles auto-scroll when text overflows on hover. Implementation in client/src/components/ui/MarqueeText.jsx:
- Speed: ~30px/second
- Pauses at start (15%) and end (25%)
- Respects
prefers-reduced-motion - GPU-accelerated via
translate3d
Loading Skeletons
<div className="animate-pulse rounded-lg" style={{
backgroundColor: "var(--bg-tertiary)",
height: "20rem" // scene cards, 24rem for standard
}} />
Keyboard Navigation
The app supports full TV/remote navigation with spatial awareness:
- Zones: search, topPagination, grid, bottomPagination, mainNav
- Focus class:
keyboard-focuson the active element - tabIndex: 0 for focused element, -1 for all others
- Arrow keys: Spatial navigation within grid
- Enter/Space: Select/navigate
- Escape: Move between zones
Layout Patterns
Page Structure
<PageLayout>
<PageHeader /> {/* Title, search, filter controls */}
<GridLayout> {/* Or BaseGrid */}
<EntityCard /> {/* Repeated per item */}
</GridLayout>
<Pagination />
</PageLayout>
Containers
| Class | Behavior |
|---|---|
.layout-container |
Full viewport width |
.container |
0.25rem padding mobile, 1rem desktop |
.container-fluid |
Full width + responsive padding |
.container-constrained |
Max 1400px + responsive padding |
Rules
- Never hardcode colors — always use CSS custom properties
- Never skip breakpoints — always include 3xl/4xl/5xl for large displays
- Use density variables for text sizing — never hardcode font sizes in cards
- Respect focus patterns — keyboard-focus class, not custom focus styles
- Use CardComponents primitives — don't create new card layouts from scratch
- Images lazy load via IntersectionObserver — never eager-load grid images
- Transitions are 0.2s ease — don't use longer or different easing
- Status colors are fixed — success=teal, error=pink, info=blue, warning=orange
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?