Initial commit: NexusOS project + desktop theme baseline

Captures the known-good state after theme consolidation and
consistency reconciliation:
- NexusOS GTK/xfwm4/icon theme assets (assets/themes, management/Mint-Y-Nexus)
- Tightened right-click menus, visible separators, no menu icons
- assets/themes/install-theme.sh: idempotent restore of all wiring
  (symlinks, xfconf xsettings+xfwm4, GTK 3/4 settings.ini)
- .gitignore excludes venv/ollama/models/runtime/db

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
jon
2026-05-18 13:39:48 -05:00
commit b0aa0438af
1264 changed files with 19255 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

+29
View File
@@ -0,0 +1,29 @@
#!/bin/sh
# Bakes a real, dereferenced copy of the NexusOS Plymouth theme into the
# initramfs. The theme files live in nexus-core and are exposed at
# /usr/share/plymouth/themes/my-custom-logo via a symlink into /home, which
# the stock initramfs plymouth hook copies verbatim -> it dangles at early
# boot (before /home is mounted) and Plymouth falls back to text mode.
# This hook runs after the stock "plymouth" hook and replaces that dangling
# symlink with the actual theme files.
PREREQS="plymouth"
prereqs() { echo "$PREREQS"; }
case "$1" in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
THEME_SRC="/home/jon/nexus-core/assets/boot/my-custom-logo"
THEME_DEST="${DESTDIR}/usr/share/plymouth/themes/my-custom-logo"
[ -d "${THEME_SRC}" ] || exit 0
rm -rf "${THEME_DEST}"
mkdir -p "${THEME_DEST}"
cp -aL "${THEME_SRC}/." "${THEME_DEST}/"
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

@@ -0,0 +1,54 @@
[Plymouth Theme]
Name=My Custom Logo
Description=Custom boot logo with shimmer effect
ModuleName=two-step
[two-step]
Font=Cantarell 12
TitleFont=Cantarell Light 30
ImageDir=/usr/share/plymouth/themes/my-custom-logo
DialogHorizontalAlignment=.5
DialogVerticalAlignment=.382
TitleHorizontalAlignment=.5
TitleVerticalAlignment=.382
HorizontalAlignment=.5
VerticalAlignment=.5
WatermarkHorizontalAlignment=.5
WatermarkVerticalAlignment=.96
Transition=none
TransitionDuration=0.0
BackgroundStartColor=0x000000
BackgroundEndColor=0x000000
ProgressBarBackgroundColor=0x606060
ProgressBarForegroundColor=0xffffff
MessageBelowAnimation=true
[boot-up]
UseEndAnimation=false
[shutdown]
UseEndAnimation=false
[reboot]
UseEndAnimation=false
[updates]
SuppressMessages=true
ProgressBarShowPercentComplete=true
UseProgressBar=true
Title=Installing Updates...
SubTitle=Do not turn off your computer
[system-upgrade]
SuppressMessages=true
ProgressBarShowPercentComplete=true
UseProgressBar=true
Title=Upgrading System...
SubTitle=Do not turn off your computer
[firmware-upgrade]
SuppressMessages=true
ProgressBarShowPercentComplete=true
UseProgressBar=true
Title=Upgrading Firmware...
SubTitle=Do not turn off your computer
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.9 KiB

+24
View File
@@ -0,0 +1,24 @@
# Theme Asset Credits
The NexusOS theme is assembled from original work plus assets adapted from the following upstream projects. All upstream sources are GPL-3.0 (or compatible), so the NexusOS theme inherits GPL-3.0.
## Sources
### WhiteSur GTK Theme — `gtk-2.0/`, `xfwm4/`
- **Project**: https://github.com/vinceliuice/WhiteSur-gtk-theme
- **Author**: Vince Liu (vinceliuice)
- **License**: GPL-3.0
- **Variant used as base**: `WhiteSur-Dark-purple`
- **What we use**: The entire `gtk-2.0/` and `xfwm4/` directories are cloned verbatim from WhiteSur-Dark-purple. We rely on these for macOS-style window controls (stoplight buttons) and the GTK2 application skin.
### Mint-Y Icon Theme — `NexusOS-icons/` (folder geometry reference)
- **Project**: https://github.com/linuxmint/mint-y-icons
- **Author**: Linux Mint team
- **License**: GPL-3.0
- **What we use**: Visual reference only for the folder shape language (flat folder with tab + lip). No PNGs are copied from Mint-Y; our folder set is regenerated from scratch via `NexusOS-icons-src/build.py` against a master SVG we authored.
## NexusOS-original content
- `gtk-3.0/*.css` — original work
- `NexusOS-icons-src/*` and the rendered output in `NexusOS-icons/places/` — original work
- The `n-small.png` badge composited into `folder-nexus-core` is the NexusOS logo at `nexus-core/assets/n-small.png`
- `index.theme` files in each theme directory — original work
+23
View File
@@ -0,0 +1,23 @@
NexusOS theme assets — attribution and license
================================================
The NexusOS GTK2 and xfwm4 themes are derived from Mint-Y-Dark-Aqua,
part of the mint-themes package shipped by Linux Mint.
Upstream:
https://github.com/linuxmint/mint-themes
Copyright (c) 2017-2024 Linux Mint <root@linuxmint.com>
Licensed under the GNU General Public License v3.0 or later.
Derivative work in this directory:
- NexusOS/gtk-2.0/ (PNGs recolored from Mint-Y-Dark-Aqua/gtk-2.0/)
- NexusOS/xfwm4/ (PNGs recolored from Mint-Y-Dark-Aqua/xfwm4/)
- NexusOS-gtk2-src/ (build script that performs the recolor)
- NexusOS-xfwm4-src/ (build script that performs the recolor)
As a derivative of GPLv3 material, these files are likewise distributed
under the terms of the GNU General Public License version 3 or later. See
https://www.gnu.org/licenses/gpl-3.0.html for the full license text.
The NexusOS GTK3 theme (NexusOS/gtk-3.0/) and the NexusOS icon set
(NexusOS-icons*/) are original works and not derived from Mint-Y.
+163
View File
@@ -0,0 +1,163 @@
#!/usr/bin/env python3
"""Build NexusOS GTK2 theme from Mint-Y-Dark-Aqua base.
- Copies .rc files + assets/ from /usr/share/themes/Mint-Y-Dark-Aqua/gtk-2.0/
- Recolors PNGs containing the Aqua accent (#1f9ede) to NexusOS green (#8cc63f)
- Rewrites the gtk-color-scheme block in gtkrc to NexusOS palette
- Replaces remaining aqua hex literals in .rc files
"""
from __future__ import annotations
import colorsys
import shutil
import sys
from pathlib import Path
THEMES_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(THEMES_ROOT))
import _palette as P # noqa: E402
from PIL import Image # noqa: E402
SRC = Path("/usr/share/themes/Mint-Y-Dark-Aqua/gtk-2.0")
OUT = THEMES_ROOT / "NexusOS" / "gtk-2.0"
AQUA_RGB = (0x1F, 0x9E, 0xDE)
AQUA_HSV = colorsys.rgb_to_hsv(*(c / 255 for c in AQUA_RGB))
GREEN_HSV = P.hex_to_hsv(P.BRAND_GREEN)
HUE_TOLERANCE = 30 / 360
SAT_FLOOR = 0.18
S_SCALE = GREEN_HSV[1] / AQUA_HSV[1]
V_SCALE = GREEN_HSV[2] / AQUA_HSV[2]
def hue_distance(a: float, b: float) -> float:
d = abs(a - b)
return min(d, 1 - d)
def recolor_pixel(r: int, g: int, b: int, a: int) -> tuple[int, int, int, int]:
if a < 8:
return (r, g, b, a)
h, s, v = colorsys.rgb_to_hsv(r / 255, g / 255, b / 255)
if s < SAT_FLOOR or hue_distance(h, AQUA_HSV[0]) > HUE_TOLERANCE:
return (r, g, b, a)
new_s = min(1.0, s * S_SCALE)
new_v = min(1.0, v * V_SCALE)
nr, ng, nb = colorsys.hsv_to_rgb(GREEN_HSV[0], new_s, new_v)
return (round(nr * 255), round(ng * 255), round(nb * 255), a)
def recolor_png(path: Path) -> int:
"""Recolor aqua pixels in-place. Returns count of pixels changed."""
im = Image.open(path).convert("RGBA")
px = im.load()
w, h = im.size
changed = 0
for y in range(h):
for x in range(w):
r, g, b, a = px[x, y]
new = recolor_pixel(r, g, b, a)
if new != (r, g, b, a):
px[x, y] = new
changed += 1
if changed:
im.save(path, optimize=True)
return changed
# ── gtkrc color-scheme block ──────────────────────────────────────────
NEW_COLOR_SCHEME = (
f"base_color:#{P.BASE_BG}\\n"
f"fg_color:#{P.TEXT_PRIMARY}\\n"
f"tooltip_fg_color:#{P.TEXT_PRIMARY}\\n"
f"selected_bg_color:#{P.BRAND_PURPLE_DARK}\\n"
f"selected_fg_color:#{P.TEXT_ON_SELECTION}\\n"
f"text_color:#{P.TEXT_PRIMARY}\\n"
f"bg_color:#{P.SURFACE_BG}\\n"
f"insensitive_bg_color:#{P.SURFACE_BG}\\n"
f"insensitive_fg_color:#{P.TEXT_DISABLED}\\n"
f"notebook_bg:#{P.BASE_BG}\\n"
f"dark_sidebar_bg:#{P.SURFACE_BG_ALT}\\n"
f"tooltip_bg_color:#{P.OVERLAY_BG}\\n"
f"link_color:#{P.BRAND_GREEN_LIGHT}\\n"
f"menu_bg:#{P.SURFACE_BG}\\n"
f"menu_separator_color:#{P.BORDER}"
)
def patch_gtkrc(path: Path) -> None:
text = path.read_text()
out_lines = []
for line in text.splitlines():
if line.startswith("gtk-color-scheme"):
out_lines.append(f'gtk-color-scheme = "{NEW_COLOR_SCHEME}"')
else:
out_lines.append(line)
path.write_text("\n".join(out_lines) + "\n")
# ── Remaining hex literals in .rc files ───────────────────────────────
# Captured from Mint-Y-Dark-Aqua; map source hex → NexusOS replacement.
RC_HEX_REPLACEMENTS = {
# accent / focus / selection
"#1f9ede": f"#{P.BRAND_GREEN}",
"#1F9EDE": f"#{P.BRAND_GREEN}",
"#5294E2": f"#{P.BRAND_GREEN_LIGHT}", # link_color fallback if quoted literal
"#5294e2": f"#{P.BRAND_GREEN_LIGHT}",
# Mint-Y greys we want to nudge onto our surface family
"#2b2b2b": f"#{P.SURFACE_BG_ALT}",
"#383838": f"#{P.SURFACE_BG}",
"#404040": f"#{P.BASE_BG}",
"#3e3e3e": f"#{P.SURFACE_BG}",
"#dadada": f"#{P.TEXT_PRIMARY}",
"#DADADA": f"#{P.TEXT_PRIMARY}",
"#d3d3d3": f"#{P.TEXT_PRIMARY}",
"#D3D3D3": f"#{P.TEXT_PRIMARY}",
}
def patch_rc(path: Path) -> int:
text = path.read_text()
count = 0
for src, dst in RC_HEX_REPLACEMENTS.items():
n = text.count(src)
if n:
text = text.replace(src, dst)
count += n
path.write_text(text)
return count
def main() -> None:
if OUT.exists():
shutil.rmtree(OUT)
shutil.copytree(SRC, OUT)
print(f"Copied {SRC}{OUT}")
# Recolor PNGs
recolored = 0
for png in sorted((OUT / "assets").glob("*.png")):
changed = recolor_png(png)
if changed:
recolored += 1
print(f" recolored {png.name}: {changed}px")
print(f"Recolored {recolored} PNGs")
# Patch rc files
patched_total = 0
for rc in sorted(OUT.glob("*.rc")):
n = patch_rc(rc)
if n:
print(f" patched {rc.name}: {n} replacements")
patched_total += n
gtkrc = OUT / "gtkrc"
patch_rc(gtkrc)
patch_gtkrc(gtkrc)
print(f"Rewrote gtkrc color scheme; total .rc hex replacements: {patched_total}")
if __name__ == "__main__":
main()
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 955 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Some files were not shown because too many files have changed in this diff Show More