Files
editor/packages/viewer/src/lib/asset-url.ts
T
f06f2fa1b1 feat: 2D editing — floorplan panel, measurements, command palette (v0.3.0)
* sync: port 2D editing features from monorepo (v0.3.0)

## New Features

### Floorplan Panel (7.5K LOC)
- Full 2D editing interface with wall drawing, measurement, and unit display
- Interactive floorplan view with pan/zoom, grid snapping
- Wall thickness visualization, door/window placement
- Zone and slab polygon editing
- Guide image overlay support
- Metric/imperial unit toggle

### Command Palette Overhaul
- Complete rewrite with new command registry system
- Keyboard shortcuts UI with ShortcutToken component
- Editor-specific commands (floorplan, measurements, camera focus)
- Improved search and action organization

### Wall Measurements
- Real-time wall length labels in 3D view
- Metric/imperial conversion
- Wall measurement UI component

### Enhanced Tools
- Wall drafting utilities (grid snapping, validation)
- Node action menu for quick operations
- Improved polygon editing for zones/slabs/sites
- Roof segment panel for granular roof control

## Package Changes

### @pascal-app/core@0.3.0
- New wall-footprint.ts: 2D wall footprint calculation
- Wall mitering exports for floorplan view
- camera-controls:focus event
- Space detection undo pause/resume
- Mark sibling nodes dirty on deletion (miter recalc)

### @pascal-app/viewer@0.3.0
- ErrorBoundary component for robust item rendering
- Broken item fallback UI
- Wall renderer: mark dirty on mount
- Ground occluder: only lowest level punches through
- Unit state (metric/imperial) in viewer store

### @pascal-app/editor@0.1.0
- 48 file changes (16 new, 32 modified)
- New stores: useCommandRegistry, usePaletteViewRegistry
- Tree node drag-and-drop system
- Level selection utilities
- Enhanced scene graph operations

## Apps/Editor
- GeistPixelSquare font for pixel-perfect UI
- Blueprint icon asset
- Updated layout and globals for font support

## Security
- Zero AI imports or internal package refs
- All monorepo-specific code excluded
- Clean audit: no API keys or secrets

## Testing
- Security audit passed 
- All AI/internal code excluded 
- Version bumps applied 

79 files modified, 16 files added
~2600 insertions, ~1400 deletions

* fix: lint cleanup — suppress intentional dep warnings, fix missing dep, remove stale ignores

- Add biome-ignore for 3 intentional useEffect reset patterns (levelId, selectedGuide, selectedId)
- Fix actual missing dependency: currentBuildingId in handleSiteEditShortcutSelect callback
- Remove 3 stale biome-ignore comments in r3f.d.ts (rule not active)

Build and lint pass clean.

* fix: type errors — polygon area guards, selection cast, readonly keywords, door guard

- ceiling-panel, slab-panel, ceiling-tree-node, slab-tree-node, zone-tree-node:
  guard polygon[i]/polygon[j] array access before arithmetic (TS2532)
- scene.ts: introduce toViewerSelection() helper to cast persisted string IDs
  to branded template literal types expected by useViewer.setSelection (TS2345)
- door-panel: guard early return when node is undefined in setSegmentHeightRatio (TS18048)
- editor-commands: remove 'as const' from inline command object, keywords is mutable string[] (TS2322)

All type checks pass. Build and lint clean.

---------

Co-authored-by: Anton Pascal <anton-pascal@users.noreply.github.com>
2026-03-24 19:48:11 +00:00

52 lines
1.7 KiB
TypeScript

import { loadAssetUrl } from '@pascal-app/core'
export const ASSETS_CDN_URL = process.env.NEXT_PUBLIC_ASSETS_CDN_URL || 'https://editor.pascal.app'
/**
* Resolves an asset URL to the appropriate format:
* - If URL starts with http:// or https://, return as-is (external URL)
* - If URL starts with asset://, resolve from IndexedDB storage
* - If URL starts with /, prepend CDN URL (absolute path)
* - Otherwise, prepend CDN URL (relative path)
*/
export async function resolveAssetUrl(url: string | undefined | null): Promise<string | null> {
if (!url) return null
// External URL - use as-is
if (url.startsWith('http://') || url.startsWith('https://')) {
return url
}
// IndexedDB asset - resolve from storage
if (url.startsWith('asset://')) {
return loadAssetUrl(url)
}
// Absolute or relative path - prepend CDN URL
const normalizedPath = url.startsWith('/') ? url : `/${url}`
return `${ASSETS_CDN_URL}${normalizedPath}`
}
/**
* Synchronous version for URLs that don't need IndexedDB resolution
* Only use this if you're sure the URL is not an asset:// URL
*/
export function resolveCdnUrl(url: string | undefined | null): string | null {
if (!url) return null
// External URL - use as-is
if (url.startsWith('http://') || url.startsWith('https://')) {
return url
}
// Don't use this for asset:// URLs - use resolveAssetUrl instead
if (url.startsWith('asset://')) {
console.warn('Use resolveAssetUrl() for asset:// URLs, not resolveCdnUrl()')
return null
}
// Absolute or relative path - prepend CDN URL
const normalizedPath = url.startsWith('/') ? url : `/${url}`
return `${ASSETS_CDN_URL}${normalizedPath}`
}