feat(web): close remaining editor, layout and persistence gaps

- Area headers get a per-area editor switcher backed by a shared
  AreaEditorContext; Preferences can hide it.
- Animation camera area is a real navigable viewport aligned to the
  scene camera; Graph Editor adds channel selection, keyframe drag/
  insert/delete and interpolation.
- Geometry Nodes node locations round-trip through the native writer
  and reader, so saved graphs keep their layout.
- Texture Paint can make linked library images local via a new native
  makeImageLocal command before packing strokes.
- Compositor IMAGE and Render Layers nodes now persist to Main and
  execute against packed images / the last PBR render.
- Spreadsheet row cap raised to 250k; Outliner gains Ctrl+A and arrow/
  Home/End navigation.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
mes123456
2026-11-13 07:47:10 +08:00
parent d11387ef6b
commit d0b6d2a164
31 changed files with 877 additions and 61 deletions

View File

@@ -162,6 +162,7 @@ export type WebEngineEditCommand =
| { type: "setMaterialPrincipled"; materialId: string; baseColor: [number, number, number, number]; roughness: number; metallic: number; emissionColor?: [number, number, number, number]; alpha?: number; ior?: number; specularIORLevel?: number; transmissionWeight?: number; coatWeight?: number; coatRoughness?: number; emissionStrength?: number }
| { type: "importImage"; name: string; mimeType: "image/png" | "image/jpeg"; width: number; height: number; base64: string }
| { type: "packImage"; imageId: string; mimeType: "image/png" | "image/jpeg"; width: number; height: number; base64: string }
| { type: "makeImageLocal"; imageId: string }
| { type: "setMaterialImageNode"; materialId: string; imageId: string; usage: "BASE_COLOR" | "METALLIC" | "ROUGHNESS" | "EMISSION" | "ALPHA" | "NORMAL"; uvMap?: string }
| { type: "insertObjectKeyframe"; objectId: string; frame: number; property: "LOCATION" | "ROTATION_EULER" | "SCALE"; interpolation?: FCurveInterpolation }
| { type: "deleteObjectKeyframe"; objectId: string; frame: number; property?: "LOCATION" | "ROTATION_EULER" | "SCALE" }