Personally, I am a big fan of how Amethyst handles these things, and I recently started putting them into a small OO ECS library for usage in a game (though I use Babylon instead of ThreeJS for that).
What is an ECS (Entity Component System)? tl;dr: it's an architecture which uses an index ("entity"), adds data-objects ("components") to the index, and then runs a logic (inside "systems") over the data-objects. It calculates everything it needs from the data provided by the data-objects only, hence is a functional, data-driven approach to handling lots of data on lots of entities which has to change often based on different logics. For example, you could create components for position, health, clan-membership,... and have a component which iterates over all entities which have a "Position" and a "Health" component, in order to decrease the health of anything which walks through lava.
ECS is just one of the architectures for big games. It gets a lot of hype recently, because it has a lot of advantages. There are variations of it in use, and depending on the needs an ECS library can be implemented in different ways to optimize certain aspects of it (for example system iteration vs. world modification performance). However, it's not the solution for all problems, so depending on the kind of simulation you want to create, ECS might be a good fit, but maybe someone else has a different pattern which is a better fit 😉
For my explanations, keep this in mind: sim-ecs is an ECS at the core, and builds utilities around it.
Handling loading state
I guess you mean loading the simulation state from a saved simulation? While not implemented, yet, sim-ecs stores all entities in an array. This array could be serialized easily in a way which keeps information about all components intact. Entities store their components in a Map locally for better performance. Loading state would do this process backwards: fill the array of entities, re-add all components with stored data and then maintain the world in order to prepare all systems for dispatch.
Three.JS does not provide any utility to do something like that, other than saving a scene - which does not include additional information about the game state. You'd have to re-calculate the information from the current scene, or store it separately. I'd prefer the ECS because it stores all relevant information centrally and is functional.
Handling animations
Using an ECS, just write a system which iterates over all entities with animation components and calculate the next step on them. Without an ECS, you could keep the animations in an array, and calculate the next step before every render-call.
Handling transition states
Transition states as in loading a new level? In that case, I like using state-objects, which define activation and de-activation methods, and possibly also expose a preparation method. The preparation method might prepare the game logic early without disturbing the current simulation (in sim-ecs, batch-adding new entities and components without maintaining the world), and then de-activate the old state (clean-up) and then activate the new state. For longer loading times, the methods may display loading screens.
In case you are not using an ECS, you might load the next scene with all assets in the background and then switch out the active scene. Just make sure that you either stay functional, or keep couplings to a minimum, so your scene does not depend on old values or similar.
Handling user input
User input is event-driven by nature. In Amethyst, at the beginning of a simulation step, all events are polled from the OS and stored in a global resource. This resource can then be polled by all logic in order to find out which keys are pressed and how the mouse was moved. Very important is that you map your code against "actions", and map keys against actions in a configurable way, so that a player can change the key mapping. Also you might want to prefer scan-codes instead of buttons for some problems. For example WASD will work most of the time, except on for example French keyboards - scan-codes will make it work everywhere. (see this discussion)
Switching / transitioning between scenes
That's very simulation-dependent. Most games use loading-screens. They might be your typical TES-style screens with a progress bar, or they might be transition videos, like in the X games. Ideally you use a chunked world, which loads in the background, so you don't need to transition, ever.
If you have to switch between scenes, you also have to keep in mind that you might have to update or even switch your state, which imho is easy with an ECS.
Adding / removing objects from scenes
In an ECS, it's just adding the entities and maintaining the world. New objects will be picked up automatically because of the functional nature.
General project structure
In general, I like the idea of ECSs. They allow me to separate data from logic, and are functional, so that I have no dependencies on data from my logic. On each frame, all data is poured into the systems, and they just do their thing. Need to add objects? Just do it, they will be available the next frame the latest. Many modern game engines change into this direction because it's a great concept!
If you do not use an ECS, I highly recommend keeping things data-driven anyway. It is rather hard to work with hard-coded objects, and each change means you'll have to re-build the project. Also you will have problems using external tools, for example for your asset pipeline, because you might have to create plugins which simulate your hard-coded behavior instead of just writing a converter from a blender scene to your ECS format for example..