Work tagtable
desktop

TagTable

RFID video kiosk — place a tagged object on the reader, the right video plays.

TagTable is a fullscreen Windows kiosk app for museums, retail installs, and interactive exhibits. It listens to a USB HID RFID reader (EM4100/TK4100 125kHz tags) and plays a mapped 4K video the moment a tagged object lands on the table. Hardware-accelerated playback, an admin panel behind Ctrl+Shift+A for tag→video mapping, customizable idle logo, optional DMX lighting cues, and a mock mode for development without the reader connected.

Last updateMar 4, 2026 PrimaryRust
  • JavaScript
  • Electron 33
  • Node.js
  • serialport
  • osc-js
  • electron-builder
  • Inno Setup
  • Rust
  • egui
TagTable — RFID video kiosk — place a tagged object on the reader, the right video plays.

TagTable is a fullscreen Windows kiosk app for tag-driven video — place an RFID-chipped object on the reader and the corresponding 4K clip starts playing. Built for museums, retail showcases, and interactive exhibits where the interaction model is "pick something up, see what it tells you." Hardware-accelerated playback, near-instant tag-to-video latency, admin panel behind Ctrl+Shift+A, mock mode for development without the reader plugged in.

What it actually does

  • RFID tag detection via USB HID — talks to any EM4100 / TK4100 125kHz reader that enumerates as a keyboard. Tag UID arrives, the engine looks up the mapped video, the kiosk swaps to it. No server round-trip; the whole map lives on disk.
  • Hardware-accelerated 4K video. The Rust prototype used libmpv direct; the current Electron build leans on Chromium's built-in decoder pipeline. Either way: no external player, no second window, no flash of black.
  • Admin panel at Ctrl+Shift+A with three modes: Assign (scan a tag, pick a video, map it), Manage (review and delete existing mappings), Settings (idle logo, playback options, license, DMX cues). Tab cycles between modes; ESC drops back to idle.
  • DMX lighting integration (optional) — fire a configured cue when each tag triggers, so the room itself responds to what the visitor picked up. OSC-out the side for any other show-control gear.
  • Mock mode for development — start with --mock and the app fakes scans on a hotkey. No reader required to iterate on layout or video pacing.
  • Update + license checks at startup with an offline grace window, so a kiosk on a spotty network doesn't fall over the first time the wifi drops.

Two implementations, same product

TagTable shipped first as a Rust + egui desktop binary cross-compiled from Linux to Windows via MinGW + FFmpeg shared libs. That version still lives in the repo under rust-legacy/ and the README documents it. The current production build is a JavaScript + Electron rewrite (v2.x) that traded the leaner footprint of the Rust version for faster iteration on the admin UI and better Mac support — same RFID flow, same video path, same admin gestures. The README's "Built with Rust" framing is accurate for the legacy code; the live installer is Electron.

Why the table

Most "interactive" exhibits are screens with buttons. TagTable's pitch is: the screen is incidental — the artifact you're holding is the input. Tagging objects with cheap 125kHz cards and letting curators map clips through a hotkey panel makes the "swap the experience next month" loop quick enough that the exhibit team can iterate without involving a developer.

Straight from the source

The project's own README.

Rendered in place — every link, image, and code block carried over from the repo. The page below is what a contributor would see opening the project for the first time.

TagTable - RFID Video Kiosk

A Windows-based video kiosk application that plays videos when RFID-tagged objects are placed on a reader. Built with Rust and egui for seamless, instant video playback.

Features

  • RFID Tag Detection: Interfaces with USB HID RFID readers (EM4100/TK4100 125kHz tags)
  • Instant Video Playback: Hardware-accelerated 4K video via libmpv - no external player needed
  • Admin Mode: Press Ctrl+Shift+A to access the admin interface
    • Assign Mode: Map RFID tags to videos
    • Manage Mode: View and delete existing mappings
    • Settings Mode: Configure videos, logo, playback, and system settings
  • Customizable Logo: Display your own logo when idle
  • Update Notifications: Checks for updates on startup
  • Product Key Licensing: Online license validation with offline grace period
  • Mock Mode: Test the application without RFID hardware

Quick Start

Installation (Windows)

  1. Download the latest release from tagtable.download
  2. Run TagTable-X.X.X-Setup.exe
  3. Launch TagTable from the Start Menu

See docs/INSTALL.md for detailed installation instructions.

Basic Usage

  1. Launch TagTable - Starts in fullscreen mode
  2. Add Videos - Place video files in the videos/ folder
  3. Enter Admin Mode - Press Ctrl+Shift+A
  4. Assign Tags - Select a video, then scan a tag
  5. Press Tab - Switch between Assign/Manage/Settings modes
  6. Exit - Press ESC to return to normal mode

See docs/USAGE.md for the complete user guide.


Technical Overview

Architecture

TagTable uses a state machine architecture with three primary states:

                    ┌─────────────────────────────────────┐
                    │                                     │
                    ▼                                     │
┌──────────┐   RFID Scan    ┌───────────┐   Video Ends   │
│   IDLE   │ ─────────────► │  PLAYING  │ ───────────────┘
│  (Logo)  │   (mapped tag) │  (Video)  │
└──────────┘                └───────────┘
     │
     │ Ctrl+Shift+A
     ▼
┌──────────────────────────────────────────┐
│            ASSIGNMENT (Admin)            │
│  ┌────────┐  ┌────────┐  ┌──────────┐   │
│  │ Assign │  │ Manage │  │ Settings │   │
│  └────────┘  └────────┘  └──────────┘   │
│         (Tab key cycles modes)           │
└──────────────────────────────────────────┘

Tech Stack

Component Technology Purpose
Language Rust 2021 Edition Systems programming with memory safety
GUI Framework egui 0.29 + eframe Immediate-mode GUI, cross-platform
Video Playback libmpv2 Hardware-accelerated 4K playback
Serialization serde + serde_json Configuration and mapping persistence
HTTP Client ureq Update checking
CLI Parsing clap 4.0 Command-line arguments
File Dialogs rfd Native folder/file selection
OpenGL glow GPU rendering for video frames

Module Structure

src/
├── main.rs           # Entry point, CLI args, event loop, app initialization
├── state.rs          # State machine: AppState, AdminMode, AdminState
├── ui.rs             # UI rendering: idle screen, admin panels, settings
├── config.rs         # Configuration: Config, Mapping, PlaybackConfig
├── player.rs         # Video playback: libmpv hardware-accelerated player
├── version.rs        # Version info and update checking
├── license.rs        # Product key licensing with online validation
├── assets.rs         # Embedded assets (default logo)
├── paths.rs          # Path resolution and data directories
└── input/
    ├── mod.rs        # Input handler interface
    ├── rfid.rs       # RFID tag detection (10-digit buffer)
    └── admin_trigger.rs  # Ctrl+Shift+A detection

Key Concepts

Immediate Mode GUI (egui)

  • UI is rebuilt every frame based on current state
  • No retained widget state - simple, predictable rendering
  • Ideal for kiosk applications with simple UI needs

RFID as HID Keyboard

  • RFID readers emulate USB keyboards
  • Output: 10 decimal digits + Enter key
  • Application captures keystrokes and buffers them
  • Timeout-based detection (50ms default)

Hardware-Accelerated Video Playback

  • libmpv with OpenGL render API
  • Hardware decoding: D3D11VA (Windows), VAAPI (Linux), V4L2 (Pi)
  • Smooth 4K playback on modest hardware
  • Supports MP4, MOV, AVI, MKV, WebM

JSON Configuration

  • config.json: Application settings (video directory, logo, playback)
  • mapping.json: Tag-to-video associations
  • Both auto-created with defaults if missing

Configuration

config.json

{
  "video_directory": "./videos",
  "input_timeout_ms": 50,
  "playback_cooldown_ms": 2000,
  "admin_code_enabled": true,
  "fullscreen": true,
  "mock_mode": false,
  "logo": {
    "path": "./logo.png",
    "display_mode": "centered",
    "opacity": 1.0
  },
  "playback": {
    "volume": 1.0,
    "loop_video": false,
    "scale_mode": "fit",
    "end_behavior": "return_to_idle",
    "fade_duration_ms": 2000
  }
}
Field Type Description
video_directory path Directory containing video files
input_timeout_ms number RFID digit buffer timeout (ms)
playback_cooldown_ms number Debounce period between same tag scans
admin_code_enabled bool Enable Ctrl+Shift+A admin access
fullscreen bool Start in fullscreen mode
mock_mode bool Enable mock mode (single-digit tags)
logo.path path Custom logo image path
logo.display_mode string centered, fit, stretched, or tiled
logo.opacity float Logo transparency (0.0 - 1.0)
playback.volume float Audio volume (0.0 - 1.0)
playback.loop_video bool Loop videos when they end
playback.scale_mode string fit, fill, stretch, or native
playback.end_behavior string return_to_idle, fade_to_idle, or hold_last_frame

mapping.json

{
  "0008265812": "intro_video.mp4",
  "0009912345": "product_demo.mp4"
}

Simple key-value mapping of 10-digit RFID tag IDs to video filenames.


Requirements

Target System (Windows)

  • Windows 10/11 (64-bit)
  • USB RFID Reader (125kHz, HID keyboard emulation)
  • Video files in supported formats (MP4, MOV, AVI, MKV, WebM)

Development (WSL2/Linux)

  • Rust 1.70+
  • mingw-w64 (for cross-compilation to Windows)
  • just (command runner)

Development

Setup

# Install cross-compilation tools
just setup

# Or manually:
rustup target add x86_64-pc-windows-gnu
sudo apt-get install -y mingw-w64

Building

# Build Windows release binary
just build-win

# Build and bundle into dist/
just bundle

# Run in mock mode (test without hardware)
just run-mock

# Run locally in windowed mode
just run

# Build Windows installer (requires Inno Setup)
just installer

Build System

The project uses just as a command runner. Key recipes:

Command Description
just setup Install cross-compilation toolchain
just build-win Build Windows release binary
just bundle Create dist/ folder with exe + config + videos
just run-mock Run locally in mock mode (windowed)
just run Run locally in windowed mode
just test Run Rust tests
just lint Run clippy with strict warnings
just fmt Format code with rustfmt
just ci Full CI pipeline (fmt + lint + test + build)
just installer Create Windows .exe installer

Cross-Compilation

TagTable is developed on Linux/WSL2 and cross-compiled for Windows:

  • Host: Linux x86_64
  • Target: x86_64-pc-windows-gnu
  • Toolchain: MinGW-w64 (GNU toolchain for Windows)

The .cargo/config.toml configures the Windows linker automatically.


Project Structure

tagtable/
├── Cargo.toml           # Dependencies and project config
├── Cargo.lock           # Locked dependency versions
├── config.json          # Runtime configuration
├── mapping.json         # Tag-to-video mappings
├── justfile             # Build commands
├── videos/              # Video files directory
├── assets/              # Logo and fonts
│   ├── tag-table-logo.png   # Default embedded logo
│   └── JetBrainsMono-Regular.ttf  # UI font
├── installer/           # Inno Setup scripts
│   └── tagtable.iss
├── docs/                # Documentation
│   ├── CHANGELOG.md
│   ├── INSTALL.md
│   ├── USAGE.md
│   ├── UPDATE_ENDPOINT.md
│   └── server/          # Server-side deployment docs
│       ├── README.md
│       ├── UPDATE_ENDPOINT.md
│       ├── DIRECTORY_STRUCTURE.md
│       └── DEPLOYMENT.md
└── src/                 # Rust source code
    ├── main.rs
    ├── state.rs
    ├── ui.rs
    ├── config.rs
    ├── player.rs
    ├── version.rs
    ├── license.rs
    ├── assets.rs
    ├── paths.rs
    ├── dmx/              # DMX lighting control (Art-Net, sACN, Serial)
    └── input/
        ├── mod.rs
        ├── rfid.rs
        └── admin_trigger.rs

Keyboard Shortcuts

Key Context Action
Ctrl+Shift+A Idle Enter Admin Mode
Ctrl+Q Any Force quit
ESC Idle Quit application
ESC Admin Exit Admin Mode
Tab Admin Cycle mode: Assign → Manage → Settings
Arrow Up/Down Admin Navigate lists/tabs
Enter Settings Select tab
Delete Manage Remove selected mapping

Hardware

Supported RFID Readers

  • YARONGTECH 125kHz USB RFID Reader
  • FissaiD or similar HID keyboard-emulating readers
  • Any reader that outputs 10 digits + Enter

Note: Choose readers without audible beeps for seamless user experience.

Supported Tags

  • EM4100/TK4100 125kHz Read-Only Passive Tags
  • Tags output a 10-digit decimal UID

Documentation


Deployment

Releasing a New Version

  1. Update version in Cargo.toml
  2. Build and bundle:
    just ci && just bundle
    
  3. Build installer:
    just installer
    
  4. Deploy to server:
    just deploy
    
  5. The version endpoint is updated automatically

See docs/server/DEPLOYMENT.md for full workflow.


License

MIT

Build something like this

Want a tool like this for your shop?

We've shipped this kind of thing before. Twenty-minute intro call, no slides.