Rework output configuration options and their consumption - #4966
Conversation
|
I'm hoping to take a closer look at this over the weekend, but here are some immediate thoughts. I'm not very familiar with the details of the current config-render-scene pipeline, so perhaps these are all obvious or irrelevant!
Exciting stuff so far 👍 |
|
Great questions!
|
Cool, I thought that might be the case! In my mind, a "session" would be the execution and rendering of all scenes provided by the user, but that's just nomenclature stuff. I'm also thinking about this from a non-CLI perspective (let's say I'm building an editor for Manim which builds its own manager or whatever), but none of this seems to directly preclude doing that, so I'm happy there. Another off-the-cuff thought before I start looking at the code: Maybe I'm an extreme outlier and my workflow shouldn't weigh too heavily in these considerations, but I actually find it very useful to be able to invoke class CombinedScene(Scene):
def construct(self):
square = Square()
self.play(FadeIn(square))
self.play(FadeOut(square))
# this scene is very dense, so turn off caching
with tempconfig(dict(disable_caching=True)):
ReusableScene.construct(self)
self.play(FadeOut(*self.mobjects))Obviously I'll survive if I have to do something else! There's also this workaround which again isn't strictly necessary, but definitely a nice thing to have at your disposal. |
nikolajmunk
left a comment
There was a problem hiding this comment.
I've only taken a cursory glance at the implementation itself so far, but here's a quick pass of documentation. Many of these were pretty LLM-y; in particular, I've noticed that LLMs love to write documentation that explains what was changed rather than what is now true about the code. For example it might write "this function accepts both string and integer input; integers are correctly cast to string and do not raise an error" rather than just "this function accepts string and int input". I've tried to make the wording clearer, more human-sounding and more useful to future users of Manim.
Hope these are of any use!
Co-authored-by: nikolajmunk <28557236+nikolajmunk@users.noreply.github.com>
|
OK, as far as I can tell everything looks good on the code side. I have a few comments about config options:
As a side note, here's a possibly overengineered thing I'm wondering: would it perhaps make sense to encode the constraints of the config (e.g. |
behackl
left a comment
There was a problem hiding this comment.
Agreed with all direct suggestions, and attempted to improve wording for all other regions where you left comments as well. Thanks for the detailed look at this!
Thanks for the careful review, much appreciated!
Ah, this is a great question! I tend to agree that any "smartness" in the handling of the output format should be restricted to when the output format is set to There actually is an argument that could be made for the library always appending a 1-frame long animation at the end (which would resolve the issue reported many times that for a scene just containing a I think what I'd like to do is implement a combination of your two suggestions: only let manim try to be smart about the output format while the value is
Are you sure? This might just be explained incorrectly in the docs, the code just has two sequential
It's an interesting suggestion, and sort of prompts the question whether it should be allowed to specify multiple output formats at once. I tend to agree, but would rather want to implement this as a fancy new feature later, separately from this refactor.
Interesting. I am sort of satisfied with the restrictions being all spelled out in I'll push a commit to change the behavior overriding user intent with the output format when there are no animations, plus fix the wording regarding preview + open in file browser. Thanks again! |
Yep, that's a very nice intermediary step!
Oop you're right! Both work at the same time on my machine. I had interpreted
Agreed! I do like the idea of
I was envisioning |
|
Pushed changes as discussed and fixed one test that failed as a consequence. I have also added a couple more cheap tests to make sure the behaviour is exactly what we want for now. (Need a lot of tests for the upcoming file writer decoupling and renderer migrations.) |
|
I think the only point I haven't really replied to in your review was about the mid-scene change of I'll update the branch, then get this merged to proceed with the refactor. Thanks again for the feedback! (I've made sure to incorporate the same points to the follow-up PRs as well, especially regarding documentation.) |
Summary
This PR replaces Manim's overlapping output flags with one canonical
formatsetting and resolves output and presentation intent once when a
Sceneisconstructed.
The resolved state consists of:
OutputSpecdescribing the primary artifact;PresentationSpecseparating post-render preview from live display;RenderSessionSpeccombining both with preserveddry_runintent; andThe resolved output is passed explicitly to
SceneFileWriter; the writer no longerreinterprets global output configuration.
Managerexposes the captured session andperforms post-render presentation from it.
User-facing output model
--formatselects one primary artifact:autoplayorwaitcalls, Manim saves a PNG instead and logs a warning. With live preview, it produces no file unless a concrete format is requested.nonemp4,mov,webm,gifplayorwaitcall.png-s/--save_last_frame.png-sequencePresentation is independent of artifact selection:
-p/--previewopens the completed artifact for either renderer.-l/--live-previewrequests renderer-provided live display. OpenGL supportsit; Cairo rejects it.
format=autois display-only. Supply a concrete video format todisplay and record simultaneously.
--show_in_file_browserreveals the completed artifact and can be combined with--preview.dry_runsuppresses output for the resolved session without rewriting the configuredformat or neighboring settings. The session retains
dry_run=Trueso later executioncoordination can distinguish it from another artifact-less render.
Breaking changes and migration
Most scenes rendered with Manim's default settings do not require changes. Scripts,
configuration files, and integrations that select output through the older boolean
options must migrate to the canonical
formatsetting.Common replacements
--write_to_movie,[CLI] write_to_movie, orconfig.write_to_movie = Trueformat=auto, or selectmp4,mov,webm, orgifexplicitly.[CLI] write_to_movie = falseorconfig.write_to_movie = Falseformat=none.-g,--save_pngs,[CLI] save_pngs, orconfig.save_pngs--format=png-sequenceorformat=png-sequence.-i,--save_as_gif,[CLI] save_as_gif, orconfig.save_as_gif--format=giforformat=gif.[CLI] save_last_frameformat=png. The-sflag and programmaticconfig.save_last_framealias remain available.--force_window,[CLI] force_window, orconfig.force_window-l/--live-preview. Add a concrete video format to record the live render as well.-f--show_in_file_browser.config.movie_file_extensionorconfig.resolve_movie_file_extension()config.format; extensions are derived from the resolved output.For example:
Output behavior changes
--format=pngnow fast-forwards animations and saves only the last frame, like-s. Use--format=png-sequenceto save every rendered frame.media/images/<module>/<Scene>/0000.png.format=auto, a scene withoutplayorwaitcalls produces a PNG and logsa warning. An explicitly requested video format fails instead; use
format=pngif a still image is intended.
-pnow opens the completed artifact after rendering, matching Cairo. Use-l --renderer=openglfor a live window.OpenGL with
format=autowrites MP4 or MOV; live preview withformat=autoremainsdisplay-only.
--previewand--show_in_file_browsercan be combined. Both require a producedartifact.
format=auto,mov, orwebm.Noneand an empty format value normalize toauto.dry_runno longer mutatesformat,write_all, or still-output settings.Sceneis constructed.Construct the scene inside the intended
tempconfigcontext. Unrelated temporaryscene configuration, such as changing
disable_cachingaround an individualplay, remains available.In particular,
formatis now loaded from configuration files.config.output_filewith the completed artifactpath. Use
scene.renderer.file_writer.final_file_pathto find the produced fileor PNG-sequence directory.
config.previewnow exclusively means opening completed output.config.live_previewrequests live display; the existingenable_guioption isalso interpreted as a live-preview request.
Python integrations
The format helpers
is_mp4_format,is_gif_format,is_png_format,is_webm_format,is_mov_format, andwrite_to_moviehave been removed frommanim.utils.file_ops. Code that decides output behavior should inspect the resolvedOutputSpec.Custom renderers and direct
SceneFileWriterusers must also:capabilities: RendererCapabilities;renderer.init_scene(scene)torenderer.init_scene(scene, session_spec);OpenGLRenderer.should_create_window();output_specwhen constructingSceneFileWriterand accept it ininjected custom writer classes; and
preview=andshow_in_file_browser=arguments toopen_media_file().Resolved intent is available through
Scene.session_spec,Manager.session_spec,Manager.output_spec, andSceneFileWriter.output_spec.Out of scope / follow-up work
This PR does not yet:
Manager;SceneFileWriterinto encoding, timeline, and assembly services;custom_folders; orThose remain stacked follow-ups after the session intent and ownership boundary.
(And just to be explicit about this: I've been working a bunch with GPT-5.6/Sol to put this together; everything in here has been reviewed at least coarsely by me though; critical parts and the general design shape were hand-crafted.)