Appearance
Video Recorder
Prov1.2.1Record your camera and/or screen with mic, entirely on-device
Video Recorder is a Pro app
It needs a free KimtOS account and a Pro subscription. Everything still runs on your device — Pro unlocks the app, it does not send your data anywhere. Install it without Pro and the app opens to an upgrade wall. See what Pro includes
Overview
Video Recorder captures your camera, your screen, and your microphone — alone or together — as a single video, all in the browser. It works like a tiny studio: the preview is always live, an action bar sits under it with the sources on one side and Record on the other, and you can flip any source on or off at any time, even while you are recording. It is part of the kimtos new-tab app suite.
Everything is fully on-device. There is no backend, no account, and no upload: capture, compositing, encoding, and storage all happen in your browser, and every recording lives in IndexedDB.
Highlights
- Three sources — camera, screen (via screen/tab sharing), and microphone. Use any combination.
- Live studio preview — the compositing canvas is the preview, so what you see is exactly what gets recorded.
- Toggle anything mid-recording — turn the camera, screen, or mic on or off without stopping or breaking the clip.
- Camera bubble — when you record screen + camera, the camera is overlaid as a small bubble, with its own strip in the action bar. Move it between corners, switch it between a rounded square and a circle, size it small, medium or large, or hide it altogether while the camera keeps running — all of it live, mid-recording included.
- Mirror — attached to the Camera button; the camera is shown as a natural mirrored self-view by default, so turn mirror off when on-camera text and whiteboards need to read the right way round.
- System audio — attached to the Screen button; optionally mixes in the shared screen's or tab's sound.
- A status pill that says what is happening — ready, recording or paused, the elapsed time, and exactly which sources are being captured.
- Quality presets — 720p (smoother) or 1080p (sharper), at 30 fps.
- Reduce noise — an optional, on-device pass that cleans background noise from the audio after recording. Chosen before you record.
- Countdown — an optional 3-2-1 (or 5-second) overlay before recording starts.
- Pause and resume — paused time is excluded from both the timer and the saved clip, which stays gapless.
- History sidebar — every recording is saved locally and played back with a custom video player. Download as
.webm, or multi-select and batch-delete.
Privacy model
Video Recorder never sends anything anywhere. Every stage runs on your machine:
- Capture uses the browser's camera, screen, and microphone APIs directly.
- Compositing and encoding happen in the page — frames are drawn to a canvas and encoded with the browser's own codecs (WebCodecs, or MediaRecorder as a fallback). The WebM muxer is pure JavaScript that runs locally.
- Reduce noise runs an on-device model in the browser (it downloads once, about 16 MB, then works offline).
- Storage writes each recording as a binary blob in IndexedDB.
Nothing is uploaded, and there are no analytics or third-party calls.
Getting Started
Open Video Recorder from the dock. It opens straight into the studio — a live preview with an action bar docked underneath it. Until a camera or screen is on, the preview shows a placeholder telling you what to turn on.
Once a camera or screen is live, a status pill in the top-left corner of the preview says what is going on: READY, REC or PAUSED, the elapsed time once you start, and which sources are being captured (for example REC · 1:23 · Camera + Mic).
Choosing your sources
The left of the action bar holds your three sources — Camera, Mic and Screen — as the buttons you reach for most. Your choices are remembered for next time.
- Camera — turns on your webcam. The first time, the browser asks for camera permission. The camera fills the frame when it is the only video source.
- Screen — starts screen or tab sharing. The browser asks which screen, window, or tab to share. When both screen and camera are on, the camera shrinks into a bubble over the screen.
- Mic — adds your microphone. Toggling the mic is an instant mute/unmute, so it never interrupts an in-progress recording.
If you stop a share from the browser's own sharing bar, the screen simply drops and the recording keeps going with whatever else is on.
Toggling sources mid-recording
You can flip any source on or off while recording — add your screen partway through, drop the camera, mute the mic — and the clip never breaks. Nothing in the action bar is hidden behind a menu, so every control stays one click away for the whole take. (The one exception is Reduce noise, which is locked once recording starts, and says so.)
Mirror and system audio
Each source button carries the small controls that only make sense with it, joined onto the same pill. They apply live, with no interruption:
- Mirror sits on the Camera button. On by default, showing your camera as a natural self-view; turn it off so text or a whiteboard in front of the camera reads correctly. It is dimmed while the camera is off, and hovering it says why.
- System audio sits on the Screen button. It includes the sound of the screen or tab you are sharing, connecting or disconnecting that audio instantly without touching the share itself. It is dimmed while the screen is off.
Shaping the camera bubble
The action bar has a Camera bubble strip of its own, controlling the bubble your camera is drawn in when you share a screen. Its four controls are live like everything else in the studio — including while you are recording — and your choice is remembered for next time:
- Show — the first button shows or hides the bubble. Hiding it leaves the camera running and available; it just stops being drawn over the screen. That is different from turning Camera off, which drops the camera entirely.
- Corner — steps the bubble round the four corners. The button is labelled with the corner it is currently in.
- Shape — a rounded Square that keeps your camera's own proportions, or a Circle. A circular bubble is a true circle: the picture is cropped to the centre rather than squashed.
- Size — Small, Medium or Large (16%, 24% or 32% of the frame width). Medium is the default.
The three look controls are inactive while the bubble is hidden, and the whole strip dims and reads Needs Camera and Screen together unless both are on — so it says why rather than leaving you to find out by clicking.
Quality, noise, countdown, and bubble position
These live in Settings → Apps → Video Recorder:
| Setting | What it does |
|---|---|
| Recording quality | 720p (smoother, lighter) or 1080p (sharper, better for screen text). Frame rate is 30 fps. |
| Reduce noise | Cleans background noise from the audio after recording, using the on-device denoise model (~16 MB on first use). It re-encodes the clip, taking roughly as long as the recording. Choose it before recording. |
| Camera bubble position | Which corner the camera bubble sits in for screen + camera recordings. Changing it applies to the studio you already have open, mid-recording included — the same as tapping Corner in the bar. |
| Countdown before recording | Off, 3 seconds, or 5 seconds — a 3-2-1 overlay after you press Record. |
Reduce noise also has its own Before recording strip along the bottom of the action bar, so you can flip it without opening Settings. Because it can only be applied to a whole clip, it greys out the moment you press Record and the strip changes to read Locked while recording — you never have to click a dead control to find that out.
Recording
- Turn on at least one video source (camera or screen).
- Press Record — it sits on its own, to the right of the sources, so it is never mistaken for a toggle. If a countdown is set, a 3-2-1 overlay plays first; pressing Record again during the countdown cancels it.
- While recording, the status pill turns red and reads
RECwith a live timer, and a Pause button appears next to Record. Pausing turns the pill amber, readsPAUSED, and excludes that time from the timer and the saved clip. - Press Stop to finish. If Reduce noise is on, a short "Cleaning audio…" progress step runs, then the recording is saved.
While it runs, the recording also appears as a row in KimtManager, so you can see it and stop it from anywhere in the app — and stopping it there finishes and saves the clip, exactly like pressing Stop. Anything that tears the studio down mid-recording — closing the window, opening another recording — saves what has been captured rather than discarding it.
History sidebar and the player
The left sidebar lists your recordings, newest first (up to 20 are kept). Click one to open it in the custom video player — your own controls, not the browser's native ones. From the result screen you can:
- Download the clip as a
.webmfile. - Record another to jump back to the studio.
Each row also has a menu with Open and Download.
Multi-select delete
To remove several recordings at once, click Select in the sidebar (or drag across the rows), tick the ones you want, and choose Delete (N). A toast lets you undo for a few seconds. Deleting a recording also removes its stored video data.
Architecture
Video Recorder is built around one idea: record a stable pair of tracks while the real inputs change underneath them. That is what lets you toggle camera, screen, and mic at any time — even mid-recording — without the clip ever breaking. The code lives in extension/src/apps/vidrec/.
The persistent mixer trick
A MediaRecorder (or a WebCodecs encoder) does not like tracks appearing and disappearing — stop a camera mid-recording and the recording falls apart. So the app never records the camera or screen directly. Instead, when the studio opens it creates a persistent mixer that exposes exactly two outputs for the whole session:
- One canvas video track. A fixed-size
<canvas>(sized to the quality preset) is redrawn ~30 times a second. Each frame it paints the screen (contained), then the camera — as a corner bubble over the screen, or full-frame on its own, and mirrored unless you turned mirror off. The bubble is clipped to a rounded-rect path, which is what makes the circular shape free: a circle is a square box rounded by half its width. Either way the camera is cover-cropped into the box, never stretched to it. This canvas is the live preview shown in the page, so the preview and the recording are always identical. - One mixed-audio track. A Web Audio
MediaStreamDestinationis the single audio output. The mic, and optionally the shared screen's audio, are connected to it as source nodes.
The camera, screen, and mic streams are the swappable inputs. Toggling a source acquires or releases that real stream and points the mixer at it (setScreen, setCamera, setMic, setScreenAudio, setMirror, setBubble) — but the mixer's two output tracks never change. setMirror and setBubble only set state the draw loop reads on its next tick, and setScreenAudio only connects or disconnects an audio node on the graph that already feeds the output track — which is why mirroring, system audio and the whole camera bubble can be changed mid-recording without re-acquiring anything or touching a track. The recorder is wired to those two outputs once, so it keeps running smoothly while inputs come and go. The source <video> elements are kept attached off-screen so the browser does not suspend their decoding, and the mic is muted by flipping its track's enabled flag rather than re-acquiring it.
When you stop, if Reduce noise is on, the clip is run through an on-device denoise model and then re-muxed: the video is played back while the cleaned audio is fed alongside it and the pair is re-recorded (browsers cannot swap an audio track in place). The result is saved to history.
Modules
| File | Role |
|---|---|
index.ts | The app descriptor and UI — the studio preview, the action bar (source pills with their attached modifiers, the camera-bubble strip, the pre-flight strip, record/pause), the status pill, countdown, driving the persistent mixer, the post-recording denoise + re-mux, and saving to history. |
mixer.ts | The persistent mixer — createMixer (the fixed video + audio output pair the whole session records from), the live setBubble setter and the pure bubbleRect/coverCrop geometry behind it, FPS, pickVideoType, and remuxWithAudio for the post-record re-mux. Imported by index.ts. |
lib/videoEncoderRecorder.ts | Hardware-accelerated recording with WebCodecs (VideoEncoder/AudioEncoder) muxed to WebM with webm-muxer. Pulls frames from the mixer canvas and audio from the mixed track; supports gapless pause/resume. Falls back to MediaRecorder where WebCodecs is unavailable. |
components/historySidebar.ts | The recordings sidebar — list, open, per-row menu, and multi-select batch delete. |
components/videoPlayer.ts | The custom video player used on the result screen (not native controls). |
lib/engines/denoise.ts | The optional on-device audio denoise model, lazy-loaded only when Reduce noise runs. |
lib/dataStore.ts | Local storage — recordings (metadata in a collection, the WebM as a blob) live in IndexedDB, keyed under history:vidrec. |
The encoder and muxer are imported lazily, only when you actually start recording, so they stay out of the new-tab bundle.
Capture flow
Camera, screen, and mic feed into the mixer's two fixed tracks; the recorder encodes those tracks to a WebM blob, which is saved to the local history. Toggling a source swaps an input on the left without disturbing the path on the right.
Encoding details
The WebCodecs path (createRecorder) keeps encoding off the main thread for smooth real-time capture:
- It picks a codec the browser can actually encode at the chosen size — VP9 (with a level chosen to fit the resolution and frame rate) or VP8 — and Opus for audio.
addFrame()is called once per composited canvas draw; frames are dropped if the encoder falls behind, so a backlog never compounds.- Pause removes paused wall-clock time from both video and audio timestamps, so the saved clip stays gapless and in sync.
Where WebCodecs is unavailable, the app falls back to MediaRecorder over a captureStream of the same canvas plus the mixed audio. Both paths expose the same stop() -> Promise<Blob>, pause(), and resume(), so the rest of the app does not care which one is running. The default codec preference is VP8 (its software encoder is far lighter than VP9 for real-time screen + camera capture).
Persistence
Each recording is one IndexedDB record plus one blob:
{ id, name, at, videoKey, dur, mime } // video bytes stored at videoKeyThe history keeps the most recent 20 recordings; older ones are pruned (record and blob together). Deleting a recording removes both its metadata and its video blob, and uninstalling the app offers to clear all history:vidrec data at once.
Changelog
1.2.1 — 2026-08-17
- A source that cannot start no longer switches itself off for good without a word. The camera, screen and microphone each say why they are unavailable, and your choice is kept.
- A device that will not start is explained rather than left to guesswork: whether to allow it in Chrome or in your computer's own settings, with the settings link there to copy.
1.2.0 — 2026-07-31
- The studio has a real action bar: your sources on the left, Record on its own to the right.
- Mirror and System audio now sit on the source they belong to, instead of looking like sources themselves.
- The camera bubble has its own strip: show or hide it, move it between corners, switch it between a square and a circle, and resize it — all of it live, mid-recording included.
- Reduce noise has its own "Before recording" strip, and says it is locked once you start rather than going quietly dead.
- A status pill on the preview shows whether you are ready, recording or paused, for how long, and what is being captured.
- A recording now appears in KimtManager while it runs, and anything that tears the app down mid-recording saves the clip instead of destroying it.
1.1.0 — 2026-07-27
- Give the extension a session model, and run the apps in one tab