Port floorplan item thumbnails, full mobile editor UI, and mobile polish from the private monorepo into the public editor. Monorepo PR #297 (feat/item-admin-advanced): - Add optional floorPlanUrl to item asset schema (core) - Render 2D floor-plan images inside item footprints on floorplan - Improve slider drag with modifier key re-anchoring Monorepo PR #302 (feat/mobile-ui): - Mobile editor layout with draggable bottom sheet - Mobile tab bar, selection bar, and panel sheet - Mobile-aware panel manager and panel wrapper - useIsMobile rewrite (useSyncExternalStore, SSR-safe) - Camera actions hideOrbit prop - GridSnapControl and SecondaryToggles exports - Action menu hides on mobile contextual tabs - SidebarTab extended with mobileDefaultSnap/mobileIcon Monorepo PR #306 (feat/mobile-ui-polish): - Touch gesture mapping for camera controls (one/two/three finger) - Snap ratio constants for bottom sheet - Thumbnail generator WebGL2 fallback (bottom-up row flip) - ErrorBoundary scope logging, viewer scene wrap - GPUDeviceWatcher enhanced logging and uncaptured error handler - WebGPURenderer init error handling and diagnostics - Post-processing log improvements - MergedOutlineNode WebGL2 FBO corruption fix Excluded: apps/community/*, apps/editor/*, packages/community-*, .cursor/*, .env.example (monorepo-only files) Co-authored-by: Pascal <open@pascal.app>
This commit is contained in:
@@ -166,6 +166,14 @@ export class MergedOutlineNode extends TempNode {
|
||||
private readonly _cacheA = new Set<Object3D>()
|
||||
private readonly _cacheB = new Set<Object3D>()
|
||||
|
||||
// Tracks whether either group rendered last frame. We use this to decide
|
||||
// when it's safe to skip renderer state manipulation entirely — touching
|
||||
// the renderer (resetRendererAndSceneState + setRenderTarget + clearColor)
|
||||
// corrupts the FBO state on the WebGL2 backend (iOS Chrome fallback) and
|
||||
// the subsequent scene render comes out blank.
|
||||
private _wroteGroupALastFrame = false
|
||||
private _wroteGroupBLastFrame = false
|
||||
|
||||
private readonly _textureNodeA: any
|
||||
private readonly _textureNodeB: any
|
||||
|
||||
@@ -294,6 +302,17 @@ export class MergedOutlineNode extends TempNode {
|
||||
updateBefore(frame: any) {
|
||||
const hasPrimary = this.primaryObjects.length > 0
|
||||
const hasSecondary = this.secondaryObjects.length > 0
|
||||
const hasAny = hasPrimary || hasSecondary
|
||||
|
||||
// Fast-path: nothing to render and nothing was rendered last frame either,
|
||||
// so there are no stale composites to clear. Touch nothing — on the WebGL2
|
||||
// backend (iOS Chrome fallback) even an empty reset/setRenderTarget cycle
|
||||
// corrupts the framebuffer state and the next scene render goes blank.
|
||||
const needsCleanupA = !hasPrimary && this._wroteGroupALastFrame
|
||||
const needsCleanupB = !hasSecondary && this._wroteGroupBLastFrame
|
||||
if (!(hasAny || needsCleanupA || needsCleanupB)) {
|
||||
return
|
||||
}
|
||||
|
||||
const { renderer } = frame
|
||||
const { camera, scene } = this
|
||||
@@ -303,24 +322,27 @@ export class MergedOutlineNode extends TempNode {
|
||||
const size = renderer.getDrawingBufferSize(_size)
|
||||
this.setSize(size.width, size.height)
|
||||
|
||||
// Clear composites for inactive groups so stale outlines don't persist on GPU.
|
||||
// Must happen inside resetRendererAndSceneState to avoid MSAA state corruption.
|
||||
if (!hasPrimary) {
|
||||
// Clear composites for groups that just transitioned from "has content"
|
||||
// to "empty" — without this, the previous outline lingers on the GPU.
|
||||
if (needsCleanupA) {
|
||||
renderer.setRenderTarget(this._groupA.composite)
|
||||
renderer.clearColor()
|
||||
this._wroteGroupALastFrame = false
|
||||
}
|
||||
if (!hasSecondary) {
|
||||
if (needsCleanupB) {
|
||||
renderer.setRenderTarget(this._groupB.composite)
|
||||
renderer.clearColor()
|
||||
this._wroteGroupBLastFrame = false
|
||||
}
|
||||
|
||||
const hasAny = hasPrimary || hasSecondary
|
||||
if (!hasAny) {
|
||||
RendererUtils.restoreRendererAndSceneState(renderer, scene, _rendererState)
|
||||
return
|
||||
}
|
||||
|
||||
renderer.setClearColor(0xff_ff_ff, 1)
|
||||
this._wroteGroupALastFrame = hasPrimary
|
||||
this._wroteGroupBLastFrame = hasSecondary
|
||||
|
||||
if (hasPrimary) this._buildCache(this.primaryObjects, this._cacheA)
|
||||
if (hasSecondary) this._buildCache(this.secondaryObjects, this._cacheB)
|
||||
|
||||
Reference in New Issue
Block a user