The Problem
Samsung The Frame TVs present a minimal “home” interface that is hard to customize. Remote‑only navigation, no font or wallpaper change, and a single‑line clock make the TV feel inflexible. Developers need a lightweight, remote‑friendly UI that can be installed on the TV or previewed in a browser.
What This Does
app/index.html and app/main.js deliver a static web‑app that runs inside the TV browser. It renders a dock of app icons, a 12‑hour clock, and a selectable background image. The UI is built with vanilla JavaScript; no framework overhead is required. Fonts are bundled under app/assets/fonts/ (Manrope, Geist, Newsreader) and loaded via app/assets/fonts.css. Icon data lives in app/assets/icons/SOURCES.json; the actual SVGs are in app/assets/icons/*.svg. Wallpapers are served from app/assets/wallpapers/, with a catalog in app/assets/wallpapers/catalog.js. User preferences (selected wallpaper, icon order, font size) are stored in localStorage and restored on each load.
The repo also ships a set of build utilities in scripts/:
build-icon-metrics.mjs– generatesmetrics.jsused byapp/assets/icons/metrics.js.build-materials.mjs– pre‑renders blurred background images for each wallpaper.export-public.py– copies the built assets into a folder that can be copied to the TV’s public directory.
The CI pipeline (.github/workflows/check.yml) runs linting, static analysis, and the Python checks in scripts/check.py.
How It Is Wired
Entry → index.html → <script src="main.js">
main.js executes init() on load. init() performs:
loadAssets()– fetchesSOURCES.json,catalog.js, and the font files.renderDock()– creates the icon list in the DOM, attaches key handlers for arrow/Enter/Escape.applySettings()– readslocalStorage, sets wallpaper, font size, and icon order.initClock()– starts a 12‑hour timer that updates every minute.
renderDock() calls createIconElement(icon) for each entry; the function injects the SVG and adds focus/blur handlers. applySettings() writes to the DOM via document.querySelector() and updates CSS variables (--bg-image, --font-size).
The build scripts are invoked outside the runtime. build-icon-metrics.mjs reads the SVGs, calculates bounding boxes, and writes metrics.js. build-materials.mjs uses Canvas to blur wallpaper images and writes PNGs to app/assets/wallpapers/. These files are not accessed during the browser session; they are pre‑generated artifacts.
How To Use It
git clone https://github.com/nthnclrk/CleanFrame.git
cd CleanFrame
npm ci # installs dependencies from package.json
npm run dev:public # starts a dev server on 4795
Open http://localhost:4795/home/ in a browser. The interface is fully operable with arrow keys, Enter, and Escape.
To produce a TV‑ready bundle:
npm run build:public # outputs static assets to dist/public
# copy dist/public to the TV's public directory
No environment variables are required. All configuration lives in the asset files and the browser’s localStorage.
Real‑World Use
A homeowner can fork the repo, replace the SVGs in app/assets/icons/ with custom icons, edit catalog.js to reorder them, and run npm run build:public. The resulting dist/public can be copied to the TV, giving the user a “clean” home screen with their own branding.
Code Health & Issues
- CI workflow (
check.yml) passes linting and static checks. - Two test files exist under
tests/; they cover basic render logic. - No secrets or credentials are committed.
- The code is modular, but
main.jscontains severaldocument.querySelectorcalls that could be refactored into a small utility module for easier testing.
The Bottom Line
CleanFrame delivers a minimal, remote‑friendly home screen that runs in the TV browser and can be quickly adapted. It is lightweight, well‑structured, and ready for experimentation, but requires manual adaptation for other TV models or Tizen versions. Ideal for developers who want a starter template that works out‑of‑the‑box on Samsung The Frame.