Skip to content

Latest commit

 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GM SurroundVision

Review and export 4-camera surround dash-recorder footage on your own machine — six synchronised views, a real 360° ground-plane stitch, and an ffmpeg exporter, with zero npm dependencies.

GM SurroundVision playing one trip: four dash-recorder cameras frame-locked while the layout cycles through the Cross, Solo, Command and Drive views and finishes on the Surround 360 ground-plane stitch orbiting a top-down truck.

An 8×-sped tour of Cross → Solo → Command → Drive → Surround 360°. Full 28 s demo (MP4) →

A local web app: one Node file, a vanilla-JS frontend, no build step, no accounts, no telemetry. The server binds 127.0.0.1 only and never writes to your footage folder. Nothing leaves the machine.

Built by ABSG for the WTPN news van, because reviewing four parallel camera streams in an ordinary player is miserable — you scrub four files by hand and guess whether they line up. This treats the whole trip as one timeline: four cameras frame-locked, a real wall clock, mark in/out, hit export. Version 1.0.

Quick start

You need Node.js 22+ and FFmpeg 6+ (both ffmpeg and ffprobe) on your PATH — details in Requirements.

git clone https://github.com/absginc/GMSurroundVision.git
cd GMSurroundVision

mkdir -p Recordings/SurroundVisionRecorder
cp /Volumes/SURROUNDVISION/*.mp4 Recordings/SurroundVisionRecorder/

node server.js

Open the URL it prints, pick a trip, and you are in the player.

SurroundVision ready → http://localhost:4171

No install, no build, no watcher, no import step — the app just reads that folder. Stop it with Ctrl+C. Files must be named {CAM}_{YYYY}_{MM}_{DD}_T_{HH}_{MM}_{SS}.mp4; see Getting footage in. To persist settings, copy .env.example to .env and use Node's native env-file support:

cp .env.example .env      # then edit .env
node --env-file=.env server.js

Download for macOS

The desktop app is the same player and exporter in a double-clickable shell — nothing to install first, no Node, no FFmpeg, no terminal. Two builds:

Your Mac Download
Apple Silicon (M-series) GM-SurroundVision-<version>-arm64.dmg
Intel GM-SurroundVision-<version>-x64.dmg
  1. Download the DMG for your Mac from the releases page, open it, and drag GM SurroundVision to Applications.
  2. First launch: the app is not notarized yet (no Apple Developer account), so macOS will balk. Either right-click the app → Open → Open (needed once), or run:
xattr -cr "/Applications/GM SurroundVision.app"
  1. On first run the app offers to use ~/Movies/GM SurroundVision/Recordings or lets you choose any folder — a USB drive under /Volumes/…, the folder you copied clips into, wherever the recorder files live. You can change it any time: the empty trips screen has a Choose Recordings Folder… button, and it's in the File menu too. Exports land in ~/Movies/GM SurroundVision/Exports (File → Open Exports Folder).

The app bundles its own FFmpeg (ffmpeg 6.0 via ffmpeg-static, ffprobe 8.1.2 from Martin Riedl's builds — GPL builds invoked as separate executables), both native arm64, so it runs without Rosetta. To build the DMGs yourself: cd desktop && npm install && npm run dist (Apple Silicon) or npm run dist:x64 (Intel) — the first build fetches sha256-verified FFmpeg binaries per architecture.

ContentsDownload for macOS · Features · Requirements · Where the footage comes from · Getting footage in · Configuration · Using the player · Exporting · Skins · How it works · Roadmap · Troubleshooting · Project layout


Features

Six views Quad · Command · Drive · Solo · Cross · Surround 360°
Surround 360° True ground-plane projection (per-camera homography), 3D orbit with presets, three style presets, live calibration drawer
Frame-locked playback All four cameras driven off one virtual trip clock, held in sync across 5-minute segment boundaries
Wall-clock timeline Real recorded time-of-day, segment ticks, hover thumbnails, in/out marking
Exporter single · all · quad · command · drive · cross · surround · pip, speeds ¼×–4×, optional per-camera clips in the same job
Six skins Broadcast · Night Ops · Dash · Daylight · DVR · Cinema
Zero dependencies Node built-ins only. node server.js and you are running.

Requirements

Node.js 22+ node --version. Nothing to npm install — v22 is the tested baseline, and configuration leans on Node's native --env-file support rather than a dotenv package.
FFmpeg 6+ Both ffmpeg and ffprobe. ffprobe measures clip durations (cached after the first scan); ffmpeg renders thumbnails and every export. Verify with ffmpeg -version && ffprobe -version.
A browser Chromium-based recommended (Chrome, Edge, Brave, Arc): the Surround view leans hard on CSS 3D transforms with matrix3d on live <video> elements. Everything else works fine in any modern browser.

Installing FFmpeg (it provides both binaries):

Platform Command
macOS brew install ffmpeg
Debian / Ubuntu sudo apt install ffmpeg
Windows winget install Gyan.FFmpeg

Disk space. Recorder clips run roughly 110 MB per 5-minute segment per camera, and exports add to that on top:

Trip length Approx. size (4 cameras)
5 min ~440 MB
20 min ~1.8 GB
40 min ~3.5 GB

Where the footage comes from

The cameras were always on the truck. What changed is the software.

GM software update 663.10 was installed on the build vehicle — a 2025 Chevrolet Tahoe Z71 — on 28 July 2026. Its release notes describe three camera features, each of them qualified with "if your vehicle is equipped":

  • Surround Vision Recorder — the vehicle records video from its own cameras, and you can watch those clips back and save them. This is the feature that produces the files this app reads.
  • Security Recording — while the vehicle is parked, a triggered alarm starts a recording on its own.
  • Cabin Glance — a live look at the seating area on the infotainment screen, for checking on passengers, kids or pets. Live only: it records nothing, so this app has nothing to do with it.

The same update also carried work unrelated to the recorder — responsiveness fixes for the driver display and the rear-view camera, reliability improvements for alerts and chimes, and memory seat buttons that can be linked to user profiles, up to two of them.

So Surround Vision Recorder supplies the footage. What it does not supply is a good way to look at it: review happens on the infotainment screen, in a parked vehicle, a camera at a time. This project is the other half of that — copy the files to a computer and watch all four cameras at once on a real timeline, then cut what you need out of it.

The connection is visible in this repository's own data. The earliest development clips are timestamped 2026-07-28 18:31:45 — a 26-second four-camera test, recorded the same evening the update landed. Everything here was written against that recorder over the days that followed.

What the recorder writes

Measured with ffprobe on the real files:

Property Value
Container / codec MP4, H.264 (avc1), yuv420p
Resolution 1280×768 per camera
Frame rate 30 fps, constant
Audio None at all — one stream per file, video only
Segment length Exactly 300.000 s; the final segment of a trip is shorter
Segment size ~106 MiB (~111 MB) per camera per segment
Files per segment Four — one per camera, sharing an identical timestamp
Segment continuity Gapless — next start == prev start + prev duration

That table explains a good deal about the app. There is no volume control and exports are silent because there is no audio anywhere in the source. Trips are grouped by a gap rule rather than by metadata because gapless segment arithmetic is the only continuity signal the files carry — nothing in them says "this is the same drive". And the 5-minute chunking is why playback is double-buffered: a trip is not a file, it is a chain of them, and the seam has to be invisible.

Compatibility

Tested. A 2025 Chevrolet Tahoe Z71 running software 663.10, four cameras, writing exactly the output described above. That is the one configuration anything here has actually been run against.

Expected, not verified. Other GM vehicles equipped with Surround Vision Recorder. If the recorder writes the same {CAM}_{YYYY}_{MM}_{DD}_T_{HH}_{MM}_{SS}.mp4 filenames, the app should treat that footage exactly as it treats the Tahoe's — but that follows from the file naming, not from testing, so treat it as an expectation.

Untested. Security Recording clips. This tool has never been pointed at any. If the recorder saves them under the same naming convention, they would land in the folder and show up as ordinary trips like anything else — that is what we would expect to happen, not something anyone here has confirmed.

Getting footage in

There is no import step and no database. The app reads a folder — that is the whole ingestion story.

  1. Copy the files off the recorder. Pull the SD card (or connect the recorder's USB storage) and copy the .mp4 files across. Copy them; do not work off the card.
  2. Drop them in Recordings/SurroundVisionRecorder/ — or leave them where they live and point RECORDINGS_DIR at that path (see Configuration).
  3. Check the filenames. They must match {CAM}_{YYYY}_{MM}_{DD}_T_{HH}_{MM}_{SS}.mp4, where CAM is FRONT, LEFT, REAR or RIGHT and the timestamp is the local wall-clock start time of that segment:
FRONT_2026_07_29_T_07_53_06.mp4
LEFT_2026_07_29_T_07_53_06.mp4
REAR_2026_07_29_T_07_53_06.mp4
RIGHT_2026_07_29_T_07_53_06.mp4

Anything that does not match is ignored — dotfiles, .DS_Store, stray exports, subfolders.

How files become trips

  • Segment — the four files sharing one timestamp. Recorders chunk continuously, typically 5 minutes (300 s) per file, with the last segment of a trip shorter. Start times and durations are identical across the four cameras.
  • Trip — consecutive segments are gapless (next start == prev start + prev duration). A gap over 45 seconds starts a new trip, so an ignition cycle, a lunch stop or a card swap naturally splits the day.
  • Missing cameras are fine. A camera with no file for a segment shows NO SIGNAL for that span, and composite exports substitute black. The trip card flags any trip with fewer than four cameras.
  • The recordings folder is read-only to this app. It scans and streams from it; it never writes, moves, renames or deletes anything there. Exports go to Exports/, caches to .cache/. That is deliberate rather than incidental: what you copied off the recorder is the only original that exists, and footage that turns out to matter later should still be byte-identical later. Nothing this app does can put that in question.
  • New footage needs no import. The folder is rescanned on every visit to the trips screen — copy new files in and hit Refresh. Durations are probed once and cached by name + size + mtime, so rescans are fast.

Different recorder? Any 4-camera recorder should work if the files are h264 MP4 and renamed to the pattern above with a shared per-segment timestamp — expected rather than tested, for the reasons in Compatibility. A batch rename is all it takes — but the timestamp must be the true segment start time, since it drives the wall clock and the trip grouping.

Configuration

Every setting is an environment variable, and all of them are optional.

Variable Default What it does
PORT 4171 Listen port. If busy, it auto-increments up to PORT+10 (4181 by default). Binds 127.0.0.1 only — never exposed to the network.
RECORDINGS_DIR ./Recordings/SurroundVisionRecorder Where your recorder files live. Read-only. Relative paths resolve from the project root.
EXPORTS_DIR ./Exports Where finished exports are written. Created if missing.
FFMPEG_PATH (auto) Explicit path to the ffmpeg binary. Otherwise resolved from PATH, then from common install directories.
FFPROBE_PATH (auto) Same, for ffprobe.
EXPORT_PREFIX SV Leading token on exported filenames — brand your own output.

Inline for a one-off:

RECORDINGS_DIR=/Volumes/DASHCAM/clips PORT=8080 node server.js

Or persisted in .env (see .env.example) and loaded with node --env-file=.env server.js:

PORT=4171
RECORDINGS_DIR=/Users/you/Footage/Tahoe
EXPORTS_DIR=/Users/you/Movies/SurroundVision
# FFMPEG_PATH=/opt/homebrew/bin/ffmpeg
# FFPROBE_PATH=/opt/homebrew/bin/ffprobe

The app will never gain an npm dependency. That is a design constraint, not an oversight.

Using the player

Pick a trip from the grid and you land on the player. One virtual clock drives all four cameras, and the header shows the real recorded time of day at the playhead. That clock — not any one video element — is the source of truth, because four independent decoders chewing through four separate chains of 5-minute files will wander apart on their own; every camera is continuously steered back to a single trip-relative position rather than merely started at the same moment (see How it works). Clicking any small tile promotes it; a camera with no footage for the current span shows NO SIGNAL rather than freezing.

Key View What it is for
Q Quad 2×2 grid — FRONT, RIGHT, LEFT, REAR. The default situational-awareness view.
W Command One camera large with the other three stacked beside it; click a small tile to swap it into the big slot. Following one thing while watching the rest.
E Drive FRONT fills the stage with mirrored REAR overhead and mirrored LEFT/RIGHT in the bottom corners — the driver's-seat reconstruction. Best for "what did the driver actually see".
R Solo One camera full-frame, the others as small thumbnails. Detail work.
T Cross FRONT over REAR down the centre, LEFT and RIGHT full-height on the flanks (fill-cropped, no black gaps). Wide-lane awareness.
Y Surround 360° All four cameras projected onto one ground plane around a top-down truck. Parking, clearances, and anything where the relationship between cameras matters more than any single one.

Keyboard

Key Action
Space Play / pause
Jump ∓10 s
Shift+ Jump ∓1 s
, . Frame step (1/30 s) — pauses first
Speed up / down (0.25× · 0.5× · 1× · 2× · 4× · 8×)
Q W E R T Y Quad · Command · Drive · Solo · Cross · Surround
1 2 3 4 Solo on FRONT / LEFT / REAR / RIGHT, from any view
I O Set the In / Out marker at the playhead
F Fullscreen the stage
[ ] Cycle skin
? Shortcut overlay
Esc Close panel or overlay · clear markers

Keys are ignored while you are typing in a field — except Esc, which always works and returns focus to the transport.

The timeline. Click or drag anywhere to scrub, hover for a wall-clock and trip-relative tooltip with a thumbnail preview, thin ticks mark segment boundaries, and the In/Out span tints in the skin's accent with draggable handles.

Surround 360 in detail

Each camera is horizon-cropped — only the bottom of the frame, the road, is used, so sky and buildings never land on the ground plane. That cropped rectangle is mapped by an exact homography onto a trapezoid on a shared ground canvas: the near edge at the truck, the far edge fanning out wide. Four trapezoids, one per bearing (FRONT 0°, RIGHT 90°, REAR 180°, LEFT 270°), feathered at their far and side edges so the seams blend, composited around a top-down vehicle graphic. The planes wrap the live video elements — nothing is cloned or re-decoded, so the stitch plays at full speed and stays in sync with every other view.

  • Orbit — drag to swing yaw/pitch (pitch clamped 0–70°), wheel to zoom, double-click to reset. Presets: TOP-DOWN, 3D FRONT, 3D CHASE, 3D QUARTER.
  • StylesFactory (clean cool-gray ground, parking guide arcs), Tactical (grid, corner brackets, harder edges), Cinematic (heavy vignette, wide feather, chrome hidden). Each skin picks a sensible default; an explicit choice sticks.
  • Calibration drawer (gear button) — per-camera sliders for crop, push, depth, near width, far width, feather and lens undistortion, plus global perspective, car size, ground darkness and a guides toggle. Isolate dims the other three cameras while you tune one. Everything applies live and persists across trips and sessions.
  • Presets — save a tuned calibration into one of four slots (nameable, loadable, clearable), or snap back to the built-in Default bird's-eye, which can never be overwritten. Loading a preset changes the calibration only; it leaves your current orbit and style alone.

Honest limitation: these are wide-angle cameras with no published lens model, intrinsics or extrinsics. Barrel distortion is corrected by a single radial term fitted by eye against real footage — enough that lane lines and kerbs come out straight and the four sectors agree, but it is a fitted approximation, not a calibrated lens model. The stitch is built on a flat-ground homography — good enough to read curbs, lines and clearances at a glance, and it looks the part. It is not a metric reconstruction; do not measure distances off it. Two minutes in the calibration drawer lines the seams up for your vehicle. The defaults are tuned for the Tahoe Z71.

Exporting

  1. Mark the rangeI and O at the playhead, drag the handles, or type mm:ss values into the export panel. "Use full trip" grabs everything.
  2. Hit EXPORT and pick a mode:
Mode Output
Single camera One camera, full frame
Quad 2×2 1920×1152 — FRONT, RIGHT, LEFT, REAR
Command 1920×864 — chosen camera large, other three stacked beside
Drive 1920×1152 — main view with mirrored rear and side overlays baked in
Cross 1920×1152 — front over rear centred between full-height sides
Surround 360° 1440×1440 top-down, or 1920×1080 when pitched — rendered with your current orbit angle, style and calibration
Picture-in-Picture Main camera with an inset second camera, top-right
All cameras — separate clips One file per camera, no composite
  1. Pick a speed — ¼× · ½× · 1× · 2× · 4×. It applies to every output in the job, and the panel tells you the resulting duration (a 30 s range at ½× renders a 60 s slow-motion clip).
  2. Optionally tick "Also export each camera as its own clip" — available on any composite mode. The composite and the four raw camera clips render in one job, sequentially, under one progress bar, so a single job produces between 1 and 5 files.
  3. Start Export. Progress is polled live and aggregated across all sub-renders. Finished files appear in the panel's Exports list with preview, download and delete.

Output is h264 (libx264, CRF 19, veryfast, +faststart), 30 fps, no audio — the source has no audio stream. Files land in Exports/ (or EXPORTS_DIR) named:

{PREFIX}_{tripId}_{MODE}_{h-mm-ss}_{durS}s{_speedX}.mp4
Part Meaning
PREFIX EXPORT_PREFIX, default SV. Set it to brand your own output.
tripId YYYY-MM-DD_HH-MM-SS of the trip start
MODE The camera name for single/individual clips, otherwise QUAD, COMMAND-FRONT, DRIVE-FRONT, CROSS, PIP-FRONT-REAR, SURROUND (top-down) or SURROUND-3D (pitched)
h-mm-ss The in-point, relative to the start of the trip
durS Source-range length in seconds
_speedX Only present when speed ≠ 1× (e.g. _0.5x)
SV_2026-07-29_07-53-06_QUAD_0-04-12_45s.mp4
SV_2026-07-29_07-53-06_FRONT_0-04-12_45s_0.5x.mp4
SV_2026-07-29_07-53-06_SURROUND-3D_0-12-30_20s.mp4

Existing names are never overwritten — a _2, _3, … suffix is appended instead.

Skins

Palette button in the header, or [ / ] to cycle. The choice persists, and every view, panel and the trips screen are themed.

Skin Look
Broadcast (default) Control room — WTPN red on steel
Night Ops NVG green phosphor, faint scanlines, amber alerts
Dash Vehicle infotainment — navy and ice blue, softer radii, larger type
Daylight Light theme for bright-room review
DVR Retro security recorder — near-black, amber mono labels, cyan hairlines
Cinema Pure black; chrome dims further during playback

How it works

Backend — one file, server.js, Node built-ins only

  • Trip scanning. Parses filenames, groups identical timestamps into segments, clusters segments into trips at the 45 s gap threshold. Durations come from ffprobe, cached in .cache/probe.json by name + size + mtime, so the first scan costs a moment and every later one is free.
  • Video streaming. /video/{filename} serves the source MP4s with full HTTP Range support (206 + Content-Range, 416 on nonsense), which is what makes instant seeking anywhere in a 40-minute trip possible. Filenames are validated against the strict pattern, so path traversal is not expressible.
  • Thumbnails. Single-frame ffmpeg extractions at snapped widths, cached on disk and served with a long Cache-Control, with a cap on concurrent renders so a fast timeline hover cannot fork-bomb the machine.
  • Export jobs. Each job writes concat-demuxer lists for the segments intersecting the range, seeks on input, and runs its sub-renders sequentially through ffmpeg with -progress pipe:1 parsed for live progress. Output goes to a .part.mp4 and is renamed on success, so a half-finished file never appears in the exports list.
  • Loopback only, by construction. The listener binds 127.0.0.1, which is why there is no account system, no auth layer and no upload path to get wrong — dash footage is full of faces, plates and the inside of your own driveway, and the most reliable way to keep it on your machine is to never open a door off it. A LAN viewer is on the roadmap as an explicit, authenticated opt-in for exactly that reason.

Frontend — public/app.js, vanilla JS, no framework, no CDN, works offline

  • Double-buffered playback. Every camera owns two <video> elements: while one plays the current segment, the other quietly preloads the next. At a boundary all four cameras swap buffers in the same tick — which is why playback rolls straight through a 5-minute file boundary instead of stalling.
  • Master/slave drift correction. One camera drives the virtual trip clock; the other three follow. Every animation frame each slave compares its position against the target: more than 0.3 s out gets a hard currentTime set, 0.08–0.3 s out gets a gentle ±6% playbackRate nudge, inside 0.08 s it is left alone. The cameras stay within about a tenth of a second of each other during steady playback.
  • Surround projection. The destination quad for each camera is computed from the geometry model, then the exact 3×3 homography from the cropped source rectangle to that quad is solved and applied as a CSS matrix3d — no faked rotateX. The exporter computes the same quads and feeds them to ffmpeg's perspective filter, so player and export agree. The player uses true CSS 3D and the exporter approximates it: aim for visually close, not pixel-identical.

The vehicle graphic is public/assets/tahoe-top.png — an RGBA top-down render with the nose pointing up. The player draws it as an <img> (falling back to a hand-drawn SVG silhouette if it fails to load) and the exporter reads the same file from disk, so both show the same truck. To use a different vehicle, replace that PNG (nose up, transparent background, tightly trimmed to the vehicle's bounding box including mirrors) and set SV_CAR_RATIO in public/app.js to the new image's width ÷ height — otherwise the render is stretched.

Roadmap

Shipped — v1.0 is this local web app: six views, the 360° surround stitch with calibration, frame-locked playback, the full exporter, six skins.

Planned, roughly in order. Nothing below exists yet.

  • Hardware-accelerated export — VideoToolbox on macOS, NVENC on NVIDIA, falling back to libx264. Exports are currently CPU-bound.
  • Auto event detection — flag hard braking, sudden motion and scene changes on the timeline so you can jump to the interesting parts instead of scrubbing.
  • GPS / telemetry overlay — speed, heading and a map trace, if the recorder logs it.
  • Trip notes, bookmarks and search — name a moment, annotate a clip, find it later.
  • Desktop appshipped as a beta for macOS (Apple Silicon and Intel): an Electron shell bundling FFmpeg, with in-app folder selection — see Download for macOS. Still planned: proper signing + notarization (needs an Apple Developer account), Windows, auto-import when a card is inserted, and a background export queue.
  • LAN / mobile viewer — opt-in and authenticated, so a phone or tablet on the same network can review trips. Today the server is deliberately loopback-only.

Troubleshooting

"ffmpeg not found" / thumbnails blank / exports fail immediately. Run which ffmpeg ffprobe. If that prints nothing, install FFmpeg (see Requirements). If it lives somewhere unusual, point at it explicitly:

FFMPEG_PATH=/opt/homebrew/bin/ffmpeg FFPROBE_PATH=/opt/homebrew/bin/ffprobe node server.js

No trips showing up. Run ls Recordings/SurroundVisionRecorder | head and check, in order:

  1. Files are directly in the folder, not in a subfolder.
  2. Filenames match {CAM}_{YYYY}_{MM}_{DD}_T_{HH}_{MM}_{SS}.mp4 exactly — FRONT_2026_07_29_T_07_53_06.mp4. Anything else is silently skipped.
  3. RECORDINGS_DIR points where you think it does.
  4. Hit Refresh on the trips screen; the folder is rescanned on every load.

Expecting one trip and seeing several? The gaps between your segments exceed 45 s — that is the trip-splitting rule doing its job.

Port already in use. The server tries 4171 and walks up to 4181 on its own, so this is usually handled. To force a port, PORT=8080 node server.js. To find whatever is holding the default:

lsof -nP -iTCP:4171 -sTCP:LISTEN

Surround view looks wrong / seams misaligned. Open the calibration drawer (gear icon in the Surround view). Raise CROP until the horizon and everything above it is gone, then adjust PUSH and DEPTH until the ground meets the truck cleanly, then NEAR W / FAR W until the seams between cameras agree. Use Isolate to work on one camera at a time. Settings save automatically; Reset restores the Tahoe defaults.

Playback stutters or cameras drift apart. Four simultaneous 1280×768 h264 streams is real work. Use a Chromium-based browser, close other heavy tabs, and prefer Solo or Drive over Quad on modest hardware. Playing from an external drive over USB can starve the decoder — copy the trip locally first.

Project layout

GMSurroundVision/
├── server.js                        # entire backend — scanning, streaming, thumbnails, export jobs
├── public/
│   ├── index.html                   # single-page shell (both screens)
│   ├── app.js                       # player, sync engine, surround projection, export panel
│   ├── style.css                    # design system + all six skins
│   └── assets/
│       └── tahoe-top.png            # top-down vehicle graphic (nose up, RGBA)
├── docs/                            # demo.gif and demo.mp4
├── Recordings/
│   └── SurroundVisionRecorder/      # your footage — READ ONLY, never written to
├── Exports/                         # finished exports land here
├── .cache/                          # probe cache, thumbnails, temp job files (safe to delete)
├── desktop/                         # macOS app (Electron shell); npm run dist builds the DMG
├── .env.example                     # copy to .env, load with --env-file
├── SPEC.md                          # full feature + API contract
└── README.md

.cache/ and Exports/ are created on first run. Deleting .cache/ costs nothing but a re-probe on the next scan.

MIT licensed — see LICENSE.


Built by ABSG for the WTPN news van — a 2025 Chevrolet Tahoe Z71 with a 4-camera GM SurroundVision recorder. Not affiliated with, endorsed by, or a product of General Motors; "Chevrolet", "Tahoe" and "SurroundVision" are used descriptively to identify the hardware this tool reads.

About

WTPN.news integration of GM Surround Vision

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages