diff --git a/apps/editor/app/page.tsx b/apps/editor/app/page.tsx index e4ccf7ed39..1e3d0933a5 100644 --- a/apps/editor/app/page.tsx +++ b/apps/editor/app/page.tsx @@ -91,16 +91,12 @@ export default function Home() {
{PROJECT_ID === 'local-editor' && (
-
- Local editor — scenes are not saved. - - Open recent scenes - - - · +
+ + Blank canvas — saved scenes are under Scenes (not this page). - Create new + Open saved scenes
diff --git a/apps/editor/components/scene-loader.tsx b/apps/editor/components/scene-loader.tsx index 9b3b6797bf..fb891f1cbd 100644 --- a/apps/editor/components/scene-loader.tsx +++ b/apps/editor/components/scene-loader.tsx @@ -12,8 +12,9 @@ import { import { Hammer, Layers } from 'lucide-react' import Image from 'next/image' import Link from 'next/link' -import { useRouter } from 'next/navigation' +import { useRouter, useSearchParams } from 'next/navigation' import { useCallback, useEffect, useRef, useState } from 'react' +import { cn } from '@/lib/utils' import { BuildTab } from './build-tab' import { CommunityViewerToolbarLeft, CommunityViewerToolbarRight } from './viewer-toolbar' @@ -92,14 +93,27 @@ function sceneGraphSignature(graph: SceneGraphWithCollections): string { }) } +/** + * `?disable=postFx` is read at post-processing module load, so it only takes + * effect on a full page load. Reading it here as well lets the flag survive a + * client-side navigation, since `disablePostFx` is a live prop. + */ +function isLightPreviewQuery(searchParams: URLSearchParams): boolean { + const disable = searchParams.get('disable') ?? '' + return disable.split(',').some((p) => p.trim() === 'postFx') +} + export function SceneLoader({ initialScene, meta }: SceneLoaderProps) { const router = useRouter() + const searchParams = useSearchParams() const versionRef = useRef(meta.version) const lastRemoteGraphJsonRef = useRef(null) const suppressRemoteSaveUntilRef = useRef(0) const [conflict, setConflict] = useState(false) const [saveError, setSaveError] = useState(null) + const lightPreview = isLightPreviewQuery(searchParams) + const handleLoad = useCallback(async () => initialScene, [initialScene]) const handleSave = useCallback( @@ -224,6 +238,20 @@ export function SceneLoader({ initialScene, meta }: SceneLoaderProps) {
)}
+
` (hosted route). This open-source + // app serves saved scenes at `/scene/` — redirect so links and bookmarks work. + async redirects() { + return [ + { + source: '/editor/:id', + destination: '/scene/:id', + permanent: false, + }, + ] + }, transpilePackages: [ 'three', '@pascal-app/viewer', diff --git a/packages/editor/src/components/editor/index.tsx b/packages/editor/src/components/editor/index.tsx index 8d6e56c815..90130ecdf8 100644 --- a/packages/editor/src/components/editor/index.tsx +++ b/packages/editor/src/components/editor/index.tsx @@ -190,6 +190,13 @@ export interface EditorProps { // Thumbnail onThumbnailCapture?: (blob: Blob, cameraData: SnapshotCameraData) => void + /** + * When true, skip the viewer post-FX pipeline (same as `?disable=postFx`). + * Hosts use this for a stable local "light preview" without relying only on + * module-load URL flags or shading toggles. + */ + disablePostFx?: boolean + // Version preview overlays (rendered by host app) sidebarOverlay?: ReactNode viewerBanner?: ReactNode @@ -961,6 +968,7 @@ const ViewerCanvas = memo(function ViewerCanvas({ onThumbnailCapture, viewerSceneSlot, floorplanSceneSlot, + disablePostFx = false, }: { isVersionPreviewMode: boolean isLoading: boolean @@ -973,6 +981,7 @@ const ViewerCanvas = memo(function ViewerCanvas({ onThumbnailCapture?: (blob: Blob, cameraData: SnapshotCameraData) => void viewerSceneSlot?: ReactNode floorplanSceneSlot?: ReactNode + disablePostFx?: boolean }) { const viewMode = useEditor((s) => s.viewMode) const floorplanPaneRatio = useEditor((s) => s.floorplanPaneRatio) @@ -1086,6 +1095,7 @@ const ViewerCanvas = memo(function ViewerCanvas({