package main import engine "shared:zephr" // Material 3 design tokens. // // Baseline dark scheme, verbatim from the M3 spec. Sizes are dp and type sizes // are sp, which are the same thing here because layout points are dp. // // Two spec notes that shape everything below: // - M3 conveys elevation with surface *colour*, not shadow. The engine draws // no shadows, and it does not need to: the container roles below are the // real mechanism. // - Corner radii are uniform. The engine's border_radius is a single float, // so shapes needing per-corner radii (segmented button ends) are noted. // -- Colour roles ------------------------------------------------------------ hex :: proc(v: u32, a: f32 = 1) -> engine.Color { return { f32((v >> 16) & 0xFF) / 255, f32((v >> 8) & 0xFF) / 255, f32(v & 0xFF) / 255, a, } } M3 :: struct { primary, on_primary, primary_container, on_primary_container: engine.Color, secondary, on_secondary, secondary_container, on_secondary_container: engine.Color, tertiary, on_tertiary, tertiary_container, on_tertiary_container: engine.Color, error, on_error, error_container, on_error_container: engine.Color, surface, on_surface, surface_variant, on_surface_variant: engine.Color, surface_c_lowest, surface_c_low, surface_c, surface_c_high, surface_c_highest: engine.Color, outline, outline_variant: engine.Color, inverse_surface, inverse_on_surface, inverse_primary: engine.Color, scrim: engine.Color, } m3: M3 m3_init_dark :: proc() { m3.primary = hex(0xD0BCFF) m3.on_primary = hex(0x381E72) m3.primary_container = hex(0x4F378B) m3.on_primary_container = hex(0xEADDFF) m3.secondary = hex(0xCCC2DC) m3.on_secondary = hex(0x332D41) m3.secondary_container = hex(0x4A4458) m3.on_secondary_container = hex(0xE8DEF8) m3.tertiary = hex(0xEFB8C8) m3.on_tertiary = hex(0x492532) m3.tertiary_container = hex(0x633B48) m3.on_tertiary_container = hex(0xFFD8E4) m3.error = hex(0xF2B8B5) m3.on_error = hex(0x601410) m3.error_container = hex(0x8C1D18) m3.on_error_container = hex(0xF9DEDC) m3.surface = hex(0x141218) m3.on_surface = hex(0xE6E0E9) m3.surface_variant = hex(0x49454F) m3.on_surface_variant = hex(0xCAC4D0) // The elevation ladder. Higher role == "further from the surface". m3.surface_c_lowest = hex(0x0F0D13) m3.surface_c_low = hex(0x1D1B20) m3.surface_c = hex(0x211F26) m3.surface_c_high = hex(0x2B2930) m3.surface_c_highest = hex(0x36343B) m3.outline = hex(0x938F99) m3.outline_variant = hex(0x49454F) m3.inverse_surface = hex(0xE6E0E9) m3.inverse_on_surface = hex(0x322F35) m3.inverse_primary = hex(0x6750A4) m3.scrim = hex(0x000000) } // State layer opacities, applied over a container colour. M3_STATE_HOVER :: f32(0.08) M3_STATE_FOCUS :: f32(0.10) M3_STATE_PRESSED :: f32(0.10) M3_DISABLED_FG :: f32(0.38) M3_DISABLED_BG :: f32(0.12) // Composites a state layer over a base colour, which is how M3 defines every // hover/press appearance rather than by naming separate colours. m3_state_layer :: proc(base: engine.Color, layer: engine.Color, opacity: f32) -> engine.Color { return { base.r + (layer.r - base.r) * opacity, base.g + (layer.g - base.g) * opacity, base.b + (layer.b - base.b) * opacity, base.a, } } m3_alpha :: proc(c: engine.Color, a: f32) -> engine.Color { return {c.r, c.g, c.b, a} } // -- Type scale (sp) --------------------------------------------------------- M3_DISPLAY_SMALL :: 36 M3_HEADLINE_MEDIUM :: 28 M3_HEADLINE_SMALL :: 24 M3_TITLE_LARGE :: 22 M3_TITLE_MEDIUM :: 16 M3_TITLE_SMALL :: 14 M3_BODY_LARGE :: 16 M3_BODY_MEDIUM :: 14 M3_BODY_SMALL :: 12 M3_LABEL_LARGE :: 14 M3_LABEL_MEDIUM :: 12 M3_LABEL_SMALL :: 11 // Roboto weights the M3 type scale uses. Title/label roles are medium (500). M3_WEIGHT_REGULAR :: f32(400) M3_WEIGHT_MEDIUM :: f32(500) // -- Shape scale (dp) -------------------------------------------------------- M3_SHAPE_XS :: 4 M3_SHAPE_SM :: 8 M3_SHAPE_MD :: 12 M3_SHAPE_LG :: 16 M3_SHAPE_XL :: 28 M3_SHAPE_FULL :: 9999 // clamped by the widget's half-height // -- Icon codepoints --------------------------------------------------------- // // Written as byte escapes rather than literal glyphs: these live in the Private // Use Area, so they are invisible in an editor and are silently lost by tools // that do not round-trip them. The codepoint in each comment is the source of // truth, and must stay in step with the pyftsubset --unicodes list. ICON_ARROW_BACK :: "\xEE\x97\x84" // U+E5C4 arrow_back ICON_MENU :: "\xEE\x97\x92" // U+E5D2 menu ICON_MORE_VERT :: "\xEE\x97\x94" // U+E5D4 more_vert ICON_SEARCH :: "\xEE\xA2\xB6" // U+E8B6 search ICON_CHECK :: "\xEE\x97\x8A" // U+E5CA check ICON_CLOSE :: "\xEE\x97\x8D" // U+E5CD close ICON_ADD :: "\xEE\x85\x85" // U+E145 add ICON_HOME :: "\xEE\xA2\x8A" // U+E88A home ICON_FAVORITE :: "\xEE\xA1\xBD" // U+E87D favorite ICON_SETTINGS :: "\xEE\xA2\xB8" // U+E8B8 settings ICON_EDIT :: "\xEE\x8F\x89" // U+E3C9 edit ICON_DELETE :: "\xEE\xA1\xB2" // U+E872 delete ICON_PERSON :: "\xEE\x9F\xBD" // U+E7FD person ICON_STAR :: "\xEE\xA0\xB8" // U+E838 star ICON_SHARE :: "\xEE\xA0\x8D" // U+E80D share ICON_DOWNLOAD :: "\xEE\x8B\x84" // U+E2C4 download ICON_BOOKMARK :: "\xEE\xA1\xA6" // U+E866 bookmark ICON_NOTIFICATIONS :: "\xEE\x9F\xB4" // U+E7F4 notifications ICON_EXPAND_MORE :: "\xEE\x97\x8F" // U+E5CF expand_more