Hey thanks for playing! Yeah so the ghosts following your movements are just visual candy - the buttons will get pressed at the right time regardless.
we did the ghosts by buffering user inputs and processing them all in the fixed rate physics loop. Then we’d send the buffer of inputs for a particular frame for storage. These lists of inputs are used to create ghosts. So the ghost receives the exact same commands at the exact same frame and uses the exact same movement controllers. Interactions are recorded by the buttons, doors, etc. in a similar way so they activate at the same time every loop.
the issues with ghost desync is sadly something that showed up towards the end of development - it’s due to the load order of ghosts vs level, we suspect.