preload='metadata' doesn't decode video frames, so readyState stays at 1 (HAVE_METADATA) and loadeddata never fires. capturePoster() now detects this state and forces a seek to 0.1s via _trySeekCapture(), which triggers frame decode and captures on the 'seeked' event.