C.W.K.
Stream
Lesson 03 of 05 · published

Fast Seek and Exact Seek Are Different Promises

~13 min · observed-state, seek, keyframes, ux

Level 0Reel Novice
0 XP0/39 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Provide two honest seek modes: a configurable relative seek for repeated keyboard movement, and exact seek for Recall handoff, Jump to Time, and A-B boundaries."

Two Things Users Mean by 'Seek'

When someone taps the right-arrow four times to skip past a slow scene, they want motion — smooth, instant, responsive. They do not care whether they land on the exact frame; they're scanning. When someone clicks a Recall transcript line, they want precision — that exact remembered second, no compromise. Same verb, opposite priorities. A player that treats both as one operation will disappoint one of them.

The reason they can't be the same is physical. Video is stored so that only some frames (keyframes) can be decoded on their own; the rest depend on their neighbors. Jumping to the nearest keyframe is fast but lands you a bit off. Decoding forward to the precise frame is exact but costs more work. You cannot have instant and exact from the same seek — so Ashen Reel offers both, and picks by intent.

Match the guarantee to the intent, don't force one mode to serve both. Scanning wants speed and forgives imprecision; landing wants accuracy and forgives a little latency. Collapsing them means either sluggish scrubbing or a Recall jump that misses the moment. Two honest modes beat one dishonest compromise.

The dispatch is tiny once you name why the seek is happening:

The relative seek is three-tier and configurable. Dad's real workflow wanted more than one skip size, so the keyboard offers a small/medium/large relative interval, each on its own collision-safe recorded shortcut. That's P1 depth earned by observed friction — not a preference-panel maze, just the few sizes a real viewer actually reaches for.

Where Each Mode Belongs

Once the split exists, assigning modes is obvious. Held arrow keys and scrubbing → keyframe seek, because the user is scanning and wants the picture to move now. Recall handoff, Jump to Time, chapter jumps, and A-B loop boundaries → exact seek, because those are promises about a specific frame. The mode is never guessed from the keypress alone; it's chosen from what the user is trying to do. That's the whole trick: a seek's correct behavior depends on its intent, so intent is what the code branches on.

I wanted one beautiful unified seek. One code path, elegant, done. Dad made me sit with the actual feel: hold-to-scan with exact seek is laggy and horrible, and a Recall jump with keyframe seek lands you two seconds off the sentence you searched for. "하나로 합치면 둘 다 반쪽이야." — merge them and both become half. The elegant version was elegant on paper and wrong in the hand. Two honest modes it is.

Code

Pick the seek mode from intent, not from the keypress·swift
enum SeekIntent { case scanning; case precise }   // WHY the seek is happening

func seek(by delta: Double, intent: SeekIntent) {
    switch intent {
    case .scanning:
        // Repeated arrow taps / scrub: keyframe seek. Trade precision for
        // instant response -- the user is scanning, not landing.
        try? mpvCommand(mpv, ["seek", "\(delta)", "relative+keyframes"])
    case .precise:
        // Recall jump, Jump to Time, chapter, A-B boundary: exact, decode
        // forward to the right frame even though it costs a little more.
        try? mpvCommand(mpv, ["seek", "\(delta)", "relative+exact"])
    }
}

// The keypress doesn't decide the mode. The user's INTENT does:
// holding an arrow -> .scanning; clicking a transcript line -> .precise.

External links

Exercise

Find an operation in your system that different callers use for different reasons — a search that's sometimes a live type-ahead and sometimes a precise lookup, a sync that's sometimes a quick refresh and sometimes a full reconcile. Are you serving both from one code path with one performance/accuracy tradeoff? Sketch splitting it by intent, and name the guarantee each variant makes. Which callers were quietly getting the wrong tradeoff?
Hint
The signal is one function whose callers would each tune it differently if they could — some want it faster-and-looser, some want it slower-and-exact. That's two promises. Branch on intent (why is this being called?), not on incidental details, and let each branch keep its own honest guarantee.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.