Use case
We are prototyping a generic opt-in path that allows a PBR scene to render its completed linear RGB result into a floating-point render target so that the application can own post-processing and final presentation.
The intended split is:
PBR lighting / IBL / emissive / plugins / fog → linear HDR render target
Then application-owned:
exposure → tone mapping → display gamma / presentation
Proposed API
enablePbrLinearOutput(scene: SceneContext): void;
Called on a fresh scene before mesh/build/registration work. It is opt-in, idempotent while fresh, and has no runtime disable; a new scene is required to return to display output.
For opted-in PBR, the final exposure, tone-mapping, display-gamma, clamp and contrast processing is omitted. Alpha is unchanged.
Current implementation shape
The prototype follows the same general family as other optional Lite enablers:
- Lazy WeakSet owned by the enabler.
- Resolver installed only when the feature is enabled.
- Optional resolver call in the PBR build path.
- No feature work during frame rendering.
The currently open implementation in PR #674, at 441b245e215e87fd8d19f3a1de1ca24c29846e24, uses a similar enabler/WeakSet/resolver shape.
Functional proof
Focused fixtures pass against source, lib and dist builds:
rgba16float, 4x MSAA + resolve, with linear PBR readback [14.34375, 14.34375, 14.34375].
- Fog and unlit preserved.
- Alpha MASK and double-sided preserved.
- CSM and a public MaterialPlugin contribution preserved.
- Two scenes with opposite policies remain isolated on one device, in both build orders and after rebuilds.
- Default output remains unchanged.
- No WebGPU validation errors in the focused fixtures; 57 devices acquired and 57 destroyed.
Bundle result
Fetched runtime bytes, measured with the same toolchain and lockfile against c9958540d15e457e2f4ba2be55d17dcfb0b09e39:
| Scene |
Base |
Candidate |
Delta |
| scene1 |
89481 |
89476 |
-5 B |
| scene10 |
52574 |
52577 |
+3 B |
| scene214 |
69338 |
69338 |
0 B |
| scene216 |
53756 |
53759 |
+3 B |
For scene10 and scene216, inspection of every emitted runtime chunk found no retained linear-output feature semantics/code.
The +3 B is caused by three occurrences of an existing baseColorMod identifier receiving a two-character minified name (te) instead of a one-character name (J / Y). All other emitted edits sum to zero bytes. A complete edit list reconstructs the candidate chunks byte-for-byte.
For precision, the raw diff also contains changed chunk hashes and a historical diagnostic ID changing from 459 to 460, with the same decoded message and zero byte delta. The +3 B growth itself is entirely identifier renaming. No minifier manipulation or unrelated byte compensation was used.
Primary questions
Does Babylon Lite consider this minifier-only byte movement an unrelated-scene bundle regression that must still be eliminated, or is the architectural requirement satisfied when no feature semantics/code remain in the unused bundle?
Is there a preferred existing PBR opt-in seam pattern we should use instead?
Lifecycle guard
There is one API-lifecycle question still open.
The enabler can reject scenes that already contain meshes/groups or are built, but during the first registration of an otherwise empty scene there is currently no existing state we found that reliably distinguishes "fresh" from "registration already in progress" before _built is set.
Is there an existing scene lifecycle state/seam that optional pre-build enablers should use for this guard, or should this simply be documented as a pre-registration contract?
Scope
- No bundle ceilings/baselines were changed.
- No fork is being proposed.
- No private API is required by callers.
- The prototype remains local and has not been pushed or submitted as a PR.
- We are asking for guidance before polishing/submitting the patch; this is an unfinished prototype.
Use case
We are prototyping a generic opt-in path that allows a PBR scene to render its completed linear RGB result into a floating-point render target so that the application can own post-processing and final presentation.
The intended split is:
PBR lighting / IBL / emissive / plugins / fog → linear HDR render target
Then application-owned:
exposure → tone mapping → display gamma / presentation
Proposed API
Called on a fresh scene before mesh/build/registration work. It is opt-in, idempotent while fresh, and has no runtime disable; a new scene is required to return to display output.
For opted-in PBR, the final exposure, tone-mapping, display-gamma, clamp and contrast processing is omitted. Alpha is unchanged.
Current implementation shape
The prototype follows the same general family as other optional Lite enablers:
The currently open implementation in PR #674, at
441b245e215e87fd8d19f3a1de1ca24c29846e24, uses a similar enabler/WeakSet/resolver shape.Functional proof
Focused fixtures pass against source, lib and dist builds:
rgba16float, 4x MSAA + resolve, with linear PBR readback[14.34375, 14.34375, 14.34375].Bundle result
Fetched runtime bytes, measured with the same toolchain and lockfile against
c9958540d15e457e2f4ba2be55d17dcfb0b09e39:For scene10 and scene216, inspection of every emitted runtime chunk found no retained linear-output feature semantics/code.
The +3 B is caused by three occurrences of an existing
baseColorModidentifier receiving a two-character minified name (te) instead of a one-character name (J/Y). All other emitted edits sum to zero bytes. A complete edit list reconstructs the candidate chunks byte-for-byte.For precision, the raw diff also contains changed chunk hashes and a historical diagnostic ID changing from 459 to 460, with the same decoded message and zero byte delta. The +3 B growth itself is entirely identifier renaming. No minifier manipulation or unrelated byte compensation was used.
Primary questions
Does Babylon Lite consider this minifier-only byte movement an unrelated-scene bundle regression that must still be eliminated, or is the architectural requirement satisfied when no feature semantics/code remain in the unused bundle?
Is there a preferred existing PBR opt-in seam pattern we should use instead?
Lifecycle guard
There is one API-lifecycle question still open.
The enabler can reject scenes that already contain meshes/groups or are built, but during the first registration of an otherwise empty scene there is currently no existing state we found that reliably distinguishes "fresh" from "registration already in progress" before
_builtis set.Is there an existing scene lifecycle state/seam that optional pre-build enablers should use for this guard, or should this simply be documented as a pre-registration contract?
Scope