From 80d5a57b5dcfa33e3a697488b96562198fa58e59 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Wed, 18 Feb 2026 12:53:08 +0100 Subject: [PATCH] feat(client): introduce Michroma font and implant UI theme (#517) Add Michroma-Regular.ttf (OFL license) as the game font. Create FontVariation with +1px tracking and a global Theme resource with cyan-white (#E0F7FA) implant text color. Wire theme into project.godot so all Label/RichTextLabel/Button/LineEdit nodes inherit automatically. Add IMPLANT_TEXT_COLOR/DIM/PULSE constants to constants.gd. Co-Authored-By: Claude Opus 4.6 --- client/assets/fonts/Michroma-Regular.ttf | Bin 0 -> 64344 bytes client/assets/fonts/OFL.txt | 93 +++++++++++++++++++++++ client/assets/fonts/michroma_ui.tres | 8 ++ client/assets/theme/game_theme.tres | 20 +++++ client/project.godot | 5 ++ client/scripts/constants.gd | 7 ++ client/ui/interaction_list.gd | 4 +- 7 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 client/assets/fonts/Michroma-Regular.ttf create mode 100644 client/assets/fonts/OFL.txt create mode 100644 client/assets/fonts/michroma_ui.tres create mode 100644 client/assets/theme/game_theme.tres diff --git a/client/assets/fonts/Michroma-Regular.ttf b/client/assets/fonts/Michroma-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..59e8c534349962143f45b48152f80524fe9045bc GIT binary patch literal 64344 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 literal 0 HcmV?d00001 diff --git a/client/assets/fonts/OFL.txt b/client/assets/fonts/OFL.txt new file mode 100644 index 000000000..2d0610cd9 --- /dev/null +++ b/client/assets/fonts/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2011 The Michroma Project Authors (https://github.com/googlefonts/Michroma-font) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/client/assets/fonts/michroma_ui.tres b/client/assets/fonts/michroma_ui.tres new file mode 100644 index 000000000..4ae6c6b2f --- /dev/null +++ b/client/assets/fonts/michroma_ui.tres @@ -0,0 +1,8 @@ +[gd_resource type="FontVariation" load_steps=2 format=3] + +[ext_resource type="FontFile" path="res://assets/fonts/Michroma-Regular.ttf" id="1_base"] + +[resource] +base_font = ExtResource("1_base") +spacing_glyph = 1 +spacing_space = 1 diff --git a/client/assets/theme/game_theme.tres b/client/assets/theme/game_theme.tres new file mode 100644 index 000000000..524d5eda7 --- /dev/null +++ b/client/assets/theme/game_theme.tres @@ -0,0 +1,20 @@ +[gd_resource type="Theme" load_steps=2 format=3] + +[ext_resource type="FontVariation" path="res://assets/fonts/michroma_ui.tres" id="1_font"] + +[resource] +default_font = ExtResource("1_font") +default_font_size = 14 + +Label/colors/font_color = Color(0.878, 0.969, 0.98, 1) +Label/font_sizes/font_size = 14 + +RichTextLabel/colors/default_color = Color(0.878, 0.969, 0.98, 1) +RichTextLabel/font_sizes/normal_font_size = 14 + +Button/colors/font_color = Color(0.878, 0.969, 0.98, 1) +Button/colors/font_hover_color = Color(0.91, 0.773, 0.278, 1) +Button/font_sizes/font_size = 14 + +LineEdit/colors/font_color = Color(0.878, 0.969, 0.98, 1) +LineEdit/font_sizes/font_size = 14 diff --git a/client/project.godot b/client/project.godot index 717e5c35f..7c46700bd 100644 --- a/client/project.godot +++ b/client/project.godot @@ -24,6 +24,11 @@ UIStrings="*res://scripts/autoloads/ui_strings.gd" FogState="*res://scripts/autoloads/fog_state.gd" AudioManager="*res://scripts/autoloads/audio_manager.gd" +[gui] + +theme/custom="res://assets/theme/game_theme.tres" +theme/custom_font="res://assets/fonts/michroma_ui.tres" + [display] window/size/viewport_width=1920 diff --git a/client/scripts/constants.gd b/client/scripts/constants.gd index 45df4f0b7..9acda78e1 100644 --- a/client/scripts/constants.gd +++ b/client/scripts/constants.gd @@ -80,3 +80,10 @@ const PERIPHERAL_ALPHA: float = 0.5 # Facing direction indicator const FACING_INDICATOR_SIZE: float = 6.0 const FACING_INDICATOR_OFFSET: float = 14.0 + +# #517: Implant UI font color grading — avoid pure white, project through a lens +const IMPLANT_TEXT_COLOR: Color = Color("#E0F7FA") # Cyan-white — primary text +const IMPLANT_TEXT_DIM: Color = Color("#9EBFC4") # Dimmed variant — secondary text +const IMPLANT_PULSE_MIN: float = 0.85 # Alpha pulse floor +const IMPLANT_PULSE_MAX: float = 1.0 # Alpha pulse ceiling +const IMPLANT_PULSE_PERIOD: float = 2.5 # Seconds per pulse cycle diff --git a/client/ui/interaction_list.gd b/client/ui/interaction_list.gd index 8758f39d5..a36fd7515 100644 --- a/client/ui/interaction_list.gd +++ b/client/ui/interaction_list.gd @@ -16,8 +16,8 @@ const FADE_IN := 0.12 const FADE_OUT := 0.10 const LABEL_HEIGHT := 22 const LABEL_GAP := 2 -const INSERT_FG := Color("#c8d0e0") -const INSERT_DIM := Color("#8b8ba0") +const INSERT_FG := Constants.IMPLANT_TEXT_COLOR +const INSERT_DIM := Constants.IMPLANT_TEXT_DIM const INSERT_BG := Color(0.05, 0.05, 0.08, 0.7) var _showing: bool = false