Use the Optics design framework for styling applications. Apply Optics classes for layout, spacing, typography, colors, and components. Use when working on CSS, styling views, or implementing design system guidelines.
65
78%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./skills/optics-context/SKILL.mdApply the Optics design system for consistent, token-based styling in Rails applications.
assets/tokens.jsonSearch for components in this order:
skills/optics-context/assets/components.json
app/assets/stylesheets for existing classesAlways use CSS custom properties from assets/tokens.json:
var(--op-color-primary-base), var(--op-color-background)var(--op-space-small), var(--op-space-medium), var(--op-space-large)var(--op-font-medium), var(--op-line-height-base)var(--op-radius-small), var(--op-border-width)var(--op-shadow-small), var(--op-shadow-medium)Never use hard-coded values:
❌ Colors: #fff, #000, rgb(...), rgba(...), hsl(...), color names like white, black ❌ Spacing: Bare px, rem, em values in padding, margin, gap ❌ Shadows: box-shadow: 0 1px 3px rgba(...) ❌ Borders: border: 1px solid #ddd ❌ Gradients: linear-gradient(...) with literal colors
Common token mistakes:
❌ var(--op_color_primary_base) - Wrong separator (underscore instead of hyphen) ❌ var(--color-primary-base) - Missing --op- prefix ❌ var(--op-primary-color-base) - Wrong segment order
✅ var(--op-color-primary-base) - Correct format
Fix violations by replacing with tokens from assets/tokens.json
Block, Element, Modifier naming:
.block {
} /* Component base */
.block__element {
} /* Part of component */
.block--modifier {
} /* Variant of component */
.block__element--modifier {
} /* Variant of element */Nest modifiers and elements:
.card {
/* Base styles */
&.card--padded {
/* Modifier */
}
.card__header {
/* Element */
}
}File organization:
app/assets/stylesheets/components/{component-name}.cssapp/assets/stylesheets/components/overrides/{component-name}.cssapplication.scssComponent structure:
Example - Card component:
.card {
position: relative;
border-radius: var(--op-radius-medium);
background-color: var(--op-color-background);
box-shadow: var(--op-shadow-small);
/* Modifiers */
&.card--padded {
padding: var(--op-space-medium);
}
&.card--elevated {
box-shadow: var(--op-shadow-large);
}
/* Elements */
.card__header {
padding: var(--op-space-medium);
border-bottom: var(--op-border-width) solid var(--op-color-border);
border-start-start-radius: var(--op-radius-medium);
border-start-end-radius: var(--op-radius-medium);
}
.card__body {
padding: var(--op-space-medium);
}
.card__footer {
padding: var(--op-space-medium);
border-top: var(--op-border-width) solid var(--op-color-border);
border-end-start-radius: var(--op-radius-medium);
border-end-end-radius: var(--op-radius-medium);
}
}Example - Button component:
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: var(--op-space-small) var(--op-space-medium);
font-size: var(--op-font-medium);
font-weight: var(--op-font-weight-medium);
border-radius: var(--op-radius-small);
border: var(--op-border-width) solid transparent;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
opacity: 0.9;
}
&.btn--large {
padding: var(--op-space-medium) var(--op-space-large);
font-size: var(--op-font-large);
}
&.btn--small {
padding: var(--op-space-x-small) var(--op-space-small);
font-size: var(--op-font-small);
}
&.btn--disabled,
&:disabled {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
}
&.btn--primary {
background-color: var(--op-color-primary-base);
color: var(--op-color-primary-on-base);
&:hover {
background-color: var(--op-color-primary-plus-two);
color: var(--op-color-primary-on-plus-two);
}
}
&.btn--secondary {
background-color: var(--op-color-neutral-base);
color: var(--op-color-neutral-on-base);
&:hover {
background-color: var(--op-color-neutral-plus-two);
color: var(--op-color-neutral-on-plus-two);
}
}
&.btn--outline {
background-color: transparent;
border-color: var(--op-color-border);
color: var(--op-color-neutral-on-plus-max);
&:hover {
border-color: var(--op-color-primary-base);
}
}First ensure there isn't an existing token that fits your need When tokens are missing, create component-specific ones:
Project-specific tokens (preferred for custom needs):
--{project-prefix}-{category}-{name}--ya-color-brand-accent for "Your App" projectToken categories:
--op-color-{name} or --{prefix}-color-{name}--op-space-{size} or --{prefix}-space-{size}--op-font-{property}-{value}--op-radius-{size}, --op-border-{property}--op-shadow-{size}Discovery workflow:
assets/components.json for existing componentapp/assets/stylesheets for project stylesToken workflow:
assets/tokens.json for appropriate tokenvar(--op-category-name)Component workflow:
components/ or components/overrides/application.scssSee assets/components.json for available Optics components and assets/tokens.json for all design tokens.
52c069a
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.