VLC already takes screenshots. It does not remember when in the video each one was taken — snapshots are named by wall-clock time, so an hour later you have a folder of PNGs and no way back to the moment.
This plugin closes that gap. Press the snapshot key while watching: the video pauses, the frame is saved, and it is paired with the exact media position to the millisecond. Type a note, and playback resumes.
macOS, VLC 3.x. Tested against 3.0.23. install.sh uses defaults write,
which is macOS-only.
A folder beside the video, holding a notes.md you can read in any Markdown
editor:
<!-- generated by VLCNotes - edits here are overwritten on the next capture -->
# lecture01.mp4
`/Movies/lecture01.mp4`
## 00:12:34.080

the bit about eigenvalues
## 00:19:07.512
Quit VLC first. VLC rewrites its preferences from memory when it quits, so
installing while it runs would silently undo the setting that enables the
plugin. install.sh checks and refuses if it finds VLC running.
git clone https://github.com/TsungChiCheng/VLC_snapshot_plugin
cd VLC_snapshot_plugin
./install.shThis copies the plugin into VLC's Lua directory and enables the watcher — the background loop that detects snapshots and writes notes:
defaults write org.videolan.vlc extraintf -string "luaintf"
defaults write org.videolan.vlc lua-intf -string "vlcnotes_watcher"Without that, the plugin looks installed and does nothing; the panel reports
"Watcher not running." To set it by hand instead: VLC → Preferences → Show
All → Interface → Main interfaces, tick Lua interpreter, then under
Lua set Lua interface to vlcnotes_watcher.
Start VLC afterwards — preferences only take effect on the next launch.
The installer also offers to bind a shortcut for opening the panel. It is
opt-in, because it can overwrite a shortcut you already assigned to that menu
item. Pass --bind-key or --no-bind-key to skip the prompt.
| ⌘⌥S | Capture. Saves the frame, records the position, pauses playback. |
| ⌥⌘N | Open the notes panel (if you accepted the shortcut at install). |
Or open the panel from VLC menu → Extensions → VLC Timestamp Notes. That is the application menu at the top-left beside the Apple logo — not the View menu; extensions live under the app menu on this build.
To annotate: pick a capture in the dropdown, press Load selected, type in the note box, press Save Note. Playback resumes.
You do not have to annotate immediately. Capture as often as you like and come back later — every capture is already saved with its timestamp, with or without a note.
The panel also has Export HTML, which writes a notes.html contact sheet
of every screenshot and note.
For /Movies/lecture01.mp4:
/Movies/lecture01.notes/
notes.json source of truth
notes.md generated — do not hand-edit, it is overwritten
notes.html generated by Export HTML
00-12-34-080.png HH-MM-SS-mmm
Move the video and take the folder with it. If the video's directory is not
writable — a network share, a DVD — everything goes to ~/VLCNotes/<name>/
instead, and the real path is recorded inside notes.json.
notes.json is the source of truth. notes.md and notes.html are
regenerated from it, so hand-edits to those two are lost on the next
capture. Edit notes through the panel, or edit notes.json directly with
VLC closed.
Worth knowing before you rely on it:
- The panel cannot raise itself. A VLC extension has no timer and no event
loop — it runs only when you click something in it. Capturing pauses the
video, but you bring the panel up yourself (⌥⌘N, or the menu). This is a VLC
architecture limit, not an oversight:
playing-listenerandmeta-listenerwere both measured and neither fires. Seedocs/spike-findings.md. - A note can be lost if you save it at the exact moment a capture lands.
The panel and the watcher both write
notes.jsonwithout locking. Writes are atomic, so the file is never corrupted, but one of two simultaneous updates can win. In practice this needs sub-second timing. - Changing the plugin needs a full VLC restart. Extensions and interface scripts are compiled once at launch; reopening the panel re-runs cached code.
- macOS only. The core modules are portable Lua, but the paths, the installer and the menu locations are not.
Quit VLC first, same reason as install.
./uninstall.shRemoves the plugin's files and reverts the preferences install.sh set — only
if they still point at this plugin, and the keyboard shortcut is removed by
subkey so any other bindings you have survive. Your notes folders, and
~/VLCNotes, are never touched.
brew install luajit luarocks
luarocks --lua-version=5.1 --local install busted
luarocks --lua-version=5.1 --local install dkjson 2.1
export PATH="$HOME/.luarocks/bin:$PATH"
busted150 tests. The versions are pinned deliberately: VLC 3.0.23 embeds Lua 5.1
and bundles dkjson 2.1, and the suite runs against both so a test cannot
pass here and fail inside the player. Homebrew's default lua is 5.5, where
unpack is nil — testing against it gives false confidence in the dangerous
direction.
Two guards enforce this, and both fail loudly:
spec/environment_spec.lua— fails if Lua 5.1 or dkjson 2.1 drift.spec/purity_spec.lua— fails if any of the four core modules starts calling intovlc.*.
src/lua/modules/vlcnotes/ timecode, paths, store, render pure Lua, unit-tested
fs the VLC filesystem adapter
src/lua/intf/ vlcnotes_watcher.lua the only loop; owns all capture
src/lua/extensions/ VLCNotes.lua the panel
The four pure modules take everything they need — filesystem access, home
directory — as plain arguments, which is what makes them testable outside VLC
at all. fs.lua is the one module allowed to touch vlc.io. The watcher and
the panel cannot be unit-tested; they are verified against
docs/manual-checklist.md.
Both VLC-facing scripts require "vlcnotes.<module>" directly — VLC puts
lua/modules/ on the Lua package.path for interface scripts and extensions
alike, so there are no vendored copies.
docs/2026-08-13-vlc-timestamp-notes-design.html |
the design spec |
docs/spike-findings.md |
measured VLC platform quirks — read before touching the VLC-facing files |
docs/manual-checklist.md |
manual verification for the watcher and the panel |
MIT.