Skip to content
E4E
PROJECTS

Ostinato

Turns any YouTube video into a hands-free practice loop for musicians.

LIVE
  • Next.js
  • React
  • TypeScript
  • Tailwind
  • Zustand
  • Firebase
  • Playwright
COMMITS
170
FIRST
Dec 2022
LAST
Oct 2026
ACTIVE MONTHS
8

Ostinato

Loop any passage of any YouTube video until you can play it.

Paste a YouTube link, mark the few seconds you're learning, and Ostinato plays them over and over — hands-free, at whatever speed you need — while you play along. No scrubbing back, no overshooting, no breaking your focus.

Open Ostinato · Try the demo · User guide

The Ostinato home page: "Mark it. Loop it. Learn it." beside an animated picture of a video and its timeline

ostinato (Italian, "obstinate"): a short musical phrase repeated persistently.


Who it's for

Anyone learning music by ear from YouTube — a guitar solo, a piano run, a drum fill, a vocal line. You find the video, you find the tricky bit, and then you need to hear that bit again. And again. And slower. Ostinato does exactly that, and keeps your place so you can pick up tomorrow where you left off.

It's free, it works without an account, and nothing is uploaded: your loops live in your browser until you choose to sync them.

Three moves

  1. Paste a YouTube link on the home page. It opens straight away.
  2. Mark the passage: press M where it starts and M again where it ends. That's a loop.
  3. Loop it: press ▶ on the loop (or its number key) and it repeats until you stop it.

Practising a guitar solo: the video on the left, the loop list on the right, and a loop called "The fast run" repeating

What you can do

Mark a loop while you listen

Press M at the start of the passage and M at the end. The frame turns red and a timer counts while you're marking, so you always know you're "recording". Changed your mind? Esc cancels. You can also just drag across the timeline to draw a loop.

Marking a new loop: the video has a red outline and the timer reads "REC 0:01.8"

Loop hands-free, at any speed

A loop jumps back to its start the instant it reaches its end — every time, at any playback speed from 0.25× to 2×. Pause and it waits; play and it carries on from where it was. The row shows a spinning ↻ and counts your repetitions.

Fine-tune the edges to a tenth of a second

Pinch the timeline (or Ctrl+scroll) to stretch it out and scroll along it. Drag either edge of a loop on the timeline. Press and hold still on an edge and the timeline zooms in ×8 right around it, so you can set it to a hundredth of a second. Or use the keyboard: [ ] move the start and { } move the end by 0.1 s.

Holding a loop's end edge: the timeline has zoomed ×8 and shows "END ▸ 0:24.00"

Everything about a loop in one menu

The ⋮ on each loop has everything else (right-click a loop's block on the timeline to delete it quickly): type exact times, rename it, duplicate it (handy for splitting a long passage), change its colour, or delete it. Every change can be undone from the message that pops up — or with ⌘Z (see Undo and redo).

The loop menu open, showing Edit times, Rename, Duplicate, the three colours and Delete

The Edit times dialog with start and end fields, ±0.1 buttons and 'Playhead' shortcuts

Undo and redo

⌘Z (Ctrl+Z) takes back your last edit — a new loop, a moved edge, a rename, a colour, a rating, a delete — and ⌘⇧Z (Ctrl+Y) puts it back. You can go back as far as the moment you opened the video.

Nothing you undo is ever lost. If you undo a few edits and then make a new one, the edits you undid aren't thrown away as they would be in most apps: they stay as a second branch. Undo back to where the two part and ⌥⌘Z (Ctrl+Alt+Z) chooses which branch redo will follow. How it works is below.

Rate yourself as you improve

Three shapes on each loop show how well you know it. Hover them and they say Rate yourself; click to set Beginner, Intermediate or Pro. Your library shows the progress across every video, and a video where you've mastered every loop gets a MASTERED badge.

Hovering a loop's rating shapes shows a small 'Rate yourself' label

Practise several passages as one

Click one loop and Shift+click another — or drag down the list, or Shift+drag across the timeline — and every loop between them plays as one: Ostinato loops the whole stretch from the earliest start to the latest end, straight away, and every loop inside it lights up. Shift+click further loops to stretch it, or its first or last loop to trim it; it keeps playing as you go. Great for stitching sections together once you know each one.

Three loops selected together and playing as one: all three rows highlighted, a hatched stretch over them on the timeline, and "3 selected · Stop" under the list

Your library

Every video you practise is kept in your library, most recent first — with how many loops it has, how well you know them, and when you last played. Search by title or channel, sort it, remove videos, or export everything as a file.

The library: four videos as cards, one with a MASTERED badge

A bigger video when you want it

Focus mode (the FOCUS button, or H) gives the video the whole page and tucks your loops into a drawer at the side.

Focus mode: a larger video with the loop list in a drawer on the right

Keyboard first

Everything works from the keyboard — press ? anytime to see every shortcut.

The keyboard shortcuts list, grouped into Player, Marking, Editing, Loops and App

KeyDoes
MMark the start, then the end, of a new loop
Space / KPlay / pause
1–9Play that loop
SStop the loop
N / PNext / previous loop
[ ] · { }Nudge the start · the end by 0.1 s (hold ⌥/Alt for 1 s)
⌘Z · ⌘⇧ZUndo · redo (Ctrl+Z · Ctrl+Y on a PC)
⌥⌘ZSwitch which branch redo follows (Ctrl+Alt+Z)
− / = · 0Slower / faster · normal speed
HFocus mode
TLight / dark theme
?All shortcuts

With a mouse or trackpad: Shift+click grows the selection, ⌘/Ctrl+click adds or removes one loop, Shift+drag on the timeline sweeps loops up, pinch zooms the timeline, and right-click a loop's block to delete it.

On your phone too

The same app works on a phone: tap ▶ to loop, tap the big red button to mark, swipe a loop left to delete it.

Ostinato on a phone: the video, the timeline and the loop list    The library on a phone

Light or dark

The practice page in dark mode

Your loops on every device — if you want

Ostinato never needs an account. When you'd like your loops on your other devices, sign in with Google or with an email and password: your library is backed up and follows you, and changes show up on your other devices within a couple of seconds.

The sign-in dialog: Continue with Google, or sign in with an email and password

Try it without typing anything

The demo opens a guitar solo with ten loops already marked. Press ▶ on one and you'll hear how it works. Nothing you do in the demo is saved, so play freely.

The demo: ten loops ready on a guitar solo, with a tip pointing at the first loop's play button

Your data

  • Without an account, everything stays in your browser on this device. Nothing is uploaded. You can export your whole library as a file from the library page.
  • Signed in, your loops are also backed up to your own account so they appear on your other devices. Signing out removes them from that browser (they stay safe in your account).
  • Ostinato stores only what you create — the video's link, title and your loops. It never downloads or copies the videos themselves; they play in YouTube's own player.

How undo and redo work

Most apps keep undo as two stacks: undo pops one, redo pops the other, and the first new edit after an undo empties the redo stack — whatever you had undone is gone. Ostinato keeps a tree instead, so that edit starts a new branch and the old one stays reachable.

The tree. Each node is one state of the video's loop list, and remembers its parent, its children in the order they were made, a label for the edit that produced it ("Loop 3 deleted"), and a redo pointer — the child redo will walk to. The root is the list as it was when the video opened. One cursor marks the node you are looking at.

text
root ── A ── B ── C          undo, undo, then a new edit D:
             └─── D ◀ you    B now has two children; C is kept

The four operations

OperationWhat it does
EditAdd the new state as a child of the cursor, move the cursor to it, and point the parent's redo pointer at it. Existing children are left alone — that is the branching.
UndoMove the cursor to its parent. Nothing at the root.
RedoMove the cursor along its node's redo pointer. Nothing at a leaf.
Switch branchAt a node with two or more children, move its redo pointer to the next child, wrapping round. The cursor doesn't move; the next redo takes that branch.

The redo pointer is what keeps plain undo/redo feeling ordinary: it always points at the child you most recently made, came back from, or chose, so undo followed by redo returns exactly where you were, and a fresh branch is the default right after you make it. In the picture, undo from D lands on B; redo goes back to D; ⌥⌘Z then redo goes to C instead.

Details that matter

  • States, not inverse operations. A node holds the whole loop list, so moving the cursor is just "make the list this". Loops are immutable values and neighbouring states share the ones that didn't change, so a node costs about one array.
  • Bursts are one step. Keyboard nudges on the same loop less than 1.5 s apart rewrite the node they started rather than adding one each — unless something has already branched off it.
  • No-ops aren't steps. An edit that leaves the list as it was adds nothing.
  • Plays aren't edits. A loop's play count is never rolled back; a loop brought back by undo or redo returns with the plays it last had.
  • The toast's Undo is the same undo. If its edit is still the latest, it moves the cursor up (so redo can bring the edit back). If you've made other edits since, it applies the reversal as a new edit.
  • What goes with a loop. If undo or redo removes a loop that was selected or playing, it is deselected and stops looping (the music carries on); if it moves a playing loop's edges, the loop follows.
  • Bounded. Past 300 states the oldest goes: the root is dropped along with any of its branches that don't lead to the cursor, and the next state towards the cursor becomes the root.
  • Where it ends. The tree lives for the visit — it isn't saved, and it starts afresh when another device's changes arrive, so an undo can't silently overwrite them. Undo is off while you are marking a loop.

The tree itself is under 200 lines with no dependencies: src/domain/history.ts, tested in history.test.ts; the practice page's store (src/stores/session.ts) records each edit into it.

More

  • User guide — every feature step by step, tips, and answers to common questions.
  • Changelog — what's new.
  • Developers — how it's built, tested and deployed: DEV_DOC.md.