K2F Style Operations - Detailed Guide
This guide covers advanced styling operations for K2F theme files.
Theme Structure
The theme.json file contains all visual styling definitions:
{
"palette": {},
"primitives": {},
"roles": {},
"font_aliases": {},
"modifiers": {}
}
Palette
Named color strings used throughout the theme:
{
"palette": {
"black": "#000000",
"white": "#FFFFFF",
"gray_800": "#333333",
"primary": "#0066CC"
}
}
Usage: Reference by name in roles: "color": "gray_800"
Roles
Role → base style mapping. Every role used in content MUST be defined here.
Basic Role Structure
{
"roles": {
"body": {
"font_family": "default",
"font_size": 12000, // 12pt in fixed-point (1/1000 pt)
"line_height_mult": 1200, // 1.2x multiplier (1/1000 units)
"color": "black", // Palette key or hex
"text_align": "start", // "start" | "center" | "end" | "justify"
"box_decoration": {}, // Optional box styling
"variants": {} // Optional variant definitions
}
}
}
Required Fields
font_family: String (must match font_aliases or be "default")font_size: Integer (fixed-point Pt, 1/1000 pt units)line_height_mult: Integer (multiplier in 1/1000 units, e.g., 1200 = 1.2x)color: String (palette key or hex color)
Optional Fields
text_align: "start" | "center" | "end" | "justify" (default: "start"; justify expands U+0020 gaps on non-final wrapped lines)first_line_indent_pt: Integer (non-negative millipt; first wrapped line only)letter_spacing_pt: Integer (extra glyph advance in 1/1000 pt; may be negative; officialh1uses-500)bold/italic: Boolean (defaultfalse)self_align: "start" | "center" | "end" | "stretch" — overrides parent stackalign_itemsfor this itemlist_style: Optional list layout tokens (see below)box_decoration: Box decoration object (see Visual Primitives)variants: Object mapping variant names to style overrides
Letter spacing, self_align, list_style
{
"roles": {
"h1": {
"font_family": "default",
"font_size": 28000,
"line_height_mult": 1200,
"letter_spacing_pt": -500,
"color": "ink"
},
"button": {
"font_family": "default",
"font_size": 12000,
"line_height_mult": 1200,
"color": "ink",
"self_align": "start"
},
"list_item": {
"font_family": "default",
"font_size": 12000,
"line_height_mult": 1400,
"color": "ink",
"list_style": {
"marker_box_width_pt": 18000,
"marker_gap_pt": 6000,
"depth_indent_pt": 18000,
"marker_align": "end",
"bullet_glyph": "•",
"number_suffix": "."
}
}
}
}
list_style fields are optional; see schema/styles.schema.json $defs/list_style. Variants may override self_align or list_style.
Variants
Variants switch visual appearance without changing semantic role:
{
"roles": {
"card": {
"font_family": "default",
"font_size": 12000,
"line_height_mult": 1200,
"color": "black",
"variants": {
"glass": {
"box_decoration": {
"background": "glass_light",
"blur": "background",
"border": "subtle",
"corner_radius": "medium"
}
},
"raised": {
"box_decoration": {
"background": "paper",
"shadow": "elevation.1",
"corner_radius": "medium"
}
}
}
}
}
}
Usage in content:
{
"id": "root.card1",
"role": "card",
"variant": "glass" // Applies glass variant styling
}
Visual Primitives
Named reusable visual atoms in primitives. Colors live only in palette (there is no primitives.colors).
Surfaces (Fills)
{
"primitives": {
"surfaces": {
"glass_light": {
"type": "solid",
"color": "#FFFFFFCC"
},
"sunrise": {
"type": "linear_gradient",
"value": {
"type": "linear",
"angle_degrees": 90,
"stops": [
{ "pos": 0, "color": "#FF6B6B" },
{ "pos": 1000, "color": "#FFE66D" }
]
}
}
}
}
}
Gradients
{
"primitives": {
"gradients": {
"sunrise": {
"type": "linear",
"angle_degrees": 90,
"stops": [
{ "pos": 0, "color": "#FF6B6B" },
{ "pos": 500, "color": "#FFE66D" },
{ "pos": 1000, "color": "#FFFFFF" }
]
}
}
}
}
Gradient rules:
angle_degrees: 0-360 (0 = horizontal right, 90 = vertical down)stops: Array of{pos: 0-1000, color: string}pos: 0 = start, 1000 = end
Corners / Borders
{
"primitives": {
"corners": { "none": 0, "small": 4000, "medium": 12000, "large": 24000, "full": 9999000 },
"borders": {
"subtle": { "width_pt": 500, "color": "#1111111A" },
"contrast": { "width_pt": 1000, "color": "#1111114D" }
}
}
}
Shadows
{
"primitives": {
"shadows": {
"elevation.1": {
"layers": [
{
"offset_x_pt": 0,
"offset_y_pt": 2000,
"blur_radius_pt": 4000,
"spread_radius_pt": 0,
"color": "#0000001A"
}
]
},
"elevation.3": {
"layers": [
{
"offset_x_pt": 0,
"offset_y_pt": 8000,
"blur_radius_pt": 24000,
"spread_radius_pt": 0,
"color": "#00000033"
},
{
"offset_x_pt": 0,
"offset_y_pt": 4000,
"blur_radius_pt": 4000,
"spread_radius_pt": 0,
"color": "#00000026"
}
]
}
}
}
}
Shadow rules:
layers: Array of shadow layers (stacked)- All values in fixed-point Pt (1/1000 pt units)
color: Hex with alpha (e.g., "#00000020" = 20% opacity)
Blurs
{
"primitives": {
"blurs": {
"background": {
"radius_pt": 20000
}
}
}
}
Box Decoration
Theme-side decoration uses named refs only (inline fill/shadow/blur/border objects fail schema):
{
"box_decoration": {
"background": "glass_light",
"border": "subtle",
"corner_radius": "medium",
"padding_pt": 24000,
"shadow": "elevation.1",
"blur": "background"
}
}
padding_pt may be a uniform integer or { top, right, bottom, left }. Compile resolves names into an inlined lock BoxDecoration.
Modifiers
Modifier styling configuration:
{
"modifiers": {
"precedence": [
"emphasis",
"link",
"underline",
"strikethrough"
],
"styles": {
"emphasis": {
"critical": {
"bold": true,
"color": "#CC0000"
},
"important": {
"bold": true
}
},
"syntax_highlight": {
"warning": {
"color": "#FFE5E5"
}
}
}
}
}
Structure:
precedence: Array of modifier types (low → high priority)styles: Modifier type → intent → text style patch
Text style patch fields:
font_family: String | nullfont_size: Integer | nullline_height_mult: Integer | nullletter_spacing_pt: Integer | nullcolor: String | nulltext_align: "start" | "center" | "end" | "justify" | nullbold: Boolean | nullitalic: Boolean | nullstrikethrough: Boolean | nullunderline: Boolean | null
Font Aliases
Map human-readable font names to loaded font keys:
{
"font_aliases": {
"Helvetica": "default",
"Roboto": "default",
"Times": "serif_font"
}
}
Usage: Reference in roles: "font_family": "Helvetica"
Style Update Operations
Update Role Base Style
// In theme.json
{
"roles": {
"body": {
"font_size": 14000, // Changed from 12000 to 14pt
"color": "gray_800" // Changed color
}
}
}
Add New Role
{
"roles": {
"h2": {
"font_family": "default",
"font_size": 24000, // 24pt
"line_height_mult": 1200,
"color": "black",
"bold": true
}
}
}
Add Variant to Existing Role
{
"primitives": {
"borders": {
"bordered": { "width_pt": 2000, "color": "#CCCCCC" }
}
},
"roles": {
"card": {
"variants": {
"bordered": {
"box_decoration": {
"border": "bordered"
}
}
}
}
}
}
Add Primitive
{
"palette": {
"accent.primary": "#0066CC"
},
"primitives": {
"surfaces": {
"surface.elevated": {
"type": "solid",
"color": "#FFFFFF"
}
},
"shadows": {
"elevation.2": {
"layers": [
{
"offset_x_pt": 0,
"offset_y_pt": 4000,
"blur_radius_pt": 8000,
"spread_radius_pt": 0,
"color": "#00000020"
}
]
}
}
}
}
Best Practices
- Use Primitives: Theme
box_decorationis named-only — no inline fill/shadow/blur/border objects - Naming: Prefer official atoms:
glass_light,elevation.1,corners.medium,blurs.background - Fixed-Point: All Pt values in 1/1000 pt units (integers)
- Color Format: Use hex with alpha: "#RRGGBBAA" or "#RRGGBB"
- Variants: Use variants for visual skins, not new roles
- Validate: Check against
schema/styles.schema.jsonandschema/visual_primitives.schema.json
Common Errors to Avoid
- Missing required role fields: Always include font_family, font_size, line_height_mult, color
- Decimal Pt values: Use integers (12000 not 12.0)
- Invalid color format: Use hex strings or palette keys
- Undefined role: Role must exist before use in content
- Undefined variant: Variant must exist in role.variants
- Invalid primitive reference: Primitive must exist before referencing