A Chrome extension that turns any number of browser tabs into mixer channels. Every tab gets a level, pan, mute and solo — and, since 0.0.9, continuous playback speed, pitch control, seeking and transport on any site, not just YouTube. Everything sums into a tape machine you can loop, reverse, scrub and stutter in real time, driven by mouse, MIDI controller or keyboard. A video mode turns the whole thing into a performance layout that fits a single stream frame. Record the finished mix to a lossless file of any length, and write a mix down so you can find it again. Every source draws its own waveform on the tape's timeline, so you can read down the column and see what each one was contributing at the moment you are hearing — and where a tab will say what it has buffered, the shape to the right of the play head is sound it has downloaded and not played yet.
chrome://extensions and turn on Developer mode (top right).
halo-halo tab folder.
Chrome will warn that developer-mode extensions can be a risk, and may re-warn on each restart. That is expected for anything not installed from the Web Store.
Play something in a tab, then click the halo-halo tab button in your toolbar while that tab is in front. That tab becomes a channel and the mixer opens.
This is the only way to add a tab. Chrome will only let an extension capture audio from a tab you have explicitly invoked it on, so there is no button inside the mixer that can do it for you. One click per tab, once per browser session.
If you skip this step the mixer stays empty. It will tell you so rather than showing you controls that cannot work — every channel listed in the mixer is a live capture, so if you can see it, its controls work.
A captured tab's own sound is muted and routed through the mixer instead, so you hear the mix rather than both. Any audible tab works — YouTube, SoundCloud, Bandcamp, Netflix, Crunchyroll, a livestream. Clicking the button again on another tab adds it alongside; the mixer is never opened twice.
Browsing that tab somewhere else costs you its controls. Chrome grants access per page, not per tab, so navigating to a different site takes the extension's reach with it — the audio keeps flowing and level, pan, mute and solo carry on, but speed, scrub and transport go grey and say so. Click the toolbar button again to get them back. Picking the next episode on Netflix does this; so does letting it auto-play one.
Rate, position, pitch and transport come from a small script the extension puts inside the page when you click the toolbar button. Level, pan, mute and solo never touch the page at all — they run on the captured audio, so they work on anything, always.
The narrow strip down the left of the tape box: the output level, left and right, with the fader that sets it between them.
Everything sums here before it reaches the tape, so this is the level the tape plays and the level a recording captures. Drag the fader to move the whole mix without touching the balance you built between the channels; double-click it to return to unity.
The channel meters are coloured the same way, which is how you find the culprit: the master tells you the mix is too hot, the channels tell you which one is doing it. Pulling the master down fixes the sum, but if one channel is far enough over on its own, only its own fader will rescue it.
The bar's height and its colour measure different things, and that is deliberate. The height is an average — what you balance by. The colour is the highest single sample — what runs out of headroom. A signal can look comfortably short of the top and still be clipping, which is exactly what the meters used to hide.
The master travels in a snapshot along with everything else, and comes back the moment the file is loaded — it needs nothing captured first.
The tape is always recording the mix — a rolling 60 seconds. Nothing you do to it affects what the tabs are playing, so the sources keep running underneath whatever you are doing.
The status line under the controls reports the mode, how far behind live the tape head is, and how much of the 60-second buffer is filled.
Every channel has a strip of its own — under its name in the control layout, laid over the foot of its picture in video mode.
They are on the tape's timeline, not their own. All of them share the tape's window and its play head, so the white lines all line up and you can read straight down the column: this is what each source was contributing at the moment you are hearing. Scrub the tape back and the strips go back with it.
Which is why they are not simply "the last ten seconds of this channel". That reading looks tidier — the strips are always full — but the moment the tape falls behind live it would be showing you a different instant from the one you are listening to, in a picture that invites you to compare them.
They show what a channel is contributing after its fader and before its pan, the same place its meter reads, so moving the pan does not change the shape of its waveform.
Clicking a channel's picture pauses it. Clicking its waveform does not — the strip sits outside the part of the tile that responds to a click, so nothing you do to it can pause the source by accident.
On a channel strip, the dim shape to the right of the play head is sound the tab has already downloaded and has not played yet.
A capture can only ever hand back audio you have already heard — that is what a capture is. But a tab streaming from YouTube has been given a good deal of audio before it is due, sitting in the page waiting its turn, and that is a real future rather than a guess at one. halo-halo tab reads it where it is and draws it in place.
How far ahead varies more than you would expect. Four tabs measured together sat 110 to 120 seconds ahead of their play heads and stayed there; other videos have been seen with twenty or thirty. It makes less difference than it sounds, because the window only has room for a few seconds of it either way — but it is worth knowing that an empty right-hand side is not the same as a tab that has buffered nothing.
It arms itself when you add the tab. There is nothing to switch on. It happens at the same moment halo-halo tab sets that tab's video quality, and the small interruption you may notice there is the same one — it is not paying for this twice.
It is drawn dimmer than the rest for a reason. What you are looking at is what the tab downloaded, not what came out of the mixer, so the fader, the pan and the mute have not touched it. A picture that made the two look identical would be claiming more than it knows.
How much room there is depends on the tape. The window holds four seconds to the right of the play head. Sitting at live, all four are available. Fall two seconds behind and the first two of them are the tape's own recording — sound already captured, waiting for the head to reach it — so the downloaded shape starts at the live edge and gets whatever is left. Far enough behind and there is no room for it at all.
Not every tab has one. This only works for tabs that stream in the way YouTube does. A plain audio file, a tab that will not say what it is buffering, and anything protected by DRM will show nothing to the right of the head — and an empty right-hand side is the honest answer, not a fault.
The strip across the top of the tape box is the tape itself, going past. Ten seconds behind the play head and four seconds ahead of it.
The white line is the play head and it never moves. The tape slides past it, the way it would on a machine. Everything to its left has been played; everything to its right has not.
Because sometimes there is something to put there. The tabs keep recording forwards whether or not the tape head is keeping up, so the moment you fall behind live — after a reverse pass, a stutter, a scrub — the seconds between the head and the present are already on the tape. That is a real future and it is drawn. The faint live mark shows where recording has actually got to, so the gap between the head and that mark is how far behind you are: a distance you can see rather than a number you have to read.
At live there is nothing ahead of the head and that side is empty. That is the right answer, not a fault — an empty right-hand side is the plainest way of saying you are in the present.
The 1s / 2s / 4s / 8s loop buttons grab the last few seconds — they reach backwards from the moment you press. Which makes choosing the start of a loop a matter of remembering where you were four seconds ago.
So each button has a colour, and a line of that colour on the waveform marks exactly where that button's loop would begin. Watch a phrase travel towards the pink line, press 8s as it arrives, and the loop starts on it. The lines stay put; the tape moves through them.
One button, in | out, and it walks through three states.
i on the keyboard walks the same three states, because reaching for a
mouse mid-performance is the thing this is trying to avoid.
A tapped loop keeps for as long as you like. It is copied out of the tape when you close it, rather than left in the part that carries on recording — so it stays the thing you captured instead of slowly turning into the present. off drops the copy and carries on from where the tape is, because the tape never stopped recording underneath.
Whichever control started the loop is the one that lights. A four-second loop lights the 4s button; a tapped loop lights in | out — even if it happens to be four seconds long. A lit button always means this is what is driving what you hear.
Everything outside the loop is dimmed, so the part being repeated is the lit part of the picture. If the loop is longer than the twelve or so seconds on screen, or has scrolled off the back, a ◀ loop mark appears at the edge rather than the loop simply looking as though it is not there.
The waveform costs nothing to keep: the tape already held sixty seconds of audio, and this is a summary of it. Sixty seconds are kept even though about fourteen are shown, which is what will let the view move further back later.
Drag the waveform and the tape moves with your hand. The tape's own picture or any channel's strip — they are all the same tape.
Left is forward. Later audio is drawn to the right of the play head, so pulling the picture leftward is what brings it under the head — the same direction your hand moves a record to play it early. Drag right and it runs backward.
The speed is your hand's speed. This is not a scrub bar that jumps: the tape is asked to be where your fingers are, and whatever rate that takes is the rate you hear. Move fast and it screams; move slowly and it crawls; hold still and it goes quiet, because a stopped record makes no sound.
Let go and it plays on from there. It does not snap back to where
you grabbed it and it does not jump to live — you moved the tape, so the tape is
where you moved it. Which means you are now further behind live than you were, and
that is what the amber reading in the corner of the picture is telling you.
to live is the way back.
You cannot scratch past now. Forward of the play head there is only what has already been recorded, and past the live edge there is nothing at all — so a hard drag leftward stops there rather than running away. Backwards you have the whole sixty seconds the tape is holding.
If the tape was not engaged, grabbing it engages it. There is nothing to pull on otherwise — in thru the head sits at the live edge by definition. Putting a hand on the waveform drops onto the tape the way putting a hand on a deck is how you start using it, which also means the quarter second of standing latency appears at that moment. Dragging a channel's strip still cannot pause that channel: the strip sits outside the part of the tile a click reaches.
Reverse leaves you in the past, and normal speed never brings you back. to live does.
reverse latches. While it is running the gap between the tape head and the present opens at two seconds for every second you hold it — the head walks backwards while the tabs keep recording forwards. Ten seconds of reverse puts you twenty seconds in the past, up to the 60-second limit of the buffer.
Since v0.0.8 the button lights up while it is running, and clicking it again releases it — but that only returns the speed to normal. The head stays where it walked to.
Pressing 1.0 afterwards does not undo that either. At normal speed the tape head advances at exactly the speed the recording does, so the gap is held open indefinitely. Only four things close it: to live and thru (instantly), releasing a stutter, or a speed above 1 — and that last one only claws back speed minus one seconds per second, so 1.5× needs eight seconds to recover a four-second gap.
Why this matters more than it sounds. Nothing about the sound tells you it is happening. You hear the mix as it was, and every change you make from then on — a fader, a speed, a mute — is recorded immediately but does not become audible until seconds later. In video mode it is worse: the picture stays live while the audio sits in the past, so they drift apart and stay there.
So the mixer says so. Once you are more than half a second behind, to live turns amber and pulses, and the status line turns amber with it. Both go back to normal the moment you are level with the present.
This is deliberate rather than a limitation. Playing forwards at normal speed from ten seconds ago is a real move — it is how you play back something you just caught — so the tape does not silently yank you to the present just because you asked for normal speed.
The video switch at the top right swaps the mixer for a performance layout: every channel becomes a video tile showing that tab's picture, with its controls laid over the bottom edge. Same channels, same tape, same MIDI bindings underneath — only the presentation changes, and switching back and forth disturbs nothing.
A 2×2 grid on a 16:9 screen gives cells that are 2:1 — wider than the 16:9 picture inside them — so every tile has spare width down its sides that the video could never use. That is where the controls go: a tall fader either side rather than a thin strip along the bottom, because side pixels are nearly free while bottom pixels cost the video both height and width.
The controls deliberately do not fade out after a few seconds the way video players usually do. On a performance stream the faders moving are half the point of watching.
The button says which it is — HQ ON or HQ OFF — not just what it is called. The setting is remembered across sessions, so a panel can inherit it from weeks ago and be doing that work with nothing on screen to distinguish it from one that is not. A lit button is a convention; the word is a fact.
Every tab is told, including ones added later. Low tells each tab to decode at its lowest quality as well as capturing it small — and until 0.0.21 a tab captured part-way through a session was never told, so it went on decoding at whatever quality it had chosen while being captured at 426×240. Four of those is most of what the machine was doing.
Four videos at once is real work for a laptop, and it is being paid twice: each tab is decoding YouTube at whatever quality it chose, and the mixer is then capturing that tab's picture on top. HQ, next to clean, moves both halves together.
Switching does not interrupt anything — no channel drops out and no audio gaps. Setting the tabs' own quality reaches into YouTube's player, so on a page that has changed shape underneath us it may quietly do nothing; the capture side always applies.
A mix is four tabs, each at some moment, blended at some levels, through a tape at some speed. Close the window and there is no way back to it — you cannot bookmark these four, at those moments. That is what snapshot is for.
Press snapshot in the Mix section (or y, or
the button beside the tape in video mode). Chrome asks where to put the
file. Inside it you get both halves at once: the top is a
readable list you can open in any text editor, or glance at with Quick
Look; below a marker line sits the data restore reads back.
halo-halo tab mix — Aug 19, 2026 4:12 PM
1. Lavender Country — Cryin' These Cocksucking Tears
https://lavendercountry.bandcamp.com/track/…
at 2:41 of 4:02 · lvl 0.82 · L20
2. Blade Runner Blues
https://youtube.com/watch?v=…
at 30:41 · lvl 0.55 · centre · MUTED
tape: thru · 1.00x forward · cubic
halo-halo tab 0.0.11
── halo-halo tab data, do not edit below ──
{"app":"halo-halo tab","snapshot":1,…}
Notes you type above the list survive a reload, so a snapshot is a reasonable place to write down what you were going for.
restore… sits directly beside snapshot, in this same Mix section. It opens a file picker. halo-halo tab reopens those tabs and, as each one is captured, puts its level, pan, mute, solo, speed and position back on.
There is a restore… beside the tape in video mode too, but pressing it drops you back into this layout first — a restore is not a performance action. It reopens tabs and then needs you at the toolbar, and the waiting list that tracks that lives here.
It cannot capture them for you. Chrome only allows a capture from a real click on the toolbar button, one tab at a time, so a restore is half-automatic by design: halo-halo tab opens the tabs, you click the button on each, and the channel snaps into place as it arrives. A waiting list names the ones still owed, and survives closing the mixer — four tabs is four trips to the toolbar.
A YouTube link gets its timestamp written in, so the tab lands near the right moment before it is even captured. No other site is guessed at: every one spells that differently and a wrong guess is worse than none.
● record in the Mix section, R on the keyboard,
or the button beside the tape in video mode. Press it again to stop, and
then you are asked where to put the file.
It records after the tape — so a reverse pass, a stutter, a speed ride are all baked into the file. The recording is the performance, not the ingredients.
Starting and stopping is inaudible. The recorder is a second tap hung off the output, never in the path of it, so you can hit record in the middle of something good without a click or a gap.
Nothing interrupts you while it runs. The take is written straight to private storage on disk as it goes, so there is no dialog until you stop — being asked where to save is a fine thing after a performance and the wrong thing during one.
The button pulses red while it runs, in both layouts, and the line beneath it counts the minutes and the megabytes. That is deliberate: a take you have forgotten you are making is the way this feature goes wrong.
.webm, so
Logic wants it converted before it will take it. Worth choosing when you
know it will be a long session.
Neither has a length limit. Both are written to disk as they record rather than held in memory, so an hour costs no more memory than a minute. WAV used to be impossible for exactly that reason; it is not any more.
The take is not lost. It is already a complete file — the dialog only decides where to copy it — so cancelling keeps it and a save take… button appears to place it later. The same thing rescues a take from a mixer that was reloaded or crashed while recording, which older versions simply lost. The button is hidden when there is nothing waiting, so if you can see it, something is owed to you.
Sixteen-bit audio has a hard ceiling that the mixer's own signal path does not, and channels sum, so a mix can run out of headroom without any single channel looking wrong. The take counts every sample it had to flatten and says so when it saves. If it does, pull the master down — see The master.
The mix comes out of the mixer tab itself. So casting that one tab sends the sound and the video grid together, while the captured tabs play on in the background, unheard directly.
set up for casting does the part that is halo-halo tab's: switches to the video grid, turns high quality on, hides the overlays and goes fullscreen — the state actually worth mirroring.
Chrome does the casting, not the extension, and that is not a shortcut taken. An extension is not allowed to start a cast: there is no API for it, and the two web APIs that come close both refuse a live audio stream. So the last three steps are yours and there is no button that can do them. None of this has been tried against real hardware. If the menu does not behave as described, that is worth reporting rather than working around.
Faders, knobs and pads can drive the mixer. Press enable MIDI once — Chrome asks permission for all MIDI access, and remembers your answer.
Bindings are saved against channel position, not against the tab. Fader 1 drives channel 1 today and tomorrow, and if you remove the top channel the one below it moves up into that fader. Binding against a tab would not survive a restart, because Chrome renumbers tabs every session.
Knobs and faders map across their full range. Pads and buttons fire once on press, so holding one doesn't retrigger. Your mappings are listed under the MIDI section with an × to forget any of them, and they survive closing the browser — they are shown even before you enable MIDI, so a restart doesn't look like they were lost.
Press ? in the mixer. That list is the manual
for this section — it is generated from the bindings themselves, so it cannot
fall out of date the way a printed one does.
Nobody has performed with this yet. It passes its tests — 64 of them — but no one has had it under their hands during a set, and the defaults for the halo-halo-tab-specific keys are considered guesses rather than decisions. Move anything that sits wrong (see rebinding below) and say what you changed; there is an open question about the grammar on issue #3 in the extension repo.
The grammar is los's,
because Tube asked for it by name and because it is a real grammar rather
than a list of shortcuts: navigate along the layout, adjust across it; a number typed first repeats what follows (3j moves three);
the shifted form of an adjust key is a bigger step.
The tape is the last strip.
h and
l walk left and right through your channels and then onto the tape,
exactly the way los's own mixer walks onto MASTER. So the tape's speed, loop
and interpolation sit under the same keys as a channel's level and pan, and
there is no separate mode to be in without realising.
3K does it three times.v is reverse and
s stops the head.
A strip below the tape says what is selected — keys channel 1 · level 1.000 — and the selected channel is outlined in both layouts, so the keyboard is never acting somewhere you cannot see. Typing into a control does not move anything: click a fader and the keys leave it alone until you click away.
Every key can be moved, the same way MIDI already works. Press
?, turn on learn, click the line you want,
then press the key. reset all puts everything back. Your changes
are saved beside your MIDI mappings and survive a restart, and the list shows
moved keys in accent so an edited keyboard reads at a glance.
Taking a key that is already in use unbinds whatever had it
rather than leaving two actions fighting over one press — the displaced line
reads unbound until you give it something. A few keys refuse to move
and say why: digits belong to counts, and gg,
gt#, dd, Esc and ?
itself stay put, since rebinding the way back into the list is a way to lose
it.