atlus/ATLUS_CONTEXT.md
roberts f9743bb29a Initial commit — Atlus web desktop environment for SBCs
Full-stack implementation: FastAPI backend with PAM auth, WebSocket
stats/terminal, and vanilla JS frontend with tiling desktop shell.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 16:53:46 -05:00

23 KiB
Raw Permalink Blame History

Atlus — Project Context

What Is Atlus?

Atlus is a lightweight, web-based desktop environment designed for headless single-board computers (SBCs) such as the Orange Pi, Raspberry Pi, and similar ARM-based Linux systems. It provides a browser-accessible interface that replaces the need for SSH or VNC for everyday system management tasks.

The goal is not to replicate a full desktop environment — it is to provide the right tools for managing a headless SBC in a way that feels natural, fast, and accessible from any device on the local network.


Problem Statement

Headless SBCs are increasingly used as always-on servers, astrophotography rigs, NAS boxes, home automation hubs, and more. Current management options are:

  • SSH — powerful but unfriendly for non-developers and tedious for routine tasks
  • VNC / noVNC — requires a full desktop environment, heavy, slow, not purpose-built
  • Cockpit / Webmin — generic server admin tools, not tailored to SBC use cases, complex UI

There is no lightweight, purpose-built web desktop for SBCs that feels like an OS rather than a server admin panel.


Core Philosophy

  • Web-native first — no X server required for core functionality
  • Purposefully minimal — only the tools that matter for headless SBC management
  • Locally hosted — runs entirely on the SBC, no cloud dependency
  • Accessible from anything — phone, tablet, laptop — any browser on the local network
  • Tiling over floating — apps open in the center stage, not as draggable windows
  • Extensible — apps/widgets can be added as plugins

Target Users

  • Makers and hobbyists running headless SBCs for specific purposes (astrophotography, NAS, IoT, etc.)
  • Home lab users who want lightweight management without full desktop overhead
  • Anyone who currently lives in SSH and wishes there was something better

Finalized Layout — Three-Column Shell

The Atlus UI is a fixed three-column layout inspired by tiling window managers (awesomewm, i3). There are no draggable or floating windows. Everything is tiled, cascaded, or tabbed within the center stage.

┌────────┬─────────────────────────────┬────────────────┐
│        │  Stage Tab Bar              │                │
│  Left  ├─────────────────────────────┤  Right Panel   │
│  Dock  │                             │                │
│        │     Center Stage            │  - Hostname    │
│ App    │     (active app view)       │  - Date/Time   │
│ Icons  │                             │  - Network     │
│        │     One app at a time,      │  - CPU/RAM/    │
│ (vert) │     or tiled side-by-side   │    Disk/Temp   │
│        │                             │  - Services    │
│ Gear   ├─────────────────────────────┤    (toggles +  │
│ (foot) │  Layout Controls (tab bar)  │    open → )    │
└────────┴─────────────────────────────┴────────────────┘

Left Dock

  • Vertical strip of app launcher icons — no labels, tooltip on hover
  • Top: Atlus "A" logo — opens a system menu (shutdown, restart, about)
  • Core apps listed in order (configurable in settings)
  • Separator line between core apps and plugins
  • Bottom: Settings gear icon (always pinned)
  • Active app highlighted with accent border/background
  • Badge dot on plugin icons when they have status to report (e.g. ASI Bridge syncing)

Center Stage

  • The primary content area — full height, fills remaining width
  • One app visible at a time by default
  • Tab bar at top shows all open apps; click to switch (previous app minimizes)
  • Layout toggle buttons (top-right of tab bar) switch between:
    • Single pane (full width)
    • Horizontal split (two panes side-by-side, 50/50 default)
    • Vertical split (stacked, stretch goal)
  • Each pane has its own macOS-style titlebar (traffic light dots + title)
  • When a second app is opened in split mode, it takes the secondary pane

Right Panel

  • Always visible, fixed width (~220px), never replaced by an app
  • Top section: Hostname, date, time (live), WiFi name + status, Ethernet status
  • Middle section: Live system stats — CPU %, Memory used/total, Storage %, CPU temp
    • Each stat: compact uppercase label + current value + colored progress bar
    • Colors: green (healthy), amber (moderate), red (high)
  • Bottom section: Services list
    • Each service: toggle (on/off), name, ↗ open button
    • Toggle maps to systemctl start/stop
    • ↗ opens that service's detail/control view in the center stage
    • Services list is configurable per deployment

Architecture Overview

Backend Daemon

  • Language: Python (FastAPI + asyncio)
  • Runs as a systemd service on boot
  • Exposes a REST API and WebSocket endpoint
  • Responsibilities:
    • File system access and management
    • Systemd service control (start/stop/restart/status)
    • Process/task enumeration
    • System stats (CPU, RAM, disk, network, temperature) via psutil
    • Notification/event bus (watches logs, mount points, service states)
    • X11 app process spawner (Xvfb + x11vnc per app — Phase 4 only)

Frontend

  • Language: Vanilla JS + CSS (no framework — keep it lightweight and portable)
  • No build step — served directly as static files by the FastAPI backend
  • Communicates via REST for actions, WebSocket for live stat updates
  • CSS custom properties for theming
  • IBM Plex Mono for system data; Inter for UI chrome

X11 App Embedding (Phase 4 — Optional/Advanced)

  • For GUI apps that require X (e.g., Nextcloud desktop client)
  • Each app spawns its own Xvfb virtual framebuffer
  • x11vnc streams that framebuffer over WebSocket via noVNC
  • Embedded as a pane in the center stage — not a floating window
  • Isolated per-app — no shared display, no full desktop environment needed

Built-in Apps (Core)

⚙️ System Settings

The unified configuration hub for the SBC. Organized into sections:

  • General — System name/hostname, date & time (manual or NTP), timezone
  • Users — User management, password changes, add/remove users
  • Security — Screen lock timeout, session timeout, auth settings
  • Applications — Choose which apps appear in the dock; enable/disable on startup
  • Services — Which systemd services appear in the right panel; autostart configuration
  • Network — Per-interface settings (WiFi SSID/password, static IP vs DHCP, DNS); shown for all detected interfaces (eth0, wlan0, etc.)
  • Storage / Automount — USB automount rules, mount point configuration, eject behavior
  • About — Atlus version, system info, OS details

📟 Terminal

A fully functional web-based terminal. No restrictions, no simplifications — behaves identically to SSH or a local terminal session. Powered by xterm.js on the frontend and ptyprocess on the backend for a real PTY.

Custom On-Screen Keyboard (Critical)

The system keyboard (iOS/Android) is never triggered. Atlus uses its own purpose-built on-screen keyboard for all terminal input. This is non-negotiable — the native keyboard is hostile to terminal use (autocorrect, autocapitalize, no Escape, no function keys, unpredictable behavior).

How it works technically:

  • The xterm.js terminal canvas is focused but never triggers a system keyboard (it is not an <input> or <textarea>)
  • All key input is intercepted via the custom keyboard UI — keys send characters directly to the terminal via terminal.input(char) and escape sequences for special keys
  • The terminal pane never calls .focus() on any element that would summon the system keyboard
  • inputmode="none" set on any focusable elements within the terminal pane as a belt-and-suspenders measure

Custom keyboard layout — three rows:

Row 1 (special/modifier):
[ Esc ] [ Tab ] [ Ctrl ] [ Alt ] [ ` ] [ ~ ] [ | ] [ \ ] [ / ]

Row 2 (function keys, scrollable):
[ F1 ] [ F2 ] [ F3 ] [ F4 ] [ F5 ] [ F6 ] [ F7 ] [ F8 ] [ F9 ] [ F10 ] [ F11 ] [ F12 ]

Row 3 (navigation):
[ ↑ ] [ ↓ ] [ ← ] [ → ] [ Home ] [ End ] [ PgUp ] [ PgDn ] [ Del ]

Modifier key behavior:

  • Ctrl, Alt are sticky — tap once to arm, next key sends the combo (e.g. Ctrl → C sends \x03)
  • Armed modifier keys are visually highlighted
  • Double-tap a modifier to lock it (Ctrl+lock for vim, etc.)

Standard alphanumeric input:

  • A compact QWERTY layout below the special rows handles letter/number/symbol input
  • Numbers row across the top of the QWERTY section
  • Shift key for capitals — also sticky
  • Common terminal symbols promoted to easy reach: $, #, >, -, _, .

Keyboard can be:

  • Toggled show/hide via a keyboard icon button in the terminal pane titlebar
  • Resized (compact vs. full) — compact shows only the special row + QWERTY condensed
  • On physical keyboard connected to iPad: custom keyboard hides, physical keys work natively through xterm.js

Other terminal features:

  • Full color output, cursor control, scrollback
  • Resize-aware (terminal resizes with the pane, keyboard height accounted for)
  • Copy: long-press selection in terminal → copy action
  • Paste: paste button on keyboard toolbar injects clipboard content via terminal.input()
  • Multiple terminal tabs within the terminal pane (Phase 2)

🗂 File Manager

Unique dual-pane design. Key characteristics:

  • Single or dual folder view — toggle between one panel (full width) and two side-by-side panels
  • List view only — no icon grid; each row shows: icon type indicator, filename, size, modified date, permissions
  • Drag and drop — files can be dragged between panels or into folders within a panel
  • Sidebar — shows filesystem tree: home, root, and all detected mounts (USB, SMB, etc.)
  • Features per file/selection:
    • Preview (text, image, FITS header for astrophotography files)
    • Compress / extract (zip, tar.gz)
    • Copy, move, rename, delete
    • Properties (permissions, owner, size on disk)
  • Mount management — right-click a mount point to unmount; USB devices show an eject option
  • Path bar — editable breadcrumb path at the top of each panel
  • No thumbnails — performance-first; list only

📊 Task Manager

htop-inspired, but scoped and web-native. Shows:

  • Process list: PID, name, CPU %, MEM %, status, user
  • Sortable columns
  • Kill / signal process action
  • Filter to show only Atlus-relevant processes (or toggle to show all)
  • Summary bar at top: total CPU, RAM, load average — mirrors the right panel stats but with more detail
  • Auto-refreshes every 2 seconds via WebSocket

🌐 Network Monitor

Per-interface detail view:

  • Interface name, MAC, state (up/down)
  • IP addresses (IPv4 + IPv6)
  • Gateway, DNS servers
  • Live throughput (bytes in/out per second)
  • For WiFi: SSID, signal strength, frequency band

🔧 Settings

(see System Settings above — Settings is the dock entry point into the System Settings app)


Plugin Apps (Installable)

App Dock Icon Description
ASI Bridge 🔭 ASI Air mount status, transfer log, Nextcloud sync, session summary
Log Viewer 📝 Real-time tail of any systemd service log via WebSocket
INDI Control (future) INDI server management for astrophotography rigs

Design Language

Aesthetic

  • Dark, utilitarian, refined — high-end terminal meets modern OS
  • Inspired by: awesomewm, macOS terminal, Linear app
  • Flat — no gradients, no heavy shadows, no decorative elements

Typography

  • IBM Plex Mono — all system data, file paths, IPs, timestamps, terminal output
  • Inter — UI chrome, labels, app names, navigation
  • Two weights only: 400 regular, 500 medium

Color System

  • Background layers (dark → light): #0d0f14#111318#161b27
  • Borders: #1e2130 (structural), #2a2d36 (component-level)
  • Text: #c8ccd8 (primary), #8891a8 (secondary), #4a5068 (muted), #2e3348 (ghost)
  • Accent (active/selected): #6ea6f0
  • Status: #3ab86a (ok/green), #e09a2a (warning/amber), #e05a4a (error/red)

Motion

  • Subtle only: tab switches, service toggle state, stat bar transitions
  • Status values update live via WebSocket — no manual refresh needed

Touch-First Design — Primary Target: iPad & Tablets

Atlus is touch-first. Desktop mouse/keyboard is secondary. Every interaction must be comfortable with a finger on a tablet screen. This affects every component.

Touch Target Sizing

  • Minimum tap target: 48×48px for all interactive elements (Apple HIG / Material guidelines)
  • Dock icons: 56×56px minimum hit area
  • File rows: minimum 48px tall
  • Settings rows: minimum 48px tall
  • Service toggles: at least 44px tall hit area (even if visually smaller)
  • Tab bar items: minimum 44px tall
  • All buttons: minimum 44px tall

No Hover Dependency

  • No tooltips as primary labels — dock icons must show a label below the icon (not on hover)
  • No hover-only states for anything critical
  • All context menus triggered by long-press, not right-click
  • Hover styles may exist as a progressive enhancement for mouse users, but never as the only way to discover functionality

Gesture Support

  • Swipe left/right on the center stage to switch between open apps (like iOS app switching)
  • Swipe right from left edge to reveal/toggle the dock on smaller screens
  • Swipe left from right edge to reveal/toggle the right panel on smaller screens
  • Long-press on files for context menu (cut, copy, rename, delete, compress, properties)
  • Long-press on dock icon for app options (remove from dock, move)
  • Pull down on file list to refresh directory
  • Pinch to zoom in terminal and file preview — browser native

Layout Adaptations for Touch

Landscape (primary tablet orientation):

  • Three-column layout as designed — dock (72px wide), stage (flex), right panel (240px)
  • Dock shows icon + label underneath (not tooltip)
  • All rows/items generously spaced

Portrait / Narrow screens:

  • Dock collapses to a slide-in drawer (swipe from left or tap hamburger)
  • Right panel collapses to a slide-in drawer (swipe from right or tap info button in tab bar)
  • Center stage goes full-width
  • Tab bar remains visible at top

Phone (stretch goal, not v1):

  • Bottom tab bar replaces left dock
  • Right panel accessible via bottom sheet

File Manager — Touch Adaptations

  • Row height: 52px minimum
  • Drag and drop uses touch drag (touchstart/touchmove/touchend events) not mouse drag
  • Selection via long-press + drag, or tap checkbox mode
  • Checkbox mode: tap a file to enter selection mode, then tap others to multi-select
  • Context menu on long-press: open, preview, copy, move, rename, compress, delete
  • No right-click context menu (or: right-click works as fallback for mouse users)

Terminal — Touch Adaptations

  • Software keyboard appears automatically on tap
  • Toolbar of common keys above the software keyboard: Escape, Tab, Ctrl, arrow keys, pipe, tilde
  • Pinch to adjust font size
  • Two-finger scroll for scrollback

Settings — Touch Adaptations

  • All form rows 52px+ tall
  • Toggle switches 51×31px (standard iOS-style)
  • Sidebar nav items 48px tall minimum
  • Save/cancel buttons large and thumb-reachable (bottom of content, full-width or right-aligned with generous padding)

Right Panel — Touch Adaptations

  • Service rows 52px tall — the toggle and ↗ button are both easy targets
  • On narrow screens: collapses, accessible via swipe or button

General Touch Rules

  • No double-click interactions — everything single tap or long-press
  • Scroll areas must be -webkit-overflow-scrolling: touch (momentum scrolling)
  • touch-action set appropriately on draggable items
  • Input fields: font-size: 16px minimum to prevent iOS auto-zoom on focus
  • Avoid position: fixed where possible — use position: sticky for headers/toolbars
  • All modals/dialogs centered and thumb-reachable, not tiny desktop-style popups

Astrophotography Reference Deployment

The initial real-world deployment target:

[ASI Air]  ──ethernet──▶  [Orange Pi 5 Max / Atlus]  ──nextcloud──▶  [Home Server]
192.168.10.120              192.168.10.121 (eth to ASI Air)
                            192.168.1.121  (wifi to home network)

The ASI Bridge plugin panel shows:

  • ASI Air SMB mount status (connected / disconnected / error)
  • Nextcloud client sync status (idle / syncing / error)
  • Live transfer log (filename, size, timestamp, sync result)
  • Session summary (frames captured tonight, total GB transferred)
  • Quick actions: remount share, restart sync service, clear log

Tech Stack

Component Technology
Backend Python 3.11+, FastAPI, asyncio, uvicorn
WebSockets FastAPI WebSocket
System stats psutil
Terminal xterm.js (frontend) + ptyprocess (backend)
File ops Python pathlib / os
Service mgmt subprocess + systemctl
X11 embedding Xvfb + x11vnc + noVNC (Phase 4 only)
Frontend Vanilla JS, CSS custom properties, no build step
Fonts IBM Plex Mono + Inter (Google Fonts CDN or self-hosted)
Packaging Single systemd service + install.sh bootstrap script
Target OS Debian/Ubuntu ARM64 (DietPi, Armbian, Raspberry Pi OS)

Project Phases

Phase 1 — Core Shell (start here)

  • Repo and project structure setup
  • FastAPI backend — /api/stats endpoint (CPU, RAM, disk, temp, network IPs)
  • WebSocket endpoint — push live stats every 2s
  • Static frontend served by FastAPI
  • Three-column shell layout (dock, stage, right panel) — HTML/CSS skeleton
  • Right panel wired to live WebSocket stats + clock
  • Left dock with app icons and active state
  • Terminal app — xterm.js frontend + ptyprocess PTY backend
  • App switching — clicking dock icon loads app into center stage

Phase 2 — File Manager + Service Control

  • File Manager — directory listing, navigate, breadcrumb path, sidebar mounts
  • Service Manager — list systemd units, start/stop/restart via API
  • Right panel service toggles wired to real systemctl calls
  • Log Viewer — real-time tail of service logs via WebSocket stream
  • Split pane layout — two apps tiled side by side

Phase 3 — Plugin System + ASI Bridge

  • Plugin architecture — self-contained module (backend route + frontend panel JS)
  • ASI Bridge plugin — mount watcher, transfer log, Nextcloud sync status
  • Settings app — configure dock items, services list, hostname display

Phase 4 — X11 App Embedding (advanced)

  • Xvfb process spawner via API call
  • x11vnc per-app streaming to WebSocket
  • noVNC embedded as a center stage pane
  • Nextcloud Qt client embedded as live X11 panel

Finalized Project Decisions

Decision Answer
Project type Single monorepo — frontend served by FastAPI backend
Framing Full desktop environment — not a server admin panel
Authentication Username + password (session token after login)
Default port 7779
Installation curl | bash installer script
License GPL
Theming Dark only for v1 — light mode planned, CSS variables structured for it from day one
Target OS DietPi (Debian ARM64) — installer targets DietPi, Armbian, Ubuntu Server as fallbacks
Terminal sessions Multiple — tabbed terminals within the terminal pane
Boot / login Branded login/boot screen before the desktop loads
Filesystem access Full — same as any desktop environment
Terminal user Runs as the logged-in system user
Multiple clients Yes — multiple browsers/devices can connect simultaneously, all receive live WebSocket updates
File operations Confirm destructive actions only (delete, overwrite)
Service detection Auto-detect all systemd services — user manages visibility in Settings
ASI Bridge when disconnected Show disconnected badge — still openable, shows a disconnected state screen
Plugin (ASI Bridge) Built-in from day one, bundled with Atlus core
Dock order Hard-coded for v1, configurable in Settings v2
Right panel width Fixed 240px for v1

Project Structure (Monorepo)

atlus/
├── README.md
├── LICENSE                    # GPL
├── install.sh                 # curl | bash installer
├── atlus.service              # systemd unit file template
│
├── backend/
│   ├── main.py                # FastAPI app entry point
│   ├── config.py              # Config, paths, constants
│   ├── auth.py                # Username/password auth, session tokens
│   ├── routers/
│   │   ├── stats.py           # /api/stats — CPU, RAM, disk, temp, network
│   │   ├── files.py           # /api/files — filesystem operations
│   │   ├── services.py        # /api/services — systemd management
│   │   ├── processes.py       # /api/processes — task manager
│   │   ├── terminal.py        # /api/terminal — PTY websocket
│   │   ├── settings.py        # /api/settings — read/write config
│   │   └── plugins/
│   │       └── asi_bridge.py  # ASI Air bridge plugin routes
│   ├── ws/
│   │   └── manager.py         # WebSocket connection manager (multi-client broadcast)
│   └── requirements.txt
│
├── frontend/
│   ├── index.html             # Login/boot screen
│   ├── desktop.html           # Main desktop shell
│   ├── css/
│   │   ├── variables.css      # CSS custom properties (colors, spacing, typography)
│   │   ├── shell.css          # Three-column layout
│   │   ├── dock.css
│   │   ├── panel.css
│   │   ├── stage.css
│   │   ├── keyboard.css       # Custom on-screen keyboard
│   │   └── apps/
│   │       ├── terminal.css
│   │       ├── files.css
│   │       ├── settings.css
│   │       └── tasks.css
│   ├── js/
│   │   ├── atlus.js           # Core shell, app switching, WebSocket client
│   │   ├── auth.js            # Login screen logic
│   │   ├── keyboard.js        # Custom on-screen keyboard
│   │   └── apps/
│   │       ├── terminal.js    # xterm.js + PTY integration
│   │       ├── files.js       # File manager
│   │       ├── settings.js    # Settings app
│   │       ├── tasks.js       # Task manager
│   │       ├── services.js    # Service manager
│   │       └── asi_bridge.js  # ASI Bridge plugin panel
│   └── assets/
│       └── atlus-logo.svg
│
└── plugins/                   # Future third-party plugins live here

Open Questions (Deferred — Not Blocking v1)

  • Portrait collapse behavior: Slide-in drawers vs. bottom tab bar — decide when building responsive CSS
  • Terminal keyboard quick-key row: Exact key selection — decide during keyboard build

Last updated: 2026-03-13 Project status: Planning complete — all decisions finalized — ready to build Phase 1