The goal of this kind of specification is to help incoming workers to dive into the code. It must also help experimented workers to hold a clear overview of the project.
You can change your blueprint for a UML diagram, particularly an activity diagram in your case. This offers a (more or less) standardised way to visually represent your workflow. It shows the actions done on the algorithm, the choices made, the options available for each choice, the loops, etc. You can also show the begining and the end of your process, exhibit the elements requiered or produced by it, and highlight some points thanks to comments.
At a lower level, intelligently comment the code is always a good idea. Generally, one must specify, for each piece of code (function, method, class, ...)
- Its inputs, and which properties they must respect (the list must be sorted, etc.);
- Its output;
- What happens in particular cases (an empty list, an invalid input, etc.). Indicate the raisable exceptions, if your language support them;
- Its side effects (ideally it should not have any). Typically the read/write from/to files, network, etc.;
- If it is thread safe. That is, if its state can be changed during its execution by an external entity. Check for instance if the list given as an input can be changed externally. Thread safety is very important in a multithreaded environment, of course, but this is also a sign of quality. The developers should be very carefull when they use an unsafe piece of code.
- Its time and memory consumption, w.r.t its inputs. The external users want answers to questions like "Can I give a (very) big list to this function with no major computation time issue?".
- The context in which it must be used, if this context can affect its behaviour (ideally it should not be the case since the only influencing factors should be its inputs).
- If requiered, how to automatically build and test it.
Use tools allowing you to add those comments in your code, and being able to automatically generate reports in a separated document. See javadoc or Doxygen for instance. Thanks to these tools, you can update the information in the same time you change your code, and get an always up-to-date separated documentation.
Complete the specifications by automated tests, and consider them as part of the documentation. Tests describe what should be the code behaviour in normal situations and exceptional situations.
Your engine should then be considered as a collection of entities communicating together. You know how each entity works, how entities must act together and how they act in representative situations.
Note this is not an advocacy of OOP, since the "entities" can be functions (in functional programming), structures, classes (in OOP), etc.