remotion-dev / remotion

🎥 Make videos programmatically with React
https://remotion.dev
Other
20.7k stars 1.04k forks source link

Proposal: Add the ability to make Player controls' UI declaratively headless for better customizability #2142

Closed Just-Moh-it closed 1 month ago

Just-Moh-it commented 1 year ago

Feature Request 🛍️

Currently, if you need to implement something along the lines of a custom player UI, you have to get messy with addEventListeners, self-managed state, synced stores (for currentFrame), etc. just to do something super simple like showing the play/pause button somewhere far apart in the UI.

Even though we have props on the Player component for customizing icons and play/pause buttons, it requires you to use Remotion's built-in controls that overlay the video (which is not generally common for stuff like video-editor UIs, where the controls are custom).

Take the following for example:

image

Just implementing the above UI (along with the volume slider) requires you to set up and manage 5+ event listeners (some of which aren't implemented, yet like volumechange (#2141)), and external store syncing hooks

Possible Solution

We could have a headless version of the controls, so adding custom controls could be less frictional.

Something along the lines of what headlessui from tailwindcss does.

For example, the play pause button could be:


// ...
<div className="container">
    <Player ... ref={playerRef} />
</div>
<div className="flex items-center gap-3">
    <Player.PlayPauseButtonRoot playerRef={playerRef}>
        <Player.PlayButton>
            {*/ Custom Play button */}
        </Player.PlayButton>
        <Player.PauseButton>
            {*/ Custom Pause button */}
        </Player.PauseButton>
    </Player.PlayPauseButtonRoot>

    <div className="group">
        <Player.VolumeButtonRoot ref={playerRef}>
            {*/ Optional function wrapper to get access to vars */}
            {({isMuted}) => (
                <Player.MutedIcon>
                    {*/ Icon */}
                </Player.MutedIcon>
            )}
        </Player.VolumeButtonRoot>

        <Player.VolumeSliderRoot ref={playerRef}>
            {({volume}) => (
                {*/ fine-grained-control: Only showing when the mouse is hovered over the volume slider */}
                {*/ type of html <range /> element */}
                <Player.VolumeSlider 
                    max={100} 
                    min={0} 
                    step={1} 
                    value={volume}
                    onChange={(newVolume) => {...}} className="group-hover:block hidden"
                >
                </Player.VolumeSlider>
            )}
    </div>
</div>

In the component, the playerRef would be used to manage state and listen for updates like pause or play.

We could take it a step further by adding the as prop to items for more fine-grained control over what DOM element the component would render, similar to headless UI.

We could have this as a major feature of the v4 release. LMK what you think @JonnyBurger.

JonnyBurger commented 1 year ago

Thanks for the great user story!

I'm positive towards, but since it seems it can be implemented in userspace, it is not a priority for Remotion to ship this soon. We will delay features for after V4 that are non-blocking for people, so for me this is a "backlog" issue.

If someone steps up and wants to implement this properly, then we will cooperate!

JonnyBurger commented 1 month ago

There is maybe a bit of a regret in how the API was designed.

But it is not necessary to duplicate the API now or make a migration IMO, because we just made it very easy to customize controls in and outside the Player. Just copy the snippets into your projects and start styling them!

https://www.remotion.dev/docs/player/custom-controls