From 482f391fd12a64e484b2f2d243fbf3966db9ed2b Mon Sep 17 00:00:00 2001
From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
Date: Tue, 27 Oct 2026 17:35:37 +0800
Subject: [PATCH] fix(splash): Draw the wordmark as outlines so it can't swap
fonts
The splash set its wordmark in Inter, a web font with font-display: swap. When
the font arrived late (on a cold dev start the dev server took up to seconds to
serve it), the splash showed the system font first and switched to Inter just
before fading, so the word grew and shifted. It is now an inline SVG of the same
text in Inter 500, so it renders identically from the first frame. This replaces
the previous attempt, which only moved where the font faces load.
---
index.html | 8 +++++---
public/splash.css | 10 +++-------
src/styles/fonts.css | 4 ----
src/styles/global.css | 2 ++
4 files changed, 10 insertions(+), 14 deletions(-)
delete mode 100644 src/styles/fonts.css
diff --git a/index.html b/index.html
index a8060de6..43471baa 100644
--- a/index.html
+++ b/index.html
@@ -5,18 +5,20 @@
OpenIDEA
-
-
diff --git a/public/splash.css b/public/splash.css
index 217b6cb7..c905db33 100644
--- a/public/splash.css
+++ b/public/splash.css
@@ -17,22 +17,18 @@ body, .splash { background: #e9eaee; }
gap: 14px;
padding-bottom: 38px;
box-sizing: border-box;
- font: 500 15px/1.2 "Inter Variable", Inter, system-ui, -apple-system, sans-serif;
color: #6c707e;
- /* As on body: picking it up when the app CSS arrives would change the wordmark's weight. */
- -webkit-font-smoothing: antialiased;
-webkit-user-select: none;
user-select: none;
cursor: default;
animation: splash-in 240ms ease-out 120ms both;
transition: opacity 160ms ease-out;
- /* One compositing layer for its whole life: WebKit layers it only while the opacity animates,
- and the fade-out's fresh layer re-snaps the centred text, which then jumps up half a pixel. */
- will-change: opacity;
}
.splash.splash-out { opacity: 0; pointer-events: none; }
:root[data-theme^="dark"] .splash { color: #8c8f95; }
-.splash svg { width: 56px; height: 56px; }
+.splash-logo { width: 56px; height: 56px; }
+/* 15px Inter: 2048 units per em, the line box from ascender to descender. */
+.splash-wordmark { width: 73.2px; height: 18.15px; }
.splash-bar { width: 120px; height: 2px; border-radius: 1px; overflow: hidden; background: rgb(127 127 127 / 0.18); }
/* Fake progress: eases towards ~90% over the 4 s cap; hideSplash() fills it before fading out. */
.splash-bar > i {
diff --git a/src/styles/fonts.css b/src/styles/fonts.css
deleted file mode 100644
index b51f53f4..00000000
--- a/src/styles/fonts.css
+++ /dev/null
@@ -1,4 +0,0 @@
-/* Linked from index.html rather than imported by global.css, so the faces are known before the
- splash first paints: the dev server injects the app CSS only once the bundle runs. */
-@import "@fontsource-variable/inter";
-@import "@fontsource-variable/jetbrains-mono";
diff --git a/src/styles/global.css b/src/styles/global.css
index 3434d5a0..ba8dff29 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -1,3 +1,5 @@
+@import "@fontsource-variable/inter";
+@import "@fontsource-variable/jetbrains-mono";
@import "./tokens.css";
/* Monochrome icons default to the theme icon grey; callers override for selected / disabled. */