Lumen
A desktop video player for people who learn from recorded lectures — bookmarks and notes pinned to the exact second, a searchable transcript, course progress, and a library that survives moving and renaming your files.
A video player built for studying. No account, no cloud, no internet connection required.

- Role
- Design & build, end to end
- Scope
- Desktop app + Windows installer
- Stack
- Electron 38 · Vanilla JavaScript · HTML/CSS
- Type
- In-house product, no client
The brief
Mainstream video players are built for watching films. A student working through a forty-lecture course needs something else: to mark the moment a derivation starts, to write a note without losing their place, to repeat thirty seconds until it makes sense, and to know which lectures are done.
The ask was a player for local files that feels smooth and premium, plays the formats courses actually come in, and treats study tools as first-class features rather than plugins. No account, no cloud, no internet connection required.
One constraint shaped the rest — the notes are the product. A player that loses a term's worth of notes because a folder was renamed, or because the laptop died mid-save, has failed at the only thing that makes it different. So the data layer got as much attention as the playback.
What shipped
- Playback for MP4, MKV, WebM, MOV and nine other video and audio formats, with resume-where-you-left-off per file
- Speed from 0.25× to 4×, volume up to 200%, frame-by-frame stepping, an A–B loop, picture-in-picture and always-on-top
- Bookmarks and notes pinned to a timestamp and shown as markers on the timeline; a note can carry a snapshot of the current frame and export to Markdown
- External subtitles (SRT, VTT) with size and delay controls, plus a searchable, clickable transcript panel
- Course folders as playlists with per-video progress, a completed count, and “continue watching” on the home screen
- A focus timer that pauses the video when the session ends, and daily study stats with a streak
- A Windows installer that registers the app for 13 media file types, with no admin rights needed
- keyboard shortcuts
- 25
- media formats
- 13
- automated tests on the data layer
- 19
- runtime dependencies
- 0
Decisions, and why
Anyone can list a stack. The useful part of a case study is the calls that had a real alternative — so each of these says what the tradeoff was, not just what was chosen.
- 01
The browser engine is the decoder
Play media with Chromium's built-in decoders instead of bundling a media engine.
Electron already ships a hardware-accelerated decoder for H.264, VP9 and AV1 in MP4, MKV and WebM, which is what recorded lectures are. Bundling a separate engine would have doubled the install size and added a native dependency to maintain for formats students rarely meet.
Tradeoff · Files that need those extra decoders are named plainly and refused with a message, rather than opening to a black screen with no explanation.
- 02
No framework, no build step
Plain JavaScript modules, hand-written CSS, zero runtime dependencies.
The interface is one window with one video and a side panel. The parts that must be fast — the progress bar, the subtitles and the loop check — run in a single animation-frame loop that touches the DOM directly. A framework would have added a layer between that loop and the screen.
Tradeoff · Rendering is manual and the interface logic lives in one large module. That is the right size for a single window, and a second window is the point to reconsider it.
- 03
A video has an identity, not a path
Every video gets its own ID and a content fingerprint; notes hang off the ID.
Students reorganise folders constantly. Keying notes by file path means a rename orphans them; keying by file name merges “Physics/Lesson 01” with “Biology/Lesson 01”. The fingerprint is the file size plus a hash of three 64 KB samples, so a multi-gigabyte lecture is identified in milliseconds without reading it all.
Tradeoff · It is a sampled hash rather than a full one, and when the original still exists a copy is treated as a new file and starts fresh — the safer of the two possible mistakes.
- 04
One JSON file, made hard to lose
Keep the library in a single JSON file rather than a database, and spend the effort on recovery.
The data is small and the user should be able to read it. Every save keeps the previous version as a backup, a snapshot is taken once a day for seven days, a damaged file is set aside rather than overwritten, and a schema version drives automatic migrations.
Tradeoff · The whole file is rewritten on each save. That is invisible for hundreds of videos and would need rethinking in the tens of thousands.
- 05
Local files are streamed through a custom protocol
The app serves media to itself over its own app:// scheme with byte-range support.
Loading videos straight from disk paths makes them a different origin from the interface, which blocks frame snapshots, and gives no control over what the interface can read. A custom scheme makes seeking in large files work, keeps snapshots possible, and puts one checkpoint in front of the file system.
Tradeoff · The range handling and stream back-pressure are our own code rather than the platform's — which is also what makes the checkpoint possible in the first place.
- 06
The interface can only read what a player needs
The media route serves playable file types and the app's own snapshots, nothing else.
A review of the first version found the media route would hand any file on disk to the interface. Nothing exploited it, since the app loads no remote content, but a player has no reason to be able to read your documents. The rules now live in one small module with tests, and every system call checks it came from the app's own page.
Tradeoff · Supporting a new format means touching the allow-list, not just the file dialog — which is the point: the list is the thing that is checked.
- 07
Shortcuts follow the key, not the letter
Keyboard shortcuts are bound to physical key positions.
The first audience types in Arabic. Bound to letters, every shortcut would die the moment the keyboard layout switched, mid-lecture, with no explanation. Bound to positions, B is always bookmark.
Tradeoff · On layouts that move the letters, such as AZERTY, the printed key and the shortcut can disagree — the rarer case, and the one that does not break mid-lecture.
- 08
Subtitles are parsed and drawn by the app
A custom subtitle parser and overlay instead of the browser's built-in text tracks.
Owning the cues is what makes the transcript panel possible — search a phrase, click a line, jump to it. It also allows a delay control, a size control, and decoding of older Arabic subtitle files saved in Windows-1256, which the built-in tracks render as noise.
Tradeoff · SRT and VTT are what it reads. Styled ASS subtitles and tracks embedded inside the video file are outside the scope, and the panel is what was bought with that.
- 09
A note belongs to the moment you started writing it
The timestamp is taken when typing begins, and the video pauses while you type.
By the time a sentence is finished, the lecture has moved on thirty seconds. Stamping the note on save would point at the wrong moment every time. Pausing means nothing is missed while writing.
Tradeoff · It is an opinion about how people study, so the pause can be switched off by anyone who disagrees with it.
Notes that survive
The hardest part of the build was not playback. It was making sure a semester of notes cannot quietly disappear. Three things threaten them: the file moves, the app dies mid-save, or a future version changes the data format.
Each was handled and then checked. Moving: a lecture was bookmarked and annotated, moved to another folder and renamed, then reopened — the app recognised it by fingerprint and reported that the notes had been reconnected. Dying mid-save: a library file was deliberately truncated halfway through a record; on the next start the app restored the last good version, kept the damaged file for inspection, and said what it had done. Changing format: a version-1 library, keyed by path, was migrated to version 2 with every note, bookmark and position intact, and a pre-migration copy left beside it.
Those cases are now 19 automated tests, including the awkward ones: a copy must not steal the original's notes, two moved files with identical content must each keep one record, and a damaged file must never overwrite a good backup. The work also surfaced a real bug — closing the window mid-video lost the playback position, because the save message could arrive after the app had already quit. Closing now saves synchronously, and reopening resumes at the second you left.
What was deliberately left out
Scope discipline is part of the work. Each of these was considered and cut for a stated reason.
- Extra decoders for older formats
- Needs a bundled media engine. Not worth doubling the install size for formats lectures rarely use.
- Accounts and cloud sync
- The app works offline with no sign-up, and notes stay on the user's machine. Sync needs a backend to mean anything.
- AI summaries
- No specific job was identified that the transcript and the notes do not already do.
- Embedded subtitle and audio tracks
- The browser engine does not expose them reliably. An external subtitle file covers the common case.
- Code signing and auto-update
- Both need a paid certificate and an update server. The installer works without them.
- An Arabic interface
- The interface is English for now. Arabic notes, labels and subtitles are fully supported, including right-to-left text.
The data layer is covered by automated tests; playback and the interface are checked by hand and by a scripted smoke run, not by an automated suite. The installer is unsigned, so Windows shows a SmartScreen prompt on first run. Lumen is a version 1.0 and has not been released publicly. It is built and tested on Windows only.
Stack
- Electron 38
- JavaScript
- HTML
- CSS
- Node.js
Services
- Product design
- Desktop engineering
- Interface engineering
- Data design
- Packaging
Need something built to this standard?
We design and build complete systems — a purchase path that works, roles, and an admin panel that actually runs the business. And Arabic here is never a translation layer bolted on at the end.
