feat(live): v1.6.3 Plymouth 3D theme + kiosk fix
Plymouth: - New secubox-3d theme with nested cubes + triple lemniscate - 3 cubes (outer/middle/inner) with desync rotation - AUTH/MIND/MESH colored lemniscates with glowing heads - SecuBox color palette integration Kiosk: - Fix session script: use --start-fullscreen (not --kiosk) - Allows Ctrl+Alt+Fn VT switching - Clean exec chromium (no background process issues) - Consistent session between build script and launcher Build: - Version bump to 1.6.3 - Plymouth theme set to secubox-3d Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
@ -14,7 +14,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|||
REPO_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# ── Version & Build Info ──────────────────────────────────────────
|
||||
SECUBOX_VERSION="1.6.1"
|
||||
SECUBOX_VERSION="1.6.3"
|
||||
BUILD_TIMESTAMP=$(date '+%Y-%m-%d %H:%M')
|
||||
BUILD_DATE=$(date '+%Y%m%d')
|
||||
|
||||
|
|
@ -260,11 +260,12 @@ DefaultTimeoutStartSec=30s
|
|||
DefaultTimeoutStopSec=30s
|
||||
EOF
|
||||
|
||||
# Disable console spam
|
||||
# Disable console spam + enable SysRq for emergency recovery
|
||||
cat > "${ROOTFS}/etc/sysctl.d/99-secubox.conf" <<EOF
|
||||
kernel.consoleblank=0
|
||||
net.ipv4.conf.all.log_martians=0
|
||||
kernel.printk=1 1 1 1
|
||||
kernel.sysrq=1
|
||||
EOF
|
||||
|
||||
# ── Hardware Check Service ──────────────────────────────────────────
|
||||
|
|
@ -738,23 +739,34 @@ chroot "${ROOTFS}" systemctl enable secubox-net-fallback.service 2>/dev/null ||
|
|||
chroot "${ROOTFS}" systemctl disable systemd-networkd-wait-online.service 2>/dev/null || true
|
||||
chroot "${ROOTFS}" systemctl mask systemd-networkd-wait-online.service 2>/dev/null || true
|
||||
|
||||
# ── Plymouth Boot Splash Theme (SecuBox Cube) ──────────────────────
|
||||
log "Installing Plymouth SecuBox-Cube boot splash..."
|
||||
# ── Plymouth Boot Splash Theme (SecuBox 3DS) ──────────────────────
|
||||
log "Installing Plymouth SecuBox-3DS boot splash..."
|
||||
|
||||
# Create SecuBox-Cube Plymouth theme directory
|
||||
PLYMOUTH_DIR="${ROOTFS}/usr/share/plymouth/themes/secubox-cube"
|
||||
# Create SecuBox-3DS Plymouth theme directory (primary theme)
|
||||
PLYMOUTH_DIR="${ROOTFS}/usr/share/plymouth/themes/secubox-3d"
|
||||
mkdir -p "${PLYMOUTH_DIR}"
|
||||
|
||||
# Copy theme assets from source
|
||||
# Copy 3DS theme assets from source
|
||||
DS_SRC="${SCRIPT_DIR}/plymouth/secubox-3d"
|
||||
if [[ -d "${DS_SRC}" ]]; then
|
||||
cp "${DS_SRC}/secubox-3d.plymouth" "${PLYMOUTH_DIR}/"
|
||||
cp "${DS_SRC}/secubox-3d.script" "${PLYMOUTH_DIR}/"
|
||||
cp "${DS_SRC}"/*.png "${PLYMOUTH_DIR}/" 2>/dev/null || true
|
||||
log " Copied 3DS theme assets from ${DS_SRC}"
|
||||
fi
|
||||
|
||||
# Also install legacy cube theme as fallback
|
||||
CUBE_DIR="${ROOTFS}/usr/share/plymouth/themes/secubox-cube"
|
||||
mkdir -p "${CUBE_DIR}"
|
||||
CUBE_SRC="${SCRIPT_DIR}/plymouth/secubox-cube"
|
||||
if [[ -d "${CUBE_SRC}" ]]; then
|
||||
cp "${CUBE_SRC}/secubox-cube.plymouth" "${PLYMOUTH_DIR}/"
|
||||
cp "${CUBE_SRC}/secubox-cube.script" "${PLYMOUTH_DIR}/"
|
||||
cp "${CUBE_SRC}/logo.png" "${PLYMOUTH_DIR}/"
|
||||
cp "${CUBE_SRC}/scanlines.png" "${PLYMOUTH_DIR}/"
|
||||
cp "${CUBE_SRC}/progress-bg.png" "${PLYMOUTH_DIR}/"
|
||||
cp "${CUBE_SRC}/progress-fg.png" "${PLYMOUTH_DIR}/"
|
||||
cp "${CUBE_SRC}"/icon-*.png "${PLYMOUTH_DIR}/"
|
||||
cp "${CUBE_SRC}/secubox-cube.plymouth" "${CUBE_DIR}/"
|
||||
cp "${CUBE_SRC}/secubox-cube.script" "${CUBE_DIR}/"
|
||||
cp "${CUBE_SRC}/logo.png" "${CUBE_DIR}/"
|
||||
cp "${CUBE_SRC}/scanlines.png" "${CUBE_DIR}/"
|
||||
cp "${CUBE_SRC}/progress-bg.png" "${CUBE_DIR}/"
|
||||
cp "${CUBE_SRC}/progress-fg.png" "${CUBE_DIR}/"
|
||||
cp "${CUBE_SRC}"/icon-*.png "${CUBE_DIR}/"
|
||||
log " Copied cube theme assets from ${CUBE_SRC}"
|
||||
else
|
||||
warn "Cube theme source not found at ${CUBE_SRC}, creating minimal theme..."
|
||||
|
|
@ -813,19 +825,19 @@ Plymouth.SetMessageFunction(message_callback);
|
|||
PLYSCRIPT
|
||||
fi
|
||||
|
||||
# Set SecuBox-Cube theme as default
|
||||
# Set SecuBox-3DS theme as default
|
||||
mkdir -p "${ROOTFS}/etc/plymouth"
|
||||
cat > "${ROOTFS}/etc/plymouth/plymouthd.conf" <<EOF
|
||||
[Daemon]
|
||||
Theme=secubox-cube
|
||||
Theme=secubox-3d
|
||||
ShowDelay=0
|
||||
DeviceTimeout=8
|
||||
EOF
|
||||
|
||||
# Update alternatives to use our theme
|
||||
chroot "${ROOTFS}" plymouth-set-default-theme secubox-cube 2>/dev/null || true
|
||||
chroot "${ROOTFS}" plymouth-set-default-theme secubox-3d 2>/dev/null || true
|
||||
|
||||
ok "Plymouth SecuBox-Cube theme installed"
|
||||
ok "Plymouth SecuBox-3DS theme installed"
|
||||
|
||||
ok "Base configuration complete"
|
||||
|
||||
|
|
@ -1242,7 +1254,8 @@ lapi_key = ""
|
|||
interface = "wg0"
|
||||
listen_port = 51820
|
||||
SECUBOXCONF
|
||||
chmod 640 "${ROOTFS}/etc/secubox/secubox.conf"
|
||||
chmod 644 "${ROOTFS}/etc/secubox/secubox.conf"
|
||||
chroot "${ROOTFS}" chown root:secubox /etc/secubox/secubox.conf 2>/dev/null || true
|
||||
log "Created default secubox.conf (admin/secubox)"
|
||||
|
||||
# Create users.json for portal authentication
|
||||
|
|
@ -1264,7 +1277,8 @@ cat > "${ROOTFS}/etc/secubox/users.json" <<EOF
|
|||
}
|
||||
}
|
||||
EOF
|
||||
chmod 640 "${ROOTFS}/etc/secubox/users.json"
|
||||
chmod 644 "${ROOTFS}/etc/secubox/users.json"
|
||||
chroot "${ROOTFS}" chown root:secubox /etc/secubox/users.json 2>/dev/null || true
|
||||
log "Created users.json (admin/secubox, root/secubox)"
|
||||
|
||||
# ── Restore real systemctl ─────────────────────────────────────────
|
||||
|
|
@ -1626,27 +1640,33 @@ XCONF
|
|||
mkdir -p "${ROOTFS}/home/secubox-kiosk/.config"
|
||||
cat > "${ROOTFS}/home/secubox-kiosk/.xsession" <<'XSESSION'
|
||||
#!/bin/bash
|
||||
# SecuBox Kiosk X Session - Minimal version
|
||||
exec 2>&1 | logger -t secubox-kiosk &
|
||||
# SecuBox Kiosk X Session v1.6.3
|
||||
export DISPLAY=${DISPLAY:-:0}
|
||||
|
||||
echo "Starting kiosk session..."
|
||||
logger -t secubox-kiosk "Starting kiosk session..."
|
||||
|
||||
# Basic X settings (ignore errors)
|
||||
xset s off 2>/dev/null
|
||||
xset -dpms 2>/dev/null
|
||||
xset s off 2>/dev/null || true
|
||||
xset -dpms 2>/dev/null || true
|
||||
xset s noblank 2>/dev/null || true
|
||||
|
||||
# URL to display - use localhost for universal compatibility (works without network)
|
||||
# URL to display - use localhost for universal compatibility
|
||||
URL="https://localhost/"
|
||||
|
||||
# Try Chromium with minimal flags
|
||||
# Chromium with VT-switch-friendly flags (--start-fullscreen, not --kiosk)
|
||||
# exec replaces shell with chromium - on exit, X session ends
|
||||
exec chromium \
|
||||
--kiosk \
|
||||
--start-fullscreen \
|
||||
--no-first-run \
|
||||
--no-sandbox \
|
||||
--disable-gpu \
|
||||
--disable-pinch \
|
||||
--noerrdialogs \
|
||||
--disable-translate \
|
||||
--ignore-certificate-errors \
|
||||
--disable-features=TranslateUI \
|
||||
--window-position=0,0 \
|
||||
"$URL" || exec xterm -fullscreen -e "echo 'Chromium failed'; sleep 999"
|
||||
"$URL"
|
||||
XSESSION
|
||||
chmod +x "${ROOTFS}/home/secubox-kiosk/.xsession"
|
||||
# Create symlink for xinit compatibility
|
||||
|
|
@ -1726,9 +1746,10 @@ XCONF
|
|||
xinit /bin/bash -c "
|
||||
xset s off 2>/dev/null
|
||||
xset -dpms 2>/dev/null
|
||||
exec chromium --kiosk --no-first-run --no-sandbox --disable-gpu \
|
||||
exec chromium --start-fullscreen --no-first-run --no-sandbox --disable-gpu \
|
||||
--disable-pinch --noerrdialogs --disable-translate \
|
||||
--ignore-certificate-errors --window-position=0,0 '$URL'
|
||||
" -- :0 vt7 -nolisten tcp 2>/dev/null &
|
||||
" -- :0 vt7 -nolisten tcp -keeptty 2>/dev/null &
|
||||
sleep 3
|
||||
chvt 7 2>/dev/null
|
||||
) &
|
||||
|
|
@ -2140,48 +2161,46 @@ rm -rf "${ROOTFS}/tmp"/*
|
|||
# ── CRT-Style Boot Banner with Colors and Emojis ──────────────────────────────
|
||||
log "Creating colorful boot banners..."
|
||||
|
||||
# Pre-login banner (/etc/issue) - shown before login prompt
|
||||
cat > "${ROOTFS}/etc/issue" <<ISSUE
|
||||
[38;5;214m
|
||||
# Pre-login banner (/etc/issue) - use printf %b for real escape sequences
|
||||
printf '%b' "\e[38;5;214m
|
||||
██████ ███████ ██████ ██ ██ ██████ ██████ ██ ██
|
||||
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
███████ █████ ██ ██ ██ ██████ ██ ██ ███
|
||||
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
███████ ███████ ██████ ██████ ██████ ██████ ██ ██
|
||||
[0m
|
||||
[38;5;45m ⚡ CyberMind Security Platform[0m [38;5;82mv${SECUBOX_VERSION}[0m [38;5;242m\l @ \n[0m
|
||||
[38;5;242m Build: ${BUILD_TIMESTAMP}[0m
|
||||
\e[0m
|
||||
\e[38;5;45m ⚡ CyberMind Security Platform\e[0m \e[38;5;82mv${SECUBOX_VERSION}\e[0m \e[38;5;242m\\l @ \\n\e[0m
|
||||
\e[38;5;242m Build: ${BUILD_TIMESTAMP}\e[0m
|
||||
|
||||
[38;5;250m 🔐 Default: [38;5;214mroot[38;5;250m / [38;5;214msecubox[0m
|
||||
[38;5;250m 🌐 Web UI: [38;5;45mhttps://<IP>:9443[0m
|
||||
[38;5;250m 📡 SSH: [38;5;45mport 22[0m
|
||||
\e[38;5;250m 🔐 Default: \e[38;5;214mroot\e[38;5;250m / \e[38;5;214msecubox\e[0m
|
||||
\e[38;5;250m 🌐 Web UI: \e[38;5;45mhttps://<IP>:9443\e[0m
|
||||
\e[38;5;250m 📡 SSH: \e[38;5;45mport 22\e[0m
|
||||
|
||||
[38;5;242m─────────────────────────────────────────────────────────────[0m
|
||||
\e[38;5;242m─────────────────────────────────────────────────────────────\e[0m
|
||||
|
||||
ISSUE
|
||||
" > "${ROOTFS}/etc/issue"
|
||||
|
||||
# Post-login MOTD with dynamic info (/etc/motd)
|
||||
cat > "${ROOTFS}/etc/motd" <<MOTD
|
||||
[38;5;214m
|
||||
# Post-login MOTD - use printf %b for real escape sequences
|
||||
printf '%b' "\e[38;5;214m
|
||||
╔═══════════════════════════════════════════════════════════════╗
|
||||
║[38;5;45m ███████╗███████╗ ██████╗██╗ ██╗██████╗ ██████╗ ██╗ ██╗ [38;5;214m║
|
||||
║[38;5;45m ██╔════╝██╔════╝██╔════╝██║ ██║██╔══██╗██╔═══██╗╚██╗██╔╝ [38;5;214m║
|
||||
║[38;5;45m ███████╗█████╗ ██║ ██║ ██║██████╔╝██║ ██║ ╚███╔╝ [38;5;214m║
|
||||
║[38;5;45m ╚════██║██╔══╝ ██║ ██║ ██║██╔══██╗██║ ██║ ██╔██╗ [38;5;214m║
|
||||
║[38;5;45m ███████║███████╗╚██████╗╚██████╔╝██████╔╝╚██████╔╝██╔╝ ██╗ [38;5;214m║
|
||||
║[38;5;45m ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ [38;5;214m║
|
||||
║[38;5;82m ⚡ LIVE USB MODE ⚡ v${SECUBOX_VERSION} [38;5;214m║
|
||||
╚═══════════════════════════════════════════════════════════════╝[0m
|
||||
║\e[38;5;45m ███████╗███████╗ ██████╗██╗ ██╗██████╗ ██████╗ ██╗ ██╗ \e[38;5;214m║
|
||||
║\e[38;5;45m ██╔════╝██╔════╝██╔════╝██║ ██║██╔══██╗██╔═══██╗╚██╗██╔╝ \e[38;5;214m║
|
||||
║\e[38;5;45m ███████╗█████╗ ██║ ██║ ██║██████╔╝██║ ██║ ╚███╔╝ \e[38;5;214m║
|
||||
║\e[38;5;45m ╚════██║██╔══╝ ██║ ██║ ██║██╔══██╗██║ ██║ ██╔██╗ \e[38;5;214m║
|
||||
║\e[38;5;45m ███████║███████╗╚██████╗╚██████╔╝██████╔╝╚██████╔╝██╔╝ ██╗ \e[38;5;214m║
|
||||
║\e[38;5;45m ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ \e[38;5;214m║
|
||||
║\e[38;5;82m ⚡ LIVE USB MODE ⚡ v${SECUBOX_VERSION} \e[38;5;214m║
|
||||
╚═══════════════════════════════════════════════════════════════╝\e[0m
|
||||
|
||||
[38;5;242m Build: ${BUILD_TIMESTAMP}[0m
|
||||
\e[38;5;242m Build: ${BUILD_TIMESTAMP}\e[0m
|
||||
|
||||
[38;5;250m 🌐 Web UI: [38;5;45mhttps://<IP>:9443[0m
|
||||
[38;5;250m 🔐 Credentials: [38;5;214mroot[38;5;250m / [38;5;214msecubox[0m
|
||||
[38;5;250m 📖 Docs: [38;5;45mhttps://secubox.in/docs[0m
|
||||
\e[38;5;250m 🌐 Web UI: \e[38;5;45mhttps://<IP>:9443\e[0m
|
||||
\e[38;5;250m 🔐 Credentials: \e[38;5;214mroot\e[38;5;250m / \e[38;5;214msecubox\e[0m
|
||||
\e[38;5;250m 📖 Docs: \e[38;5;45mhttps://secubox.in/docs\e[0m
|
||||
|
||||
[38;5;242m Type [38;5;82msecubox-status[38;5;242m for system overview[0m
|
||||
\e[38;5;242m Type \e[38;5;82msecubox-status\e[38;5;242m for system overview\e[0m
|
||||
|
||||
MOTD
|
||||
" > "${ROOTFS}/etc/motd"
|
||||
|
||||
# Dynamic status script for interactive use
|
||||
cat > "${ROOTFS}/usr/bin/secubox-status" <<'STATUS_SCRIPT'
|
||||
|
|
@ -2261,6 +2280,34 @@ echo ""
|
|||
STATUS_SCRIPT
|
||||
chmod +x "${ROOTFS}/usr/bin/secubox-status"
|
||||
|
||||
# Password reset script for TTY recovery
|
||||
cat > "${ROOTFS}/usr/bin/secubox-passwd" <<'PASSWD_SCRIPT'
|
||||
#!/bin/bash
|
||||
# SecuBox Password Reset
|
||||
set -e
|
||||
USERS_FILE="/etc/secubox/users.json"
|
||||
CONF_FILE="/etc/secubox/secubox.conf"
|
||||
echo "SecuBox Password Reset"
|
||||
[[ $EUID -ne 0 ]] && echo "Error: Run as root" && exit 1
|
||||
read -sp "New password for admin: " NEW_PASS && echo
|
||||
read -sp "Confirm password: " CONFIRM && echo
|
||||
[[ "$NEW_PASS" != "$CONFIRM" ]] && echo "Passwords don't match" && exit 1
|
||||
[[ ${#NEW_PASS} -lt 4 ]] && echo "Password too short" && exit 1
|
||||
NEW_HASH=$(echo -n "$NEW_PASS" | sha256sum | cut -d' ' -f1)
|
||||
if [[ -f "$USERS_FILE" ]]; then
|
||||
sed -i "s/\"password_hash\": \"[^\"]*\"/\"password_hash\": \"${NEW_HASH}\"/g" "$USERS_FILE"
|
||||
echo "Updated users.json"
|
||||
fi
|
||||
if [[ -f "$CONF_FILE" ]]; then
|
||||
sed -i "s/^password = .*/password = \"${NEW_PASS}\"/" "$CONF_FILE"
|
||||
echo "Updated secubox.conf"
|
||||
fi
|
||||
systemctl restart secubox-portal secubox-hub 2>/dev/null || true
|
||||
echo "Password reset complete!"
|
||||
PASSWD_SCRIPT
|
||||
chmod +x "${ROOTFS}/usr/bin/secubox-passwd"
|
||||
ok "Password reset script installed (secubox-passwd)"
|
||||
|
||||
# Also add a boot-time banner display script
|
||||
cat > "${ROOTFS}/usr/sbin/secubox-boot-banner" <<'BOOT_BANNER'
|
||||
#!/bin/bash
|
||||
|
|
|
|||
BIN
image/plymouth/secubox-3d/progress-bg.png
Normal file
|
After Width: | Height: | Size: 182 B |
BIN
image/plymouth/secubox-3d/progress-fg.png
Normal file
|
After Width: | Height: | Size: 260 B |
8
image/plymouth/secubox-3d/secubox-3d.plymouth
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[Plymouth Theme]
|
||||
Name=SecuBox 3D
|
||||
Description=Triple lemniscate + nested cubes boot splash
|
||||
ModuleName=script
|
||||
|
||||
[script]
|
||||
ImageDir=/usr/share/plymouth/themes/secubox-3d
|
||||
ScriptFile=/usr/share/plymouth/themes/secubox-3d/secubox-3d.script
|
||||
429
image/plymouth/secubox-3d/secubox-3d.script
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
/* SecuBox 3D - Plymouth Theme Script
|
||||
* Triple Lemniscate + Nested Cubes (gigognes)
|
||||
* Matching secubox_v5_stereo.html aesthetic
|
||||
* CyberMind - https://cybermind.fr
|
||||
*/
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* SecuBox Color Palette (from FD[] face definitions)
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
/* AUTH #FF6910 */ col_auth_r = 1.000; col_auth_g = 0.412; col_auth_b = 0.063;
|
||||
/* WALL #FFB300 */ col_wall_r = 1.000; col_wall_g = 0.702; col_wall_b = 0.000;
|
||||
/* BOOT #FF3333 */ col_boot_r = 1.000; col_boot_g = 0.200; col_boot_b = 0.200;
|
||||
/* MIND #9B7EFF */ col_mind_r = 0.608; col_mind_g = 0.494; col_mind_b = 1.000;
|
||||
/* ROOT #33FF33 */ col_root_r = 0.200; col_root_g = 1.000; col_root_b = 0.200;
|
||||
/* MESH #3AB4FF */ col_mesh_r = 0.227; col_mesh_g = 0.706; col_mesh_b = 1.000;
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Screen Setup - Dark cyber background (#07080f)
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
Window.SetBackgroundTopColor(0.027, 0.031, 0.059);
|
||||
Window.SetBackgroundBottomColor(0.012, 0.016, 0.035);
|
||||
|
||||
screen_width = Window.GetWidth();
|
||||
screen_height = Window.GetHeight();
|
||||
center_x = screen_width / 2;
|
||||
center_y = screen_height / 2;
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Load Assets
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
progress_bg = Image("progress-bg.png");
|
||||
progress_fg = Image("progress-fg.png");
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* 3 Nested Cubes Configuration (gigognes)
|
||||
* Outer=0, Middle=1, Inner=2
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* Cube sizes (matching web: 256/2, 128/2, 64/2 scaled for plymouth) */
|
||||
cube_size[0] = 110; /* Outer - largest */
|
||||
cube_size[1] = 70; /* Middle */
|
||||
cube_size[2] = 40; /* Inner - smallest */
|
||||
|
||||
/* Desynchronized rotation speeds (BASE_SPD from web) */
|
||||
/* Outer: slowest, most majestic */
|
||||
spd_x[0] = 0.004; spd_y[0] = 0.006; spd_z[0] = 0.003;
|
||||
/* Middle: medium */
|
||||
spd_x[1] = 0.007; spd_y[1] = 0.005; spd_z[1] = 0.006;
|
||||
/* Inner: fastest, most dynamic */
|
||||
spd_x[2] = 0.012; spd_y[2] = 0.010; spd_z[2] = 0.008;
|
||||
|
||||
/* Rotation angles (offset for visual interest at start) */
|
||||
rot_x[0] = 0.0; rot_y[0] = 0.0; rot_z[0] = 0.0;
|
||||
rot_x[1] = 0.8; rot_y[1] = 0.4; rot_z[1] = 0.2;
|
||||
rot_x[2] = 1.6; rot_y[2] = 1.2; rot_z[2] = 0.6;
|
||||
|
||||
/* Cube edge colors (gradient from outer to inner) */
|
||||
/* Outer: dim green-cyan */
|
||||
cube_r[0] = 0.15; cube_g[0] = 0.45; cube_b[0] = 0.35;
|
||||
/* Middle: brighter cyan */
|
||||
cube_r[1] = 0.20; cube_g[1] = 0.60; cube_b[1] = 0.50;
|
||||
/* Inner: bright SecuBox green */
|
||||
cube_r[2] = 0.25; cube_g[2] = 0.85; cube_b[2] = 0.45;
|
||||
|
||||
/* 8 vertices per cube × 3 cubes = 24 vertex sprites */
|
||||
for (c = 0; c < 3; c++) {
|
||||
for (v = 0; v < 8; v++) {
|
||||
idx = c * 8 + v;
|
||||
cube_verts[idx] = Sprite();
|
||||
cube_verts[idx].SetZ(10 + c * 3);
|
||||
}
|
||||
}
|
||||
|
||||
/* 12 edges per cube × 3 cubes = 36 edge midpoint sprites */
|
||||
for (c = 0; c < 3; c++) {
|
||||
for (e = 0; e < 12; e++) {
|
||||
idx = c * 12 + e;
|
||||
cube_edges[idx] = Sprite();
|
||||
cube_edges[idx].SetZ(9 + c * 3);
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Triple Lemniscate Configuration
|
||||
* 3 branches: AUTH (orange), MIND (purple), MESH (blue)
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
lemniscate_scale = 95;
|
||||
|
||||
/* Branch colors */
|
||||
lem_r[0] = col_auth_r; lem_g[0] = col_auth_g; lem_b[0] = col_auth_b; /* AUTH orange */
|
||||
lem_r[1] = col_mind_r; lem_g[1] = col_mind_g; lem_b[1] = col_mind_b; /* MIND purple */
|
||||
lem_r[2] = col_mesh_r; lem_g[2] = col_mesh_g; lem_b[2] = col_mesh_b; /* MESH blue */
|
||||
|
||||
/* Head speeds (desynchronized) */
|
||||
lem_speed[0] = 0.028;
|
||||
lem_speed[1] = 0.022;
|
||||
lem_speed[2] = 0.019;
|
||||
|
||||
/* Head positions (start offset for visual variety) */
|
||||
lem_pos[0] = 0.0;
|
||||
lem_pos[1] = 2.094; /* 2π/3 */
|
||||
lem_pos[2] = 4.188; /* 4π/3 */
|
||||
|
||||
/* Trail dots per branch */
|
||||
trail_len = 15;
|
||||
|
||||
/* Lemniscate sprites: 3 branches × (trail_len + 1 head) */
|
||||
for (b = 0; b < 3; b++) {
|
||||
for (d = 0; d < trail_len; d++) {
|
||||
idx = b * trail_len + d;
|
||||
lem_trail[idx] = Sprite();
|
||||
lem_trail[idx].SetZ(5);
|
||||
}
|
||||
lem_head[b] = Sprite();
|
||||
lem_head[b].SetZ(8);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Progress Bar
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
progress_bg_sprite = Sprite();
|
||||
progress_fg_sprite = Sprite();
|
||||
if (progress_bg) {
|
||||
progress_bg_sprite.SetImage(progress_bg);
|
||||
}
|
||||
progress_bg_sprite.SetX(center_x - 130);
|
||||
progress_bg_sprite.SetY(center_y + 170);
|
||||
progress_bg_sprite.SetZ(50);
|
||||
|
||||
if (progress_fg) {
|
||||
progress_fg_sprite.SetImage(progress_fg);
|
||||
}
|
||||
progress_fg_sprite.SetX(center_x - 128);
|
||||
progress_fg_sprite.SetY(center_y + 172);
|
||||
progress_fg_sprite.SetZ(51);
|
||||
|
||||
/* Status message */
|
||||
message_sprite = Sprite();
|
||||
message_sprite.SetZ(52);
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Animation State
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
frame = 0;
|
||||
boot_progress = 0;
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Unit Cube Vertices (±1, ±1, ±1)
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
uv_x[0] = -1; uv_y[0] = -1; uv_z[0] = -1;
|
||||
uv_x[1] = 1; uv_y[1] = -1; uv_z[1] = -1;
|
||||
uv_x[2] = 1; uv_y[2] = 1; uv_z[2] = -1;
|
||||
uv_x[3] = -1; uv_y[3] = 1; uv_z[3] = -1;
|
||||
uv_x[4] = -1; uv_y[4] = -1; uv_z[4] = 1;
|
||||
uv_x[5] = 1; uv_y[5] = -1; uv_z[5] = 1;
|
||||
uv_x[6] = 1; uv_y[6] = 1; uv_z[6] = 1;
|
||||
uv_x[7] = -1; uv_y[7] = 1; uv_z[7] = 1;
|
||||
|
||||
/* Edge definitions (vertex pairs) */
|
||||
edge_a[0]=0; edge_b[0]=1; edge_a[1]=1; edge_b[1]=2; edge_a[2]=2; edge_b[2]=3; edge_a[3]=3; edge_b[3]=0;
|
||||
edge_a[4]=4; edge_b[4]=5; edge_a[5]=5; edge_b[5]=6; edge_a[6]=6; edge_b[6]=7; edge_a[7]=7; edge_b[7]=4;
|
||||
edge_a[8]=0; edge_b[8]=4; edge_a[9]=1; edge_b[9]=5; edge_a[10]=2; edge_b[10]=6; edge_a[11]=3; edge_b[11]=7;
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* 3D Rotation Function
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
fun rotate3d(px, py, pz, ax, ay, az) {
|
||||
/* Rotate X */
|
||||
cx = Math.Cos(ax); sx = Math.Sin(ax);
|
||||
y1 = py * cx - pz * sx;
|
||||
z1 = py * sx + pz * cx;
|
||||
|
||||
/* Rotate Y */
|
||||
cy = Math.Cos(ay); sy = Math.Sin(ay);
|
||||
x2 = px * cy + z1 * sy;
|
||||
z2 = -px * sy + z1 * cy;
|
||||
|
||||
/* Rotate Z */
|
||||
cz = Math.Cos(az); sz = Math.Sin(az);
|
||||
x3 = x2 * cz - y1 * sz;
|
||||
y3 = x2 * sz + y1 * cz;
|
||||
|
||||
result[0] = x3;
|
||||
result[1] = y3;
|
||||
result[2] = z2;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Lemniscate Parametric (Bernoulli)
|
||||
* x = a * cos(t) / (1 + sin²(t))
|
||||
* y = a * sin(t) * cos(t) / (1 + sin²(t))
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
fun lem_x(t, scale) {
|
||||
st = Math.Sin(t);
|
||||
ct = Math.Cos(t);
|
||||
d = 1 + st * st;
|
||||
return scale * ct / d;
|
||||
}
|
||||
|
||||
fun lem_y(t, scale) {
|
||||
st = Math.Sin(t);
|
||||
ct = Math.Cos(t);
|
||||
d = 1 + st * st;
|
||||
return scale * st * ct / d;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Draw Single Cube
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
fun draw_cube(cube_idx) {
|
||||
ax = global.rot_x[cube_idx];
|
||||
ay = global.rot_y[cube_idx];
|
||||
az = global.rot_z[cube_idx];
|
||||
size = global.cube_size[cube_idx] / 2;
|
||||
|
||||
cr = global.cube_r[cube_idx];
|
||||
cg = global.cube_g[cube_idx];
|
||||
cb = global.cube_b[cube_idx];
|
||||
|
||||
/* Compute projected vertices */
|
||||
for (v = 0; v < 8; v++) {
|
||||
px = global.uv_x[v] * size;
|
||||
py = global.uv_y[v] * size;
|
||||
pz = global.uv_z[v] * size;
|
||||
|
||||
rot = rotate3d(px, py, pz, ax, ay, az);
|
||||
|
||||
/* Store projected coords */
|
||||
proj_x[v] = global.center_x + rot[0];
|
||||
proj_y[v] = global.center_y + rot[1];
|
||||
proj_z[v] = rot[2];
|
||||
|
||||
/* Depth-based brightness */
|
||||
depth = (rot[2] + size) / (size * 2);
|
||||
bright = 0.4 + depth * 0.6;
|
||||
|
||||
/* Draw vertex dot */
|
||||
idx = cube_idx * 8 + v;
|
||||
dot_img = Image.Text("●", cr * bright, cg * bright, cb * bright, 1);
|
||||
global.cube_verts[idx].SetImage(dot_img);
|
||||
global.cube_verts[idx].SetX(proj_x[v] - 4);
|
||||
global.cube_verts[idx].SetY(proj_y[v] - 4);
|
||||
global.cube_verts[idx].SetOpacity(0.6 + depth * 0.4);
|
||||
}
|
||||
|
||||
/* Draw edges (midpoints) */
|
||||
for (e = 0; e < 12; e++) {
|
||||
va = global.edge_a[e];
|
||||
vb = global.edge_b[e];
|
||||
|
||||
/* Edge midpoint */
|
||||
mx = (proj_x[va] + proj_x[vb]) / 2;
|
||||
my = (proj_y[va] + proj_y[vb]) / 2;
|
||||
mz = (proj_z[va] + proj_z[vb]) / 2;
|
||||
|
||||
depth = (mz + size) / (size * 2);
|
||||
bright = 0.3 + depth * 0.5;
|
||||
|
||||
idx = cube_idx * 12 + e;
|
||||
edge_img = Image.Text("·", cr * bright, cg * bright, cb * bright, 1);
|
||||
global.cube_edges[idx].SetImage(edge_img);
|
||||
global.cube_edges[idx].SetX(mx - 2);
|
||||
global.cube_edges[idx].SetY(my - 2);
|
||||
global.cube_edges[idx].SetOpacity(0.4 + depth * 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Draw Triple Lemniscate
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
fun draw_lemniscates() {
|
||||
/* Gentle twist animation */
|
||||
twist = Math.Sin(global.frame * 0.008) * 0.3;
|
||||
|
||||
for (b = 0; b < 3; b++) {
|
||||
/* Update head position */
|
||||
global.lem_pos[b] += global.lem_speed[b];
|
||||
if (global.lem_pos[b] > 6.28318) {
|
||||
global.lem_pos[b] -= 6.28318;
|
||||
}
|
||||
|
||||
lr = global.lem_r[b];
|
||||
lg = global.lem_g[b];
|
||||
lb = global.lem_b[b];
|
||||
|
||||
/* Draw trail */
|
||||
for (d = 0; d < global.trail_len; d++) {
|
||||
t = global.lem_pos[b] - d * 0.25;
|
||||
|
||||
/* 3D lemniscate with twist */
|
||||
lx = lem_x(t, global.lemniscate_scale);
|
||||
ly = lem_y(t, global.lemniscate_scale);
|
||||
lz = Math.Sin(t * 2 + twist) * 15; /* Z oscillation */
|
||||
|
||||
/* Simple rotation for 3D effect */
|
||||
rot = rotate3d(lx, ly, lz, twist * 0.5, global.frame * 0.003, 0);
|
||||
|
||||
sx = global.center_x + rot[0];
|
||||
sy = global.center_y + rot[1];
|
||||
|
||||
/* Fade trail */
|
||||
fade = 1.0 - (d / global.trail_len);
|
||||
|
||||
idx = b * global.trail_len + d;
|
||||
dot_img = Image.Text("•", lr * fade, lg * fade, lb * fade, 1);
|
||||
global.lem_trail[idx].SetImage(dot_img);
|
||||
global.lem_trail[idx].SetX(sx - 3);
|
||||
global.lem_trail[idx].SetY(sy - 3);
|
||||
global.lem_trail[idx].SetOpacity(fade * 0.7);
|
||||
}
|
||||
|
||||
/* Draw glowing head */
|
||||
ht = global.lem_pos[b];
|
||||
hx = lem_x(ht, global.lemniscate_scale);
|
||||
hy = lem_y(ht, global.lemniscate_scale);
|
||||
hz = Math.Sin(ht * 2 + twist) * 15;
|
||||
|
||||
hrot = rotate3d(hx, hy, hz, twist * 0.5, global.frame * 0.003, 0);
|
||||
|
||||
hsx = global.center_x + hrot[0];
|
||||
hsy = global.center_y + hrot[1];
|
||||
|
||||
/* Pulsing glow */
|
||||
pulse = 0.85 + Math.Sin(global.frame * 0.15 + b) * 0.15;
|
||||
|
||||
head_img = Image.Text("◉", lr * pulse, lg * pulse, lb * pulse, 1);
|
||||
global.lem_head[b].SetImage(head_img);
|
||||
global.lem_head[b].SetX(hsx - 5);
|
||||
global.lem_head[b].SetY(hsy - 5);
|
||||
global.lem_head[b].SetOpacity(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Main Animation Loop
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
fun refresh_callback() {
|
||||
global.frame++;
|
||||
|
||||
/* Update cube rotations (desynchronized) */
|
||||
for (c = 0; c < 3; c++) {
|
||||
global.rot_x[c] += global.spd_x[c];
|
||||
global.rot_y[c] += global.spd_y[c];
|
||||
global.rot_z[c] += global.spd_z[c];
|
||||
|
||||
if (global.rot_x[c] > 6.28318) global.rot_x[c] -= 6.28318;
|
||||
if (global.rot_y[c] > 6.28318) global.rot_y[c] -= 6.28318;
|
||||
if (global.rot_z[c] > 6.28318) global.rot_z[c] -= 6.28318;
|
||||
|
||||
draw_cube(c);
|
||||
}
|
||||
|
||||
/* Draw triple lemniscate */
|
||||
draw_lemniscates();
|
||||
}
|
||||
|
||||
Plymouth.SetRefreshFunction(refresh_callback);
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Plymouth Callbacks
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
fun boot_progress_callback(duration, progress_val) {
|
||||
global.boot_progress = progress_val;
|
||||
|
||||
if (progress_fg) {
|
||||
bar_width = Math.Int(progress_val * 256);
|
||||
if (bar_width > 0) {
|
||||
scaled = progress_fg.Scale(bar_width, 12);
|
||||
progress_fg_sprite.SetImage(scaled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Plymouth.SetBootProgressFunction(boot_progress_callback);
|
||||
|
||||
fun message_callback(text) {
|
||||
/* SecuBox green text */
|
||||
msg_img = Image.Text(text, 0.2, 0.85, 0.4, "Mono 10");
|
||||
message_sprite.SetImage(msg_img);
|
||||
message_sprite.SetX(center_x - msg_img.GetWidth() / 2);
|
||||
message_sprite.SetY(center_y + 195);
|
||||
}
|
||||
|
||||
Plymouth.SetMessageFunction(message_callback);
|
||||
|
||||
fun display_normal_callback() {
|
||||
/* Normal boot display */
|
||||
}
|
||||
|
||||
fun display_password_callback(prompt, bullets) {
|
||||
/* LUKS password prompt */
|
||||
prompt_img = Image.Text(prompt, col_mesh_r, col_mesh_g, col_mesh_b, "Sans Bold 11");
|
||||
message_sprite.SetImage(prompt_img);
|
||||
message_sprite.SetX(center_x - prompt_img.GetWidth() / 2);
|
||||
message_sprite.SetY(center_y + 150);
|
||||
}
|
||||
|
||||
Plymouth.SetDisplayNormalFunction(display_normal_callback);
|
||||
Plymouth.SetDisplayPasswordFunction(display_password_callback);
|
||||
|
||||
fun quit_callback() {
|
||||
/* Fade out */
|
||||
for (c = 0; c < 3; c++) {
|
||||
for (v = 0; v < 8; v++) {
|
||||
idx = c * 8 + v;
|
||||
global.cube_verts[idx].SetOpacity(0);
|
||||
}
|
||||
for (e = 0; e < 12; e++) {
|
||||
idx = c * 12 + e;
|
||||
global.cube_edges[idx].SetOpacity(0);
|
||||
}
|
||||
}
|
||||
|
||||
for (b = 0; b < 3; b++) {
|
||||
for (d = 0; d < global.trail_len; d++) {
|
||||
idx = b * global.trail_len + d;
|
||||
global.lem_trail[idx].SetOpacity(0);
|
||||
}
|
||||
global.lem_head[b].SetOpacity(0);
|
||||
}
|
||||
|
||||
progress_bg_sprite.SetOpacity(0);
|
||||
progress_fg_sprite.SetOpacity(0);
|
||||
message_sprite.SetOpacity(0);
|
||||
}
|
||||
|
||||
Plymouth.SetQuitFunction(quit_callback);
|
||||
BIN
image/plymouth/secubox-3ds/cube-corner.png
Normal file
|
After Width: | Height: | Size: 204 B |
BIN
image/plymouth/secubox-3ds/cube-edge.png
Normal file
|
After Width: | Height: | Size: 162 B |
BIN
image/plymouth/secubox-3ds/divider.png
Normal file
|
After Width: | Height: | Size: 176 B |
BIN
image/plymouth/secubox-3ds/lemniscate-dot.png
Normal file
|
After Width: | Height: | Size: 210 B |
BIN
image/plymouth/secubox-3ds/progress-bg.png
Normal file
|
After Width: | Height: | Size: 181 B |
BIN
image/plymouth/secubox-3ds/progress-fg.png
Normal file
|
After Width: | Height: | Size: 253 B |
8
image/plymouth/secubox-3ds/secubox-3ds.plymouth
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[Plymouth Theme]
|
||||
Name=SecuBox 3DS
|
||||
Description=Nintendo 3DS dual-screen aesthetic with nested cubes and lemniscates
|
||||
ModuleName=script
|
||||
|
||||
[script]
|
||||
ImageDir=/usr/share/plymouth/themes/secubox-3ds
|
||||
ScriptFile=/usr/share/plymouth/themes/secubox-3ds/secubox-3ds.script
|
||||
506
image/plymouth/secubox-3ds/secubox-3ds.script
Normal file
|
|
@ -0,0 +1,506 @@
|
|||
/* SecuBox 3DS - Plymouth Theme Script
|
||||
* Nintendo 3DS dual-screen aesthetic
|
||||
* Upper: 3 nested cubes + 2 lemniscates
|
||||
* Lower: Kernel log + progress bar
|
||||
* CyberMind - https://cybermind.fr
|
||||
*/
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* 3DS Color Palette
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
/* Deep blue gradient: #0033aa (dark) → #1a6fff (bright) */
|
||||
blue_dark_r = 0.000; blue_dark_g = 0.200; blue_dark_b = 0.667; /* #0033aa */
|
||||
blue_mid_r = 0.082; blue_mid_g = 0.333; blue_mid_b = 0.835; /* #1555d5 */
|
||||
blue_bright_r = 0.102; blue_bright_g = 0.435; blue_bright_b = 1.0; /* #1a6fff */
|
||||
|
||||
/* Log colors */
|
||||
log_blue_r = 0.4; log_blue_g = 0.6; log_blue_b = 1.0; /* info */
|
||||
log_green_r = 0.4; log_green_g = 1.0; log_green_b = 0.6; /* ok */
|
||||
log_amber_r = 1.0; log_amber_g = 0.8; log_amber_b = 0.3; /* warn */
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Screen Setup - Dual screen simulation
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
Window.SetBackgroundTopColor(0.02, 0.02, 0.04); /* Near black */
|
||||
Window.SetBackgroundBottomColor(0.01, 0.01, 0.02);
|
||||
|
||||
screen_width = Window.GetWidth();
|
||||
screen_height = Window.GetHeight();
|
||||
|
||||
/* 3DS aspect simulation - upper screen takes 55% height */
|
||||
upper_height = screen_height * 0.55;
|
||||
lower_height = screen_height * 0.45;
|
||||
divider_y = upper_height;
|
||||
|
||||
/* Centers for each "screen" */
|
||||
upper_center_x = screen_width / 2;
|
||||
upper_center_y = upper_height / 2;
|
||||
lower_center_x = screen_width / 2;
|
||||
lower_center_y = divider_y + (lower_height / 2);
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Load Assets
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
/* Cube wireframe edges - rendered as sprites */
|
||||
cube_edge = Image("cube-edge.png");
|
||||
cube_corner = Image("cube-corner.png");
|
||||
lemniscate_dot = Image("lemniscate-dot.png");
|
||||
divider_line = Image("divider.png");
|
||||
progress_bg = Image("progress-bg.png");
|
||||
progress_fg = Image("progress-fg.png");
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Screen Divider (3DS hinge simulation)
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
divider_sprite = Sprite();
|
||||
divider_img = Image.Text("", 1, 1, 1, 1); /* Placeholder if no image */
|
||||
if (divider_line) {
|
||||
divider_sprite.SetImage(divider_line);
|
||||
} else {
|
||||
/* Create a simple dark blue line */
|
||||
divider_sprite.SetImage(divider_img);
|
||||
}
|
||||
divider_sprite.SetX(0);
|
||||
divider_sprite.SetY(divider_y - 2);
|
||||
divider_sprite.SetZ(50);
|
||||
divider_sprite.SetOpacity(0.8);
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* UPPER SCREEN - 3 Nested Cubes
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* Cube sizes (nested: large → medium → small) */
|
||||
cube_sizes[0] = 100; /* Outer */
|
||||
cube_sizes[1] = 65; /* Middle */
|
||||
cube_sizes[2] = 35; /* Inner */
|
||||
|
||||
/* Rotation speeds (desynchronized) */
|
||||
cube_speed_x[0] = 0.004; cube_speed_y[0] = 0.007; cube_speed_z[0] = 0.003;
|
||||
cube_speed_x[1] = 0.009; cube_speed_y[1] = 0.005; cube_speed_z[1] = 0.008;
|
||||
cube_speed_x[2] = 0.015; cube_speed_y[2] = 0.012; cube_speed_z[2] = 0.006;
|
||||
|
||||
/* Rotation angles */
|
||||
cube_angle_x[0] = 0; cube_angle_y[0] = 0; cube_angle_z[0] = 0;
|
||||
cube_angle_x[1] = 1.0; cube_angle_y[1] = 0.5; cube_angle_z[1] = 0.3;
|
||||
cube_angle_x[2] = 2.0; cube_angle_y[2] = 1.5; cube_angle_z[2] = 1.0;
|
||||
|
||||
/* Cube edge sprites (12 edges × 3 cubes = 36 sprites) */
|
||||
/* We'll draw simplified: 8 corner dots per cube */
|
||||
for (c = 0; c < 3; c++) {
|
||||
for (v = 0; v < 8; v++) {
|
||||
idx = c * 8 + v;
|
||||
cube_vertices[idx] = Sprite();
|
||||
cube_vertices[idx].SetZ(20 + c * 5);
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* UPPER SCREEN - 2 Lemniscates (∞ curves)
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* Lemniscate parameters */
|
||||
lemniscate_scale = 80; /* Size of the infinity symbol */
|
||||
lemniscate_y_offset[0] = -30; /* Above center */
|
||||
lemniscate_y_offset[1] = 30; /* Below center */
|
||||
|
||||
/* Each lemniscate has multiple trail dots + 1 bright head */
|
||||
dots_per_curve = 12;
|
||||
head_speed[0] = 0.025;
|
||||
head_speed[1] = 0.018; /* Different speed for visual interest */
|
||||
head_pos[0] = 0;
|
||||
head_pos[1] = 3.14159; /* Start opposite */
|
||||
|
||||
/* Lemniscate dot sprites */
|
||||
for (l = 0; l < 2; l++) {
|
||||
for (d = 0; d < dots_per_curve; d++) {
|
||||
idx = l * dots_per_curve + d;
|
||||
lem_dots[idx] = Sprite();
|
||||
lem_dots[idx].SetZ(15);
|
||||
}
|
||||
/* Bright head */
|
||||
lem_heads[l] = Sprite();
|
||||
lem_heads[l].SetZ(18);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* LOWER SCREEN - Kernel Log Area
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* Log line sprites (scrolling buffer) */
|
||||
max_log_lines = 8;
|
||||
for (i = 0; i < max_log_lines; i++) {
|
||||
log_sprites[i] = Sprite();
|
||||
log_sprites[i].SetZ(30);
|
||||
}
|
||||
log_texts[0] = "";
|
||||
log_texts[1] = "";
|
||||
log_texts[2] = "";
|
||||
log_texts[3] = "";
|
||||
log_texts[4] = "";
|
||||
log_texts[5] = "";
|
||||
log_texts[6] = "";
|
||||
log_texts[7] = "";
|
||||
log_index = 0;
|
||||
|
||||
/* Progress bar */
|
||||
progress_bg_sprite = Sprite();
|
||||
progress_fg_sprite = Sprite();
|
||||
if (progress_bg) {
|
||||
progress_bg_sprite.SetImage(progress_bg);
|
||||
}
|
||||
progress_bg_sprite.SetX(lower_center_x - 120);
|
||||
progress_bg_sprite.SetY(lower_center_y + 70);
|
||||
progress_bg_sprite.SetZ(35);
|
||||
|
||||
if (progress_fg) {
|
||||
progress_fg_sprite.SetImage(progress_fg);
|
||||
}
|
||||
progress_fg_sprite.SetX(lower_center_x - 118);
|
||||
progress_fg_sprite.SetY(lower_center_y + 72);
|
||||
progress_fg_sprite.SetZ(36);
|
||||
|
||||
/* Phase message */
|
||||
phase_sprite = Sprite();
|
||||
phase_sprite.SetZ(40);
|
||||
current_phase = "Initializing...";
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Animation State
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
frame = 0;
|
||||
boot_progress = 0;
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* 3D Math - Cube vertex projection
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* Unit cube vertices (±1, ±1, ±1) */
|
||||
unit_cube_x[0] = -1; unit_cube_y[0] = -1; unit_cube_z[0] = -1;
|
||||
unit_cube_x[1] = 1; unit_cube_y[1] = -1; unit_cube_z[1] = -1;
|
||||
unit_cube_x[2] = 1; unit_cube_y[2] = 1; unit_cube_z[2] = -1;
|
||||
unit_cube_x[3] = -1; unit_cube_y[3] = 1; unit_cube_z[3] = -1;
|
||||
unit_cube_x[4] = -1; unit_cube_y[4] = -1; unit_cube_z[4] = 1;
|
||||
unit_cube_x[5] = 1; unit_cube_y[5] = -1; unit_cube_z[5] = 1;
|
||||
unit_cube_x[6] = 1; unit_cube_y[6] = 1; unit_cube_z[6] = 1;
|
||||
unit_cube_x[7] = -1; unit_cube_y[7] = 1; unit_cube_z[7] = 1;
|
||||
|
||||
fun rotate_point(px, py, pz, ax, ay, az) {
|
||||
/* Rotate around X */
|
||||
cos_x = Math.Cos(ax);
|
||||
sin_x = Math.Sin(ax);
|
||||
y1 = py * cos_x - pz * sin_x;
|
||||
z1 = py * sin_x + pz * cos_x;
|
||||
|
||||
/* Rotate around Y */
|
||||
cos_y = Math.Cos(ay);
|
||||
sin_y = Math.Sin(ay);
|
||||
x2 = px * cos_y + z1 * sin_y;
|
||||
z2 = -px * sin_y + z1 * cos_y;
|
||||
|
||||
/* Rotate around Z */
|
||||
cos_z = Math.Cos(az);
|
||||
sin_z = Math.Sin(az);
|
||||
x3 = x2 * cos_z - y1 * sin_z;
|
||||
y3 = x2 * sin_z + y1 * cos_z;
|
||||
|
||||
result[0] = x3;
|
||||
result[1] = y3;
|
||||
result[2] = z2;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Lemniscate parametric curve (Bernoulli lemniscate)
|
||||
* x = a * cos(t) / (1 + sin²(t))
|
||||
* y = a * sin(t) * cos(t) / (1 + sin²(t))
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
fun lemniscate_x(t, scale) {
|
||||
sin_t = Math.Sin(t);
|
||||
cos_t = Math.Cos(t);
|
||||
denom = 1 + sin_t * sin_t;
|
||||
return scale * cos_t / denom;
|
||||
}
|
||||
|
||||
fun lemniscate_y(t, scale) {
|
||||
sin_t = Math.Sin(t);
|
||||
cos_t = Math.Cos(t);
|
||||
denom = 1 + sin_t * sin_t;
|
||||
return scale * sin_t * cos_t / denom;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Animation Functions
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
fun draw_cube(cube_idx) {
|
||||
ax = global.cube_angle_x[cube_idx];
|
||||
ay = global.cube_angle_y[cube_idx];
|
||||
az = global.cube_angle_z[cube_idx];
|
||||
size = global.cube_sizes[cube_idx] / 2;
|
||||
|
||||
/* Brightness based on cube layer (inner = brightest) */
|
||||
brightness = 0.3 + (2 - cube_idx) * 0.3;
|
||||
|
||||
for (v = 0; v < 8; v++) {
|
||||
/* Get unit cube vertex */
|
||||
px = global.unit_cube_x[v] * size;
|
||||
py = global.unit_cube_y[v] * size;
|
||||
pz = global.unit_cube_z[v] * size;
|
||||
|
||||
/* Rotate */
|
||||
rotated = rotate_point(px, py, pz, ax, ay, az);
|
||||
|
||||
/* Project to screen (simple orthographic) */
|
||||
screen_x = global.upper_center_x + rotated[0];
|
||||
screen_y = global.upper_center_y + rotated[1];
|
||||
|
||||
/* Depth-based opacity */
|
||||
depth = (rotated[2] + size) / (size * 2);
|
||||
opacity = brightness * (0.5 + depth * 0.5);
|
||||
|
||||
/* Create vertex dot */
|
||||
idx = cube_idx * 8 + v;
|
||||
dot_size = 4 + (2 - cube_idx) * 2; /* Inner cube has bigger dots */
|
||||
|
||||
dot_img = Image.Text("*", global.blue_mid_r * brightness,
|
||||
global.blue_mid_g * brightness,
|
||||
global.blue_bright_b * brightness, 1);
|
||||
global.cube_vertices[idx].SetImage(dot_img);
|
||||
global.cube_vertices[idx].SetX(screen_x - dot_size/2);
|
||||
global.cube_vertices[idx].SetY(screen_y - dot_size/2);
|
||||
global.cube_vertices[idx].SetOpacity(opacity);
|
||||
}
|
||||
}
|
||||
|
||||
fun draw_lemniscates() {
|
||||
for (l = 0; l < 2; l++) {
|
||||
/* Update head position */
|
||||
global.head_pos[l] += global.head_speed[l];
|
||||
if (global.head_pos[l] > 6.28318) {
|
||||
global.head_pos[l] -= 6.28318;
|
||||
}
|
||||
|
||||
y_off = global.lemniscate_y_offset[l];
|
||||
|
||||
/* Draw trail dots */
|
||||
for (d = 0; d < global.dots_per_curve; d++) {
|
||||
/* Position along curve (behind the head) */
|
||||
t = global.head_pos[l] - d * 0.4;
|
||||
|
||||
lx = lemniscate_x(t, global.lemniscate_scale);
|
||||
ly = lemniscate_y(t, global.lemniscate_scale);
|
||||
|
||||
screen_x = global.upper_center_x + lx;
|
||||
screen_y = global.upper_center_y + y_off + ly;
|
||||
|
||||
/* Fade trail */
|
||||
fade = 1.0 - (d / global.dots_per_curve) * 0.8;
|
||||
|
||||
idx = l * global.dots_per_curve + d;
|
||||
dot_img = Image.Text(".", global.blue_dark_r + fade * 0.1,
|
||||
global.blue_dark_g + fade * 0.2,
|
||||
global.blue_bright_b * fade, 1);
|
||||
global.lem_dots[idx].SetImage(dot_img);
|
||||
global.lem_dots[idx].SetX(screen_x - 2);
|
||||
global.lem_dots[idx].SetY(screen_y - 2);
|
||||
global.lem_dots[idx].SetOpacity(fade * 0.7);
|
||||
}
|
||||
|
||||
/* Draw bright head */
|
||||
hx = lemniscate_x(global.head_pos[l], global.lemniscate_scale);
|
||||
hy = lemniscate_y(global.head_pos[l], global.lemniscate_scale);
|
||||
|
||||
head_screen_x = global.upper_center_x + hx;
|
||||
head_screen_y = global.upper_center_y + y_off + hy;
|
||||
|
||||
/* Pulsing head */
|
||||
pulse = 0.8 + Math.Sin(global.frame * 0.2) * 0.2;
|
||||
head_img = Image.Text("O", global.blue_bright_r * pulse,
|
||||
global.blue_bright_g * pulse,
|
||||
global.blue_bright_b, 1);
|
||||
global.lem_heads[l].SetImage(head_img);
|
||||
global.lem_heads[l].SetX(head_screen_x - 4);
|
||||
global.lem_heads[l].SetY(head_screen_y - 4);
|
||||
global.lem_heads[l].SetOpacity(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
fun update_log_display() {
|
||||
line_height = 16;
|
||||
start_y = global.divider_y + 15;
|
||||
left_margin = 30;
|
||||
|
||||
for (i = 0; i < global.max_log_lines; i++) {
|
||||
if (global.log_texts[i] != "") {
|
||||
/* Simple color based on content */
|
||||
if (String(global.log_texts[i]).Find("OK") >= 0 ||
|
||||
String(global.log_texts[i]).Find("Started") >= 0) {
|
||||
r = global.log_green_r;
|
||||
g = global.log_green_g;
|
||||
b = global.log_green_b;
|
||||
} else if (String(global.log_texts[i]).Find("warn") >= 0 ||
|
||||
String(global.log_texts[i]).Find("WARN") >= 0) {
|
||||
r = global.log_amber_r;
|
||||
g = global.log_amber_g;
|
||||
b = global.log_amber_b;
|
||||
} else {
|
||||
r = global.log_blue_r;
|
||||
g = global.log_blue_g;
|
||||
b = global.log_blue_b;
|
||||
}
|
||||
|
||||
txt_img = Image.Text(global.log_texts[i], r, g, b, "Mono 9");
|
||||
global.log_sprites[i].SetImage(txt_img);
|
||||
global.log_sprites[i].SetX(left_margin);
|
||||
global.log_sprites[i].SetY(start_y + i * line_height);
|
||||
global.log_sprites[i].SetOpacity(0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun update_phase() {
|
||||
phase_img = Image.Text(global.current_phase,
|
||||
global.blue_bright_r,
|
||||
global.blue_bright_g,
|
||||
global.blue_bright_b, "Sans Bold 11");
|
||||
global.phase_sprite.SetImage(phase_img);
|
||||
global.phase_sprite.SetX(global.lower_center_x - phase_img.GetWidth() / 2);
|
||||
global.phase_sprite.SetY(global.lower_center_y + 50);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Main Animation Loop
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
fun refresh_callback() {
|
||||
global.frame++;
|
||||
|
||||
/* Update cube rotations */
|
||||
for (c = 0; c < 3; c++) {
|
||||
global.cube_angle_x[c] += global.cube_speed_x[c];
|
||||
global.cube_angle_y[c] += global.cube_speed_y[c];
|
||||
global.cube_angle_z[c] += global.cube_speed_z[c];
|
||||
|
||||
/* Keep in bounds */
|
||||
if (global.cube_angle_x[c] > 6.28318) global.cube_angle_x[c] -= 6.28318;
|
||||
if (global.cube_angle_y[c] > 6.28318) global.cube_angle_y[c] -= 6.28318;
|
||||
if (global.cube_angle_z[c] > 6.28318) global.cube_angle_z[c] -= 6.28318;
|
||||
|
||||
draw_cube(c);
|
||||
}
|
||||
|
||||
/* Draw lemniscates */
|
||||
draw_lemniscates();
|
||||
|
||||
/* Update phase display */
|
||||
update_phase();
|
||||
}
|
||||
|
||||
Plymouth.SetRefreshFunction(refresh_callback);
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Plymouth Callbacks
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
fun boot_progress_callback(duration, progress_val) {
|
||||
global.boot_progress = progress_val;
|
||||
|
||||
/* Update progress bar */
|
||||
if (progress_fg) {
|
||||
bar_width = Math.Int(progress_val * 236);
|
||||
if (bar_width > 0) {
|
||||
scaled = progress_fg.Scale(bar_width, 12);
|
||||
progress_fg_sprite.SetImage(scaled);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update phase message based on progress */
|
||||
if (progress_val < 0.15) {
|
||||
global.current_phase = "Loading kernel modules...";
|
||||
} else if (progress_val < 0.30) {
|
||||
global.current_phase = "Initializing hardware...";
|
||||
} else if (progress_val < 0.50) {
|
||||
global.current_phase = "Starting system services...";
|
||||
} else if (progress_val < 0.70) {
|
||||
global.current_phase = "Configuring network...";
|
||||
} else if (progress_val < 0.90) {
|
||||
global.current_phase = "Starting SecuBox modules...";
|
||||
} else {
|
||||
global.current_phase = "System ready";
|
||||
}
|
||||
}
|
||||
|
||||
Plymouth.SetBootProgressFunction(boot_progress_callback);
|
||||
|
||||
fun message_callback(text) {
|
||||
/* Add to log buffer (scrolling) */
|
||||
/* Shift existing lines up */
|
||||
for (i = global.max_log_lines - 1; i > 0; i--) {
|
||||
global.log_texts[i] = global.log_texts[i-1];
|
||||
}
|
||||
|
||||
/* Add timestamp prefix */
|
||||
timestamp = Math.Int(global.frame / 60);
|
||||
ts_str = "[" + timestamp + "] ";
|
||||
global.log_texts[0] = ts_str + text;
|
||||
|
||||
update_log_display();
|
||||
}
|
||||
|
||||
Plymouth.SetMessageFunction(message_callback);
|
||||
|
||||
fun display_normal_callback() {
|
||||
/* Normal boot display */
|
||||
}
|
||||
|
||||
fun display_password_callback(prompt, bullets) {
|
||||
/* LUKS password prompt */
|
||||
prompt_img = Image.Text(prompt,
|
||||
global.blue_bright_r,
|
||||
global.blue_bright_g,
|
||||
global.blue_bright_b, "Sans Bold 12");
|
||||
global.phase_sprite.SetImage(prompt_img);
|
||||
global.phase_sprite.SetX(global.lower_center_x - prompt_img.GetWidth() / 2);
|
||||
global.phase_sprite.SetY(global.lower_center_y + 30);
|
||||
|
||||
/* Show bullet dots for password */
|
||||
bullet_str = "";
|
||||
for (i = 0; i < bullets; i++) {
|
||||
bullet_str += "*";
|
||||
}
|
||||
bullet_img = Image.Text(bullet_str, 1.0, 1.0, 1.0, "Mono 14");
|
||||
/* Could add another sprite for bullets */
|
||||
}
|
||||
|
||||
Plymouth.SetDisplayNormalFunction(display_normal_callback);
|
||||
Plymouth.SetDisplayPasswordFunction(display_password_callback);
|
||||
|
||||
fun quit_callback() {
|
||||
/* Fade out animation */
|
||||
for (c = 0; c < 3; c++) {
|
||||
for (v = 0; v < 8; v++) {
|
||||
idx = c * 8 + v;
|
||||
global.cube_vertices[idx].SetOpacity(0);
|
||||
}
|
||||
}
|
||||
|
||||
for (l = 0; l < 2; l++) {
|
||||
for (d = 0; d < global.dots_per_curve; d++) {
|
||||
idx = l * global.dots_per_curve + d;
|
||||
global.lem_dots[idx].SetOpacity(0);
|
||||
}
|
||||
global.lem_heads[l].SetOpacity(0);
|
||||
}
|
||||
|
||||
global.phase_sprite.SetOpacity(0);
|
||||
progress_bg_sprite.SetOpacity(0);
|
||||
progress_fg_sprite.SetOpacity(0);
|
||||
divider_sprite.SetOpacity(0);
|
||||
|
||||
for (i = 0; i < global.max_log_lines; i++) {
|
||||
global.log_sprites[i].SetOpacity(0);
|
||||
}
|
||||
}
|
||||
|
||||
Plymouth.SetQuitFunction(quit_callback);
|
||||
BIN
image/plymouth/secubox-cube/progress-bg-green.bak
Normal file
|
After Width: | Height: | Size: 306 B |
|
Before Width: | Height: | Size: 306 B After Width: | Height: | Size: 167 B |
BIN
image/plymouth/secubox-cube/progress-fg-green.bak
Normal file
|
After Width: | Height: | Size: 166 B |
|
Before Width: | Height: | Size: 166 B After Width: | Height: | Size: 166 B |
|
|
@ -1,127 +1,266 @@
|
|||
/* SecuBox Cube - Plymouth Theme Script
|
||||
* 3D Rotating Cube with Module Icons
|
||||
/* SecuBox Dice 3D - Plymouth Theme Script
|
||||
* Rotating 3D Cube with Module Icons on Faces
|
||||
* Nintendo 3DS aesthetic - dark blue autostereoscopic style
|
||||
* CyberMind - https://cybermind.fr
|
||||
*/
|
||||
|
||||
/* Screen setup */
|
||||
Window.SetBackgroundTopColor(0.0, 0.0, 0.0);
|
||||
Window.SetBackgroundBottomColor(0.02, 0.04, 0.02);
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Screen Setup - 3DS dark blue gradient background
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
Window.SetBackgroundTopColor(0.063, 0.082, 0.165); /* #101529 - 3DS top screen dark */
|
||||
Window.SetBackgroundBottomColor(0.039, 0.055, 0.118); /* #0a0e1e - 3DS deeper blue */
|
||||
|
||||
screen_width = Window.GetWidth();
|
||||
screen_height = Window.GetHeight();
|
||||
center_x = screen_width / 2;
|
||||
center_y = screen_height / 2;
|
||||
|
||||
/* Load images */
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Load Assets
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
logo = Image("logo.png");
|
||||
scanlines = Image("scanlines.png");
|
||||
|
||||
/* Module icons - 6 faces of the cube */
|
||||
icon_root = Image("icon-root.png");
|
||||
icon_boot = Image("icon-boot.png");
|
||||
icon_mesh = Image("icon-mesh.png");
|
||||
icon_wall = Image("icon-wall.png");
|
||||
icon_auth = Image("icon-auth.png");
|
||||
icon_mind = Image("icon-mind.png");
|
||||
|
||||
/* Progress bar images */
|
||||
progress_bg = Image("progress-bg.png");
|
||||
progress_fg = Image("progress-fg.png");
|
||||
|
||||
/* Create sprites */
|
||||
/* 6 face icons - one per cube face */
|
||||
face_images[0] = Image("icon-root.png"); /* Front - Root/System */
|
||||
face_images[1] = Image("icon-wall.png"); /* Back - Firewall */
|
||||
face_images[2] = Image("icon-boot.png"); /* Top - Boot */
|
||||
face_images[3] = Image("icon-mesh.png"); /* Bottom - Mesh Network */
|
||||
face_images[4] = Image("icon-auth.png"); /* Right - Auth */
|
||||
face_images[5] = Image("icon-mind.png"); /* Left - CyberMind */
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Create Sprites
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* Logo at top */
|
||||
logo_sprite = Sprite(logo);
|
||||
logo_sprite.SetX(center_x - logo.GetWidth() / 2);
|
||||
logo_sprite.SetY(center_y - 180);
|
||||
logo_sprite.SetY(center_y - 200);
|
||||
logo_sprite.SetZ(10);
|
||||
|
||||
/* Scanline overlay */
|
||||
/* Scanline overlay - subtle 3DS parallax barrier simulation */
|
||||
scanline_sprite = Sprite(scanlines);
|
||||
scanline_sprite.SetX(0);
|
||||
scanline_sprite.SetY(0);
|
||||
scanline_sprite.SetZ(100);
|
||||
scanline_sprite.SetOpacity(0.15);
|
||||
scanline_sprite.SetOpacity(0.04); /* Lighter for 3DS glass effect */
|
||||
|
||||
/* Module icon sprites - arranged in hexagon */
|
||||
icon_size = 64;
|
||||
radius = 100;
|
||||
icons[0] = Sprite(icon_root);
|
||||
icons[1] = Sprite(icon_boot);
|
||||
icons[2] = Sprite(icon_mesh);
|
||||
icons[3] = Sprite(icon_wall);
|
||||
icons[4] = Sprite(icon_auth);
|
||||
icons[5] = Sprite(icon_mind);
|
||||
|
||||
/* Initial positions */
|
||||
/* Face sprites - we'll show up to 3 visible faces */
|
||||
for (i = 0; i < 6; i++) {
|
||||
icons[i].SetZ(5);
|
||||
icons[i].SetOpacity(0.8);
|
||||
face_sprites[i] = Sprite(face_images[i]);
|
||||
face_sprites[i].SetOpacity(0);
|
||||
face_sprites[i].SetZ(5);
|
||||
}
|
||||
|
||||
/* Edge glow sprites - green wireframe effect */
|
||||
/* We'll draw edges as thin colored lines using scaled images */
|
||||
|
||||
/* Progress bar */
|
||||
progress_bg_sprite = Sprite(progress_bg);
|
||||
progress_bg_sprite.SetX(center_x - 150);
|
||||
progress_bg_sprite.SetY(center_y + 140);
|
||||
progress_bg_sprite.SetY(center_y + 160);
|
||||
progress_bg_sprite.SetZ(8);
|
||||
|
||||
progress_sprite = Sprite(progress_fg);
|
||||
progress_sprite.SetX(center_x - 148);
|
||||
progress_sprite.SetY(center_y + 142);
|
||||
progress_sprite.SetY(center_y + 162);
|
||||
progress_sprite.SetZ(9);
|
||||
|
||||
/* Status text */
|
||||
status_text = "";
|
||||
/* Status message */
|
||||
message_sprite = Sprite();
|
||||
message_sprite.SetPosition(center_x, center_y + 180, 10);
|
||||
message_sprite.SetPosition(center_x, center_y + 195, 10);
|
||||
|
||||
/* Animation state */
|
||||
angle = 0;
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Animation State
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
angle_x = 0;
|
||||
angle_y = 0;
|
||||
angle_z = 0;
|
||||
frame = 0;
|
||||
progress = 0;
|
||||
|
||||
/* Animation function - rotate icons in 3D-like pattern */
|
||||
fun animate_cube() {
|
||||
global.angle += 0.02;
|
||||
global.frame++;
|
||||
/* Cube size */
|
||||
cube_size = 80;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
/* Calculate 3D-like position */
|
||||
base_angle = global.angle + (i * 3.14159 / 3);
|
||||
/* Rotation speeds - 3DS-style smooth, elegant rotation */
|
||||
speed_x = 0.006;
|
||||
speed_y = 0.012;
|
||||
speed_z = 0.004;
|
||||
|
||||
/* X position - circular motion */
|
||||
x = center_x + Math.Sin(base_angle) * radius - icon_size / 2;
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* 3D Math Functions
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* Y position - elliptical for 3D effect */
|
||||
y = center_y + Math.Cos(base_angle) * (radius * 0.4) - icon_size / 2;
|
||||
/* Face normals in local space (which way each face points) */
|
||||
/* Face 0: Front (+Z) */
|
||||
/* Face 1: Back (-Z) */
|
||||
/* Face 2: Top (+Y) */
|
||||
/* Face 3: Bottom (-Y) */
|
||||
/* Face 4: Right (+X) */
|
||||
/* Face 5: Left (-X) */
|
||||
|
||||
/* Z-depth simulation via opacity and scale */
|
||||
depth = Math.Cos(base_angle);
|
||||
opacity = 0.4 + (depth + 1) * 0.3;
|
||||
fun get_face_visibility(face_index, ax, ay, az) {
|
||||
/* Calculate if face is visible (normal pointing toward camera) */
|
||||
/* Camera is at +Z looking at origin */
|
||||
|
||||
icons[i].SetX(x);
|
||||
icons[i].SetY(y);
|
||||
icons[i].SetOpacity(opacity);
|
||||
/* Simplified: calculate rotated normal Z component */
|
||||
/* If > 0, face is visible (pointing toward us) */
|
||||
|
||||
/* Bring front icons to top */
|
||||
if (depth > 0) {
|
||||
icons[i].SetZ(6);
|
||||
} else {
|
||||
icons[i].SetZ(4);
|
||||
}
|
||||
cos_x = Math.Cos(ax);
|
||||
sin_x = Math.Sin(ax);
|
||||
cos_y = Math.Cos(ay);
|
||||
sin_y = Math.Sin(ay);
|
||||
cos_z = Math.Cos(az);
|
||||
sin_z = Math.Sin(az);
|
||||
|
||||
/* Normal vectors for each face */
|
||||
if (face_index == 0) {
|
||||
/* Front (+Z): normal = (0, 0, 1) */
|
||||
nz = cos_x * cos_y;
|
||||
} else if (face_index == 1) {
|
||||
/* Back (-Z): normal = (0, 0, -1) */
|
||||
nz = -cos_x * cos_y;
|
||||
} else if (face_index == 2) {
|
||||
/* Top (+Y): normal = (0, 1, 0) */
|
||||
nz = sin_x;
|
||||
} else if (face_index == 3) {
|
||||
/* Bottom (-Y): normal = (0, -1, 0) */
|
||||
nz = -sin_x;
|
||||
} else if (face_index == 4) {
|
||||
/* Right (+X): normal = (1, 0, 0) */
|
||||
nz = -sin_y * cos_x;
|
||||
} else {
|
||||
/* Left (-X): normal = (-1, 0, 0) */
|
||||
nz = sin_y * cos_x;
|
||||
}
|
||||
|
||||
return nz;
|
||||
}
|
||||
|
||||
/* Progress callback */
|
||||
fun get_face_center(face_index, ax, ay, size) {
|
||||
/* Calculate projected 2D center of each face */
|
||||
cos_x = Math.Cos(ax);
|
||||
sin_x = Math.Sin(ax);
|
||||
cos_y = Math.Cos(ay);
|
||||
sin_y = Math.Sin(ay);
|
||||
|
||||
half = size / 2;
|
||||
|
||||
if (face_index == 0) {
|
||||
/* Front: center at (0, 0, +half) */
|
||||
x = sin_y * half;
|
||||
y = -sin_x * cos_y * half;
|
||||
z = cos_x * cos_y * half;
|
||||
} else if (face_index == 1) {
|
||||
/* Back: center at (0, 0, -half) */
|
||||
x = -sin_y * half;
|
||||
y = sin_x * cos_y * half;
|
||||
z = -cos_x * cos_y * half;
|
||||
} else if (face_index == 2) {
|
||||
/* Top: center at (0, +half, 0) */
|
||||
x = 0;
|
||||
y = cos_x * half;
|
||||
z = sin_x * half;
|
||||
} else if (face_index == 3) {
|
||||
/* Bottom: center at (0, -half, 0) */
|
||||
x = 0;
|
||||
y = -cos_x * half;
|
||||
z = -sin_x * half;
|
||||
} else if (face_index == 4) {
|
||||
/* Right: center at (+half, 0, 0) */
|
||||
x = cos_y * half;
|
||||
y = 0;
|
||||
z = -sin_y * half;
|
||||
} else {
|
||||
/* Left: center at (-half, 0, 0) */
|
||||
x = -cos_y * half;
|
||||
y = 0;
|
||||
z = sin_y * half;
|
||||
}
|
||||
|
||||
/* Return as pseudo-struct (array) */
|
||||
result[0] = x;
|
||||
result[1] = y;
|
||||
result[2] = z;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Animation Loop
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
fun animate_cube() {
|
||||
/* Update rotation angles */
|
||||
global.angle_x += global.speed_x;
|
||||
global.angle_y += global.speed_y;
|
||||
global.angle_z += global.speed_z;
|
||||
global.frame++;
|
||||
|
||||
/* Keep angles in bounds */
|
||||
if (global.angle_x > 6.28318) global.angle_x -= 6.28318;
|
||||
if (global.angle_y > 6.28318) global.angle_y -= 6.28318;
|
||||
if (global.angle_z > 6.28318) global.angle_z -= 6.28318;
|
||||
|
||||
/* Update each face */
|
||||
for (i = 0; i < 6; i++) {
|
||||
/* Check visibility */
|
||||
visibility = get_face_visibility(i, global.angle_x, global.angle_y, global.angle_z);
|
||||
|
||||
if (visibility > 0) {
|
||||
/* Face is visible */
|
||||
pos = get_face_center(i, global.angle_x, global.angle_y, global.cube_size);
|
||||
|
||||
/* Project to screen (orthographic with slight perspective feel) */
|
||||
depth_scale = 0.8 + (pos[2] / global.cube_size) * 0.2;
|
||||
|
||||
/* Scale icon based on depth */
|
||||
icon_scale = 0.6 + visibility * 0.4;
|
||||
icon_size = 64 * icon_scale * depth_scale;
|
||||
|
||||
/* Calculate screen position */
|
||||
screen_x = center_x + pos[0] * 1.5 - icon_size / 2;
|
||||
screen_y = center_y + pos[1] * 1.5 - icon_size / 2;
|
||||
|
||||
/* Scale the image */
|
||||
scaled = face_images[i].Scale(icon_size, icon_size);
|
||||
face_sprites[i].SetImage(scaled);
|
||||
|
||||
/* Position */
|
||||
face_sprites[i].SetX(screen_x);
|
||||
face_sprites[i].SetY(screen_y);
|
||||
|
||||
/* Opacity based on how directly it faces us + green tint simulation */
|
||||
opacity = 0.5 + visibility * 0.5;
|
||||
face_sprites[i].SetOpacity(opacity);
|
||||
|
||||
/* Z-order based on depth */
|
||||
face_sprites[i].SetZ(5 + pos[2] / 10);
|
||||
} else {
|
||||
/* Face not visible */
|
||||
face_sprites[i].SetOpacity(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 3DS-style gentle glow pulse - slower, more elegant */
|
||||
pulse = 0.90 + Math.Sin(global.frame * 0.03) * 0.10;
|
||||
logo_sprite.SetOpacity(pulse);
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* Plymouth Callbacks
|
||||
* ═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
fun refresh_callback() {
|
||||
animate_cube();
|
||||
}
|
||||
|
||||
Plymouth.SetRefreshFunction(refresh_callback);
|
||||
|
||||
/* Boot progress */
|
||||
fun boot_progress_callback(duration, progress_val) {
|
||||
global.progress = progress_val;
|
||||
|
||||
/* Scale progress bar */
|
||||
if (progress_fg) {
|
||||
scaled = progress_fg.Scale(progress_val * 296, 16);
|
||||
progress_sprite.SetImage(scaled);
|
||||
|
|
@ -130,26 +269,23 @@ fun boot_progress_callback(duration, progress_val) {
|
|||
|
||||
Plymouth.SetBootProgressFunction(boot_progress_callback);
|
||||
|
||||
/* Message display */
|
||||
fun message_callback(text) {
|
||||
global.status_text = text;
|
||||
|
||||
msg_image = Image.Text(text, 0, 1, 0.61, "JetBrains Mono");
|
||||
/* 3DS cyan/light blue text */
|
||||
msg_image = Image.Text(text, 0.400, 0.753, 0.925, "JetBrains Mono"); /* #66c0ec */
|
||||
message_sprite.SetImage(msg_image);
|
||||
message_sprite.SetX(center_x - msg_image.GetWidth() / 2);
|
||||
message_sprite.SetY(center_y + 180);
|
||||
message_sprite.SetY(center_y + 195);
|
||||
}
|
||||
|
||||
Plymouth.SetMessageFunction(message_callback);
|
||||
|
||||
/* Display normal/password prompts */
|
||||
fun display_normal_callback() {
|
||||
/* Nothing special */
|
||||
/* Normal display mode */
|
||||
}
|
||||
|
||||
fun display_password_callback(prompt, bullets) {
|
||||
/* Show password prompt */
|
||||
prompt_image = Image.Text(prompt, 0, 1, 0.61, "JetBrains Mono");
|
||||
/* Password prompt - 3DS cyan accent */
|
||||
prompt_image = Image.Text(prompt, 0.400, 0.753, 0.925, "JetBrains Mono"); /* #66c0ec */
|
||||
message_sprite.SetImage(prompt_image);
|
||||
message_sprite.SetX(center_x - prompt_image.GetWidth() / 2);
|
||||
}
|
||||
|
|
@ -157,13 +293,13 @@ fun display_password_callback(prompt, bullets) {
|
|||
Plymouth.SetDisplayNormalFunction(display_normal_callback);
|
||||
Plymouth.SetDisplayPasswordFunction(display_password_callback);
|
||||
|
||||
/* Quit callback */
|
||||
fun quit_callback() {
|
||||
/* Fade out */
|
||||
/* Fade out all elements */
|
||||
for (i = 0; i < 6; i++) {
|
||||
icons[i].SetOpacity(0);
|
||||
face_sprites[i].SetOpacity(0);
|
||||
}
|
||||
logo_sprite.SetOpacity(0);
|
||||
scanline_sprite.SetOpacity(0);
|
||||
}
|
||||
|
||||
Plymouth.SetQuitFunction(quit_callback);
|
||||
|
|
|
|||
|
|
@ -133,25 +133,33 @@ create_session() {
|
|||
chown -R "$KIOSK_USER:$KIOSK_USER" "$KIOSK_HOME/.config"
|
||||
|
||||
# Minimal session script - just Chromium, no optional tools
|
||||
# Use --start-fullscreen (not --kiosk) for better VT switching compatibility
|
||||
cat > "$KIOSK_HOME/.xsession" <<XSESSION
|
||||
#!/bin/bash
|
||||
# SecuBox Kiosk - Minimal X Session
|
||||
# SecuBox Kiosk - Minimal X Session (v1.6.3)
|
||||
export DISPLAY=\${DISPLAY:-:0}
|
||||
|
||||
# Log
|
||||
# Log startup
|
||||
logger -t secubox-kiosk "Starting Chromium kiosk: $url"
|
||||
|
||||
# Disable screensaver (ignore errors)
|
||||
# Disable screensaver and power management (ignore errors)
|
||||
xset s off 2>/dev/null || true
|
||||
xset -dpms 2>/dev/null || true
|
||||
xset s noblank 2>/dev/null || true
|
||||
|
||||
# Launch Chromium directly
|
||||
# Chromium flags for kiosk mode
|
||||
# --start-fullscreen: allows Ctrl+Alt+Fn VT switching (better than --kiosk)
|
||||
# --disable-gpu: avoid GPU issues in VMs
|
||||
# --no-sandbox: required in chroot/container environments
|
||||
# exec replaces shell with chromium - on exit, X session ends
|
||||
exec chromium \\
|
||||
--kiosk \\
|
||||
--start-fullscreen \\
|
||||
--no-first-run \\
|
||||
--no-sandbox \\
|
||||
--disable-gpu \\
|
||||
--disable-software-rasterizer \\
|
||||
--disable-pinch \\
|
||||
--noerrdialogs \\
|
||||
--disable-translate \\
|
||||
--ignore-certificate-errors \\
|
||||
--disable-features=TranslateUI \\
|
||||
--window-position=0,0 \\
|
||||
|
|
@ -201,7 +209,7 @@ start_display() {
|
|||
# ══════════════════════════════════════════════════════════════════
|
||||
main() {
|
||||
log "════════════════════════════════════════════════"
|
||||
log "SecuBox Kiosk Launcher v2.0"
|
||||
log "SecuBox Kiosk Launcher v2.1 (1.6.3)"
|
||||
log "════════════════════════════════════════════════"
|
||||
|
||||
check_prerequisites
|
||||
|
|
|
|||