Or just loop through all the players on the server and push to everyone but the engaging player instead of using FireAllClients
That is also valid - and saves one callback on one client, but I personally prefer just using FireAllClients()
Motor6D or hinges (with motor or AlignOrientation) are the viable options. Motor6D would be my preferred solution for these gates if they just auto-open at constant speed and are unstoppable. You would consider a hinge-based solution if you need them to respond to character physics, e.g. if players can push them open, or if you need them to stop opening or closing if the doors hit a player. Motor6D will not stop and can knock down or fling a player who gets pinched in the closing doors.
The slowness in undoubtedly from the wait() calls, which don’t wait a single frame like RunService.Stepped:Wait() or RunService.Heartbeat:Wait(), but can actually yield for multiple frames. In general, wait() should not be part of an animation system. You should also not move scripted animation to client LocalScripts to make it smooth when the animation involves collidable parts. Client-side animation should be for things like visual effects that have no physics and do not need to appear consistent across all clients. Having local physically-simulated parts in different places on the client and server is unsupported and will inevitably cause inconsistent-state-related glitches.
As long as I’ve got you here, in what circumstances does wait tend to yield multiple frames? I’m wondering why I’m seeing differences from server to server, and if resources really are being leaked somewhere I should probably fix that…