37 Commits

Author SHA1 Message Date
Wassim SAMAD
5c071ecad5
feat(plugins): plugin contract + first-party Nature pack (trees/flowers/grass) (#457)
* feat(plugins): trees tracer-bullet plugin + minimal host panel surface

Ship one real first-party plugin and only the host surface it forces
into existence, proving the plugin contribution paths every future
plugin (mint.gg generator, Home Assistant, environments, room volume)
will reuse.

Host surface (core + editor):
- core: Plugin.panels + observable panelRegistry; loadPlugin routes
  panels (namespaced by plugin id, dup-throws like nodes).
- editor: AppSidebar merges panelRegistry into the icon rail via
  useSyncExternalStore; each plugin panel lazy-loaded behind an error
  boundary; host extraPanels keep precedence.
- editor: widen Tool to `KnownTool | (string & {})` so plugin tool ids
  (e.g. 'trees:tree') typecheck; dispatch already registry-first.

Trees plugin (packages/plugin-trees), structurally a third-party pack
(peer-deps on @pascal-app/*):
- trees:tree node — procedural low-poly geometry (oak/pine/birch/palm),
  free parametric inspector (preset/height/seed + Randomize), placement
  tool + ghost preview built from public primitives only.
- presets rail panel — panel -> plugin store -> def.tool -> SceneApi ->
  scene -> reactive read-back ("N planted").

Loading + docs:
- apps/editor: setPluginDiscovery([treesPlugin]) in bootstrap;
  transpilePackages + dep.
- wiki/architecture/plugin-authoring.md: panels field, error-boundary
  contract, styling, tool-from-panel note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(plugins): merge plugin panels into the v2 sidebar layout too

The community shell renders <Editor layoutVersion="v2" sidebarTabs={...}>,
a separate rail from AppSidebar. Merge registry panels into the v2
tabMap + tab bar (and thus mobile) so plugin panels show up there as
well, not only in the v1 AppSidebar.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(plugin-trees): ez-tree geometry + instanced rendering + snapping

Replace the placeholder low-poly geometry with dgreenheck/ez-tree
(self-contained — bark/leaf textures inlined as base64, no assets to
host) and render the forest with true GPU instancing.

Rendering:
- def.system (system.tsx): one collective renderer that groups every
  trees:tree node by (preset, seed) variant and draws each variant as
  one InstancedMesh per ez-tree sub-mesh, composing the parent level's
  world matrix into per-instance matrices. ~1 draw call per variant.
- def.renderer (proxy-renderer.tsx): an invisible, raycastable per-node
  proxy so the host's existing selection / outline / zone machinery
  keeps working — no instanceId bookkeeping. (Outline highlights the
  proxy bbox; documented.)
- geometry per variant generated once by ez-tree and cached; seeds drawn
  from a bounded pool so trees actually share variants.

Presets remapped to ez-tree built-ins (oak/pine/aspen/ash/bush).

Placement now respects the active snap mode — isGridSnapActive() +
gridSnapStep + snapPointToGrid, like the built-in item/shelf tools.

transpilePackages += @dgreenheck/ez-tree in the editor app.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(plugin-trees): true-silhouette hover/select + richer presets panel

Selection/hover now outlines the real tree shape, not the bbox. The
proxy splits into an outer group (stable invisible box collider +
pointer handlers, the raycast target) and an inner registered group that
mounts the real ez-tree geometry (invisible, non-raycasting) only while
the node is hovered or selected. The host outline pass reads the
registered inner group, so it traces the true silhouette; picking stays
on the steady box. Geometry for the highlight reuses the cached variant.

Panel: redesigned cards with gradient swatches + selected state, a
"planted" count chip, and a height slider that seeds the next tree's
height (a per-instance scale — never touches placed trees or instancing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(plugin-trees): curated tree params + procedural flowers (sibling kind)

Tree params: expose foliageDensity, trunkThickness, and a leafless toggle
in the inspector and the panel brush. Each is folded into the instancing
variant key and mapped onto ez-tree options (radius scale, leaf count),
so editing one tree only re-buckets that tree — instancing degrades
gracefully, never worse than per-node.

Flowers: add a `trees:flower` sibling kind — simple procedural geometry
(stem + petals + center, merged per material), presets daisy / tulip /
lavender, instanced + selectable exactly like trees.

Refactor: extract the instanced renderer + selection proxy into a generic
`instanced.tsx` (InstancedKindSystem + KindProxy) and the snap/level/grid
placement wiring into `placement.tsx` (usePlacement). Trees and flowers
are now thin bindings — the template for future plant kinds.

Panel: a Trees / Flowers toggle, gradient preset cards, per-kind planted
count, and brush sliders.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(plugin-trees): native inspector controls in panel + preset thumbnails + ez-tree credit

- swap the panel's custom slider/checkbox/toggle for the host's exported
  SliderControl/ToggleControl/SegmentedControl so the brush matches the
  right-hand inspector pixel-for-pixel
- replaceable preset thumbnails (inline SVG data URIs, no asset hosting) render
  as <img> cards instead of gradient swatches
- credit footer linking @dgreenheck/ez-tree (Daniel Greenheck, MIT)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(plugin-trees): all ez-tree presets + type + leaf/branch colours, flower petal colour, grass kind

- tree presets now cover all of ez-tree's built-ins via species × size
  (Small/Medium/Large + Bush 1/2/3 + Trellis), plus a Deciduous/Evergreen type
- edit-only leaf & branch colour tints (leaves.tint / bark.tint), all folded
  into the instancing variant key
- flowers gain a per-flower petal colour (baked from preset at placement)
- new trees:grass instanced kind — procedural blade tufts (meadow/fescue/reed)
  with a per-tuft blade colour, reusing the generic instanced + placement core
- panel: Trees/Flowers/Grass segmented switch, size + type controls, native
  host controls throughout; credit links Daniel Greenheck's X

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(plugin-trees): tolerate nodes persisted before new fields existed

treeSpecOf/flowerPetalColor now default every geometry field, and hexToInt
guards undefined — trees/flowers placed before size/type/colour fields were
added load with neutral defaults instead of crashing the instanced renderer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(plugin-trees): shared always-on wind + pin credits to panel bottom

- wind.ts injects a sway into each material's begin_vertex driven by one shared
  uTime uniform (advanced per frame in the instanced system); USE_INSTANCING
  guards keep the same material valid for the non-instanced placement ghost.
  Applied to tree, flower, and grass materials — a whole scene sways like ez-tree.
- credits footer is now sticky to the bottom of the panel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(plugin-trees): rename rail panel Trees -> Nature (covers trees/flowers/grass)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(plugin-trees): rename panel header Plant -> Nature to match the rail

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: bake-exportable instanced plants + renderer-agnostic wind

Bake (GLB export): add a transient useViewer.isExporting flag. BakeExporter
flips it, waits for the commit, then exports. KindProxy watches it and, during
export, emits each plant's REAL visible geometry under scene-renderer (which the
exporter clones) instead of the invisible collider — so instanced kinds
(def.system) that live outside that subtree are captured. The collider box is
dropped during export so it doesn't bake as a phantom solid.

Wind: the previous onBeforeCompile wind was a no-op under the editor's WebGPU
renderer (WebGL-only hook). Replace it with a renderer-agnostic per-instance
base-pivot tilt animated in useFrame (which FrameLimiter drives continuously).
Reads as wind under any renderer; removes the dead wind.ts + applyWind calls.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(plugin-trees): TSL vertex-bend wind (WebGPU), replacing CPU tilt

wind-node.ts adds a TSL positionNode that bends each plant proportional to
height above its base, phased per-instance (instanceIndex) and per-vertex, so
tips sway and roots stay planted — animated on the GPU via the renderer's time
node. ez-tree is untouched: its materials are copied into MeshStandardNodeMaterial
(toWindMaterial); flowers/grass build node materials directly (windStandardMaterial).
Instance matrices go back to static.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(plugin-trees): tree materials render black under wind (Phong not Standard)

ez-tree's bark/leaves are MeshPhongMaterial; copying them into a
MeshStandardNodeMaterial swapped the shading model (specular/shininess ->
roughness/metalness) and rendered black. Convert into the matching node
material type (Phong->Phong, Lambert->Lambert, else Standard) so map/color/
alphaTest/side are preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(plugin-trees): trees still black — build node material from map/color explicitly

Material.copy() doesn't transfer a classic material's map/color onto a node
material, so textured trees rendered black (flowers/grass were fine — they carry
no map). Re-create the ez-tree materials as MeshStandardNodeMaterial with map,
alphaMap, color, side, alphaTest passed explicitly in the constructor — the same
proven path the flower/grass materials use.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(plugin-trees): tree wind — per-leaf flutter (ez-tree style), static trunk

The whole-tree height-based bend was a rigid rotation about the base ('rotating
in place'). Replicate ez-tree's actual approach: scale sway by the leaf card's
uv.y and apply it ONLY to the 'leaves' material (multi-frequency wave, phased per
instance + per leaf) so leaves flutter from their attachment while bark/branches
stay static. Flowers/grass keep the gentle whole-plant stem bend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(plugins): Plugin.onSceneLoad hook + viewer application; trees wind via it

Adds a broad, plugin-declared post-load scene hook so effects survive GLB export:
- core: Plugin.onSceneLoad (lazy, three-free) + observable sceneHookRegistry + loadPlugin routing.
- viewer: applyPluginSceneHooks util; PluginSceneHooksSystem re-runs it on the live
  scene as nodes change; GlbScene runs it on each loaded baked GLB.
- plugin-trees: declare onSceneLoad; wind is no longer welded into the materials —
  the hook re-attaches LEAF_FLUTTER/STEM_BEND by material name (leaves / flower-* /
  grass-*), so it now animates in the baked /viewer too, not just live.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(plugin-trees): scale-invariant leaf wind (÷ modelScale) so baked GLB matches editor

The bake's quantiser renormalises each plant mesh to [-1,1] and moves real size
into a large node scale (~3 on trees). LEAF_FLUTTER added a constant local offset,
so in the baked GLB it was multiplied by that scale → ~3x over-swing. Divide the
sway by modelScale.x to keep a constant world-space amplitude; editor (scale 1)
is unchanged, baked now matches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* revert: onSceneLoad wind approach → back to wind-in-materials

Reverts the Plugin.onSceneLoad hook + viewer application + modelScale compensation
(commits 893ca839, 6c9ee003). Superseded by the bake-policy 'replace' model
(plans/editor-plugin-trees-example.md Part D): trees render live in the viewer via
their own path, so wind is a plain positionNode on the material again — no hook,
no baked-geometry decoration, no coordinate-space fights.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(bake): per-kind bake policy (static/strip/replace)

Adds NodeDefinition.bake ('static' default | 'strip' | 'replace') + registry
helpers bakePolicyOf/kindsWithBakePolicy in core. Generalises the previously
hardcoded scan/guide handling:
- glb-export strips kinds with bake==='strip' from the artifact (was a
  scan/guide type check); 'replace' kinds stay baked (portable static snapshot).
- glb-reference-nodes selects rebuild candidates by policy instead of type.
- scan/guide declare bake:'strip'; trees/flower/grass declare bake:'replace'.

Viewer-side 'replace' swap (strip baked meshes + live-rebuild) is the next slice.
Part of plans/editor-plugin-trees-example.md Part D.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(bake): viewer 'replace' swap — hide baked meshes, re-render live

Adds NodeDefinition.bakeReplaceRenderer (falls back to renderer). The baked
/viewer now, for kinds with bake:'replace' and a loaded plugin:
- hides the static baked meshes (bakePolicyOf(kind)==='replace') in GlbScene's
  identity pass — capability-gated, so with no plugin the meshes stay;
- re-renders each node live via buildGlbReplaceNodes + the shared portal-into-
  baked-level path (GlbReferenceNode now prefers bakeReplaceRenderer), so trees
  ride level stacking automatically and wind runs in real coordinate space.

plugin-trees ships a hookless KindStatic (real geometry + wind materials, no
collider/selection) and per-kind static-renderer binds; tree/flower/grass point
bakeReplaceRenderer at them. Completes plans/editor-plugin-trees-example.md Part D.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* perf(viewer): memoize GlbReferenceNode(s) — skip forest re-render on camera move

GlbScene re-renders per frame during camera movement (hover raycast / walkthrough
HUD). The rebuilt nodes reconciled every frame — fine for 1-2 scans/guides, but a
bake:'replace' forest puts dozens of nodes here (profiler: KindStatic x56 6ms,
GlbReferenceNode x57 4ms per frame). memo at the node boundary skips the whole
subtree (incl. the plugin renderer) when (node, anchor) are unchanged; both props
are stable refs, so it short-circuits cleanly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* perf(plugin-trees): NO_RAYCAST on KindStatic meshes — cheap hover over a forest

The baked scene's <primitive> has pointer handlers, so R3F recursively raycasts
every descendant on each pointer move (incl. orbit drags). The live replace trees
had fully-raycastable dense ez-tree geometry, so hover cost ~400ms/frame over a
forest (profiler: 'JavaScript' 413ms during camera move). They carry no pascalId
(a hit resolves to the level, not the tree), so they're scenery, not pick targets
— mirror KindProxy, which already NO_RAYCASTs its real geometry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* refactor(bake): viewer 'replace' renders instanced per level (was per-node)

Replaces the per-node KindStatic viewer path with a collective instanced one,
mirroring the editor's system instead of diverging from it:

- extract InstancedNodes from InstancedKindSystem (shared by both) with a
  localSpace flag: editor folds parent world matrix (root instances); viewer uses
  level-local matrices + NO_RAYCAST, portaled into the baked level.
- bakeReplaceRenderer is now a collective renderer (BakeReplaceRenderer<N>,
  receives {nodes}); GlbReplaceInstances groups replace nodes by (level, kind) and
  portals each kind's instanced renderer into that baked level. GlbReferenceNode
  reverts to per-node renderer (strip kinds only).

Fixes: forest hover cost (100+ tree meshes → a few instanced draws, R3F walks far
fewer objects) and per-tree wind phase (instanceIndex varies again; per-node
KindStatic gave every tree phase 0 → unison sway). Trees still ride level stacking
(portaled) and stay static in a plain glTF viewer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* perf(viewer): BVH the baked scene — accelerate hover/pick raycasts

The baked /viewer runs with useBvh={false}, so GlbScene's hover/pick raycasts
against the baked building were brute-force triangle intersection (profiler:
_computeIntersections + intersectTriangle ~30%). The parametric viewer wraps its
scene in <SceneBvh>; the baked one never did. SceneBvh's effect is one-shot on
mount and can't catch the async-loaded GLB, so compute a per-mesh BVH inside
GlbScene keyed on gltf.scene instead. 'replace' instances are NO_RAYCAST, so the
raycast===Mesh.prototype.raycast guard skips them (mirrors SceneBvh).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(plugin-trees): inherit ez-tree preset by default (seed/type/tints)

Our node defaults (seed:1, treeType:deciduous, colors:#ffffff) were applied as
*overrides* on top of loadPreset, discarding each preset's tuned seed, growth
model, and tints — so our trees looked nothing like eztree.dev (pine grew
deciduous, foliage washed white, every silhouette off).

Mirror the flower petalColor pattern: seed/treeType/leafColor/branchColor are now
optional; generateTree only overrides an ez-tree option when the node set it,
otherwise loadPreset's value stands. Placement stores none of them (fresh tree =
pure preset; all same-preset trees share one instancing variant); the deciduous/
evergreen brush toggle is gone (growth model comes from the preset). The inspector
keeps them as per-tree overrides, and Randomize still varies the seed.

Verified against ez-tree: fresh Oak Medium → seed 35729 + preset tints; Pine
Medium → evergreen + seed 13977; overrides apply when set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(plugin-trees): bundle real preset artwork (webp, in-package)

Replaces the placeholder SVG thumbnails + lucide panel icon with the real nature
art. 13 webp (~126KB total, 256px cards / 128px icon) live in src/assets and are
imported via art.ts — both consumers are Next, so transpilePackages runs them
through the image pipeline (hashed, cached /_next/static/media URLs). No CDN, no
per-app public/ mirroring; the assets travel with the package.

- art.ts: central webp imports → TREE_ART / FLOWER_ART / GRASS_ART / NATURE_ICON
- presets/flower-presets/grass-presets: thumbnail ← bundled art (was *Thumbnail())
- index.ts: Nature panel icon ← NATURE_ICON (was lucide:leaf)
- assets.d.ts: ambient *.webp decl (no next type dep)
- remove thumbnails.ts (placeholder generators, now dead)

Verified on the running dev server: webp emitted + served (HTTP 200, image/webp).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(plugin-trees): square preset cards on light-gray flattened thumbnails

Regenerate the 12 thumbnails with the transparency flattened onto gray-100
(#f3f4f6) and render the card square (aspect-square, was h-16 crop). The
nature-icon keeps its transparency for the icon rail.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(plugin-trees): correct move-drag + outline behavior for instanced plants

Two selection defects, one root cause each:

1. Outline moved mirror-wise during a move drag. The host move tool drives the
   registered Object3D imperatively with absolute level-local positions (and
   mirrors them via useLiveTransforms) — the contract ParametricNodeRenderer
   satisfies by putting position + registration on the same group. KindProxy
   registered a child nested inside the transform-carrying group, so drag
   positions landed in the node's rotated frame (placement gives every plant a
   random Y rotation → deltas rotated up to 180°). Restructure: the registered
   group now carries position/rotation (live-transform aware); the box collider
   is a positioned sibling, staying out of the outline mask.

2. Outline froze while the mesh swayed. The outline mask pass renders with a
   shared override material, so it can never follow the material positionNode
   wind. Instead, while hovered/selected the collective system skips the node
   and the proxy mounts the real geometry with static twins of the wind
   materials (toStaticMaterial — explicit property transfer; node-material
   clone() drops map/color). Outlined mesh == visible mesh, both still.

Bonus from the same restructure: a move drag now animates the actual plant in
realtime (the proxy is what the tool drives), not just the drag box.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(plugin-trees): 2D plan symbols + trunk-sized footprint

- def.floorplan for the three kinds — the registry floor-plan layer renders any
  kind that provides one, so this is all plugin nodes need to appear in 2D.
  Tree: dashed canopy ring (dashed = overhead element) in the preset swatch +
  solid trunk dot; ring is pointer-events:stroke so the large disc doesn't
  steal clicks from what's under the canopy. Flower/grass: small colour dots.
  Selected → palette stroke + move-handle; hovered → hover stroke.
- Tree floorPlaced.footprint is trunk-sized (treeTrunkRadius) instead of
  canopy-sized, so the move/placement drag box hugs where the tree actually
  plants instead of spanning the crown. The invisible hover collider keeps its
  larger radius — only the displayed box shrinks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(plugin-trees): trunk-sized drag box, 45°-aligned rotation, rotate gizmo

- The move drag box ignored floorPlaced.footprint: with collides:false the tool
  auto-measures the rendered mesh — which, since the selection swap-out, is the
  whole canopy. Declare capabilities.dragBounds (trunk-sized, node-local) so the
  box hugs the trunk and rotates with the node instead of wrapping the crown as
  a world AABB.
- Placement wrote a fully random Y rotation, so the box/gizmo never sat on a 45°
  step. Snap the random rotation to 45° increments (variety preserved, alignment
  restored) and widen rotatable.snapAngles to 8×45° on all three kinds.
- Add the standard rotate gizmo (def.handles, shelf-style arc handle): ring
  around the trunk near the ground — not the canopy, which would put the handle
  meters out on a large oak.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(plugin-trees): live rotate preview + ground-level rotate ring

- KindProxy now folds useLiveNodeOverrides into its transform (mirrors
  ParametricNodeRenderer) — the rotate/resize gizmos publish mid-drag patches
  there, so the plant turns in realtime instead of snapping on commit. The
  snap-on-commit (with the arc delta wrapping to ±180°) is also what made long
  drags land 'the wrong way'; with live feedback the direction reads correctly
  and matches the item gizmo pipeline exactly.
- Rotate ring drops from mid-trunk to 0.25m — a floor affordance like the item
  gizmo, not a waist-height hoop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(registry): panelForKind — 'find in catalog' opens a plugin kind's panel

loadPlugin now associates every node kind with its plugin's first (namespaced)
panel id; panelRegistry.panelForKind(kind) exposes it. A host's find-node
handler can open the right panel for any plugin kind with zero per-plugin
knowledge.

plugin-trees uses it end-to-end: a module-level selection:find-node listener
(find-sync.ts, imported by the manifest so it's live from plugin load) points
the panel store at the found node's section + preset — panel section state
moved from panel-local useState into the store to make it addressable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(registry): plugin panels declare their workspaces (default edit-only)

Plugin panels rode into the studio rail: the host swaps its own sidebar tabs by
workspaceMode, but usePluginPanels appended registry panels unconditionally.

PluginPanel gains workspaces?: readonly ('edit'|'studio')[] — manifest metadata,
default ['edit'] (an authoring panel has no business in the clean render
workspace; a plugin shipping studio tooling opts in explicitly). usePluginPanels
filters by the current workspaceMode, covering both the v1 AppSidebar and v2 tab
bar paths. Nature declares nothing and disappears from studio via the default;
the v2 layout's existing active-tab fallback handles a panel vanishing mid-use.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: link plugin-authoring guide from README + CONTRIBUTING, fix stale wiki path

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(plugin-trees): keep ez-tree off the eager SSR path

ez-tree loads its inlined textures at module scope (needs document), so any
eager import chain reaching geometry.ts crashed Next prerender
(ReferenceError: document is not defined on /_not-found). Move the pure
helpers (mulberry32, naturalHeight) to variant-utils.ts so the
flower/grass builders and floorplan no longer pull ez-tree, and drop the
generateTree re-export from the package barrel (no external consumers).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 13:45:20 -04:00
Aymeric Rabot
1b4c656901 chore(ts7): adopt the TypeScript 7 native compiler (tsgo)
Make the editor packages compatible with, and benefit from, the native Go
compiler (TypeScript 7 / tsgo) while keeping the npm publish path on stable tsc.

- Add @typescript/native-preview (pinned 7.0.0-dev.20260624.1). tsgo coexists
  with typescript@6, which Next typegen and the IDE plugin still need until the
  TS 7.1 programmatic API ships.
- Fix two react-three-fiber JSX augmentations the native checker rejects but
  tsc tolerated:
  - viewer: map only LineBasicNodeMaterial (the one webgpu node material used as
    a JSX tag) instead of the whole three/webgpu namespace (TS2320/TS2590).
  - plane-box-select-tool: drop the redundant `IntrinsicElements extends
    ThreeElements` block — it duplicated R3F's global augmentation and, by
    referencing @react-three/fiber's ThreeElements directly, hit a bun peer-dep
    variant-directory duplicate under tsgo (TS2320). r3f.d.ts already covers
    those JSX intrinsics. Types-only — no runtime change.
- check-types -> tsgo --noEmit (editor, @repo/ui, editor app, ifc-converter app)
- emit-package dev watch -> tsgo --build --watch
- build/publish stay tsc --build (prepublishOnly + release.yml unchanged;
  emitted .d.ts is byte-identical to tsc output)
- bump next 16.2.6 -> 16.2.9

tsc remains the source of truth and fallback. Published artifacts unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 13:37:58 -04:00
Aymeric Rabot
c57901e7d9 chore(deps): review-pass fixes — pin next 16.2.6, drop dead dep, dedupe three
- next 16.2.7 -> 16.2.6 in both apps. 16.2.7 regresses Turbopack dev route
  matching for API routes nested below a dynamic segment (probed in the
  private repo: /api/items/[id]/fork, /api/scenes/[id]/events 404 with the
  router's HTML not-found; production builds unaffected; bisected
  16.2.6 good / 16.2.7 bad). 16.2.6 carries all the 16.2.5/16.2.6
  security fixes — only the bugfix backports are forgone.
- Remove @react-three/uikit-lucide from @pascal-app/editor dependencies:
  zero imports in this repo or private-editor; dead weight in every npm
  consumer's install.
- Pin @visual-json/react "latest" -> "^0.4.0" (current resolution;
  "latest" in a published package's deps is unreproducible and was
  inconsistent with private-editor's ^0.4.0).
- Add root override three: 0.184.0, mirroring private-editor's dedupe —
  drops the nested stats-gl three@0.170.0 so the lockfile resolves a
  single three (the stated single-instance invariant now holds here too).

Verified: build, check-types, biome check, 931 package tests green;
lockfile resolves one next (16.2.6) and one three (0.184.0);
oxide/lightningcss optionalDependency pins still match resolutions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 16:28:02 -04:00
Aymeric Rabot
9d24e260c3 chore(deps): June 2026 dependency refresh
Range edits:
- next 16.2.1 -> 16.2.7 in apps/editor + apps/ifc-converter. 16.2.5/16.2.6
  fixed six high-severity advisories (middleware bypass, DoS, SSRF, XSS,
  RSC cache poisoning); 16.2.7 is bugfix backports. No API/config changes.
- typescript 6.0.2 -> 6.0.3 everywhere, including aligning the 5.9.3
  stragglers (@pascal-app/mcp, @repo/ui, @repo/eslint-config) that date
  from the original scaffold and were never intentionally held back.
- @types/node in @pascal-app/mcp: ^25.5.0 -> ^22.19.20 — mcp was the only
  workspace typed against non-LTS node 25; 22 matches the release
  workflow's node and every other workspace.
- @number-flow/react ^0.5.14 -> ^0.6.0 (packages/editor, apps/editor);
  the only breaking change (removed --number-flow-char-height CSS var)
  is unused here.
- agentation ^2.3.2 -> ^3.0.2 (apps/editor devtool; v3 is a drop-in for
  the props-less <Agentation /> usage, additions are opt-in).
- Root overrides: @types/react 19.2.14 -> 19.2.17,
  @types/three 0.184.0 -> 0.184.1 (types-only fixes).

Lockfile refresh within existing ranges picks up react 19.2.7 (pairs with
next 16.2.7 — 19.2.6 had a server-action FormData regression), motion
12.40.0, three-mesh-bvh 0.9.10, @react-three/uikit-lucide 1.0.73, the
June radix wave, lucide-react 1.17.0, zustand 5.0.14, tailwind-merge
3.6.0, geist 1.7.2 (fixes Geist Mono ligature regression), react-grab
0.1.44, biome 2.4.16 + ultracite 7.8.2, turbo 2.9.17.

Held: three stays 0.184.0 (npm latest; single-instance constraint),
tailwindcss 4.3.0 + lightningcss 1.32.0 already match the pinned
optionalDependencies native binaries, eslint 10 major not taken
(@repo/ui is unconsumed legacy scaffold).

Verified: turbo build, check-types, biome check, and 931 package tests
green; bun.lock stays lockfileVersion 1 (CI bun 1.3.0 compatible);
single next/three resolution confirmed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 14:48:40 -04:00
Wassim SAMAD
4d5226ce10 Wire loadPlugin(builtinPlugin) at editor app bootstrap
Adds apps/editor/lib/bootstrap.ts that calls loadPlugin(builtinPlugin)
as a module-side-effect on first import. Imported from scene-loader.tsx
so it runs on the client side where the editor mounts.

Idempotency guard handles HMR re-execution (would otherwise throw on
duplicate registerNode). For the empty plugin this commit, the entire
call is a no-op — included now so future commits that add real node
kinds only need to push them onto builtinPlugin.nodes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 11:28:01 -04:00
sudhir
2fc754108d Use community viewer toolbars in editor app 2026-05-12 09:49:10 +05:30
Wawa
e618175bba Reset core/viewer/editor/mcp packages and apps/editor from private-editor
Wholesale swap of packages/{core,viewer,editor,mcp} and apps/editor with the
versions from the private editor repo, which is the production source of truth.

Setup changes:
- packages/{core,viewer,editor} versions held at 0.7.0 baseline (matching
  the most recent published release) so a bump=minor publishes 0.8.0
- packages/mcp held at 0.1.1 (never published; first publish will go through
  the new release.yml flow)
- peerDependencies and devDependencies for inter-package @pascal-app/*
  references pinned to ^0.7.0 instead of '*' / 'workspace:*' so they are
  valid for npm consumers
- Root package.json: TypeScript bumped to 6.0.2, added overrides for
  @types/react, @types/react-dom, @types/three to prevent JSX namespace
  fragmentation across the workspace
- release.yml extended to also publish editor and mcp; 'both' option renamed
  to 'all'; added a sync step that updates inter-package peerDeps/devDeps to
  match the new versions on every bump (so viewer/editor/mcp tarballs always
  reference the version of core they were built against)
- Root scripts gained release:editor and release:mcp shortcuts

Verification:
- bun install --frozen-lockfile is consistent
- packages/{core,viewer,mcp} build cleanly, dist/index.d.ts emitted
- packages/editor check-types reports 21 pre-existing errors, identical to
  what private-editor currently reports

Open PRs against editor-v2 will need rebasing/conflict resolution.
2026-05-09 20:52:26 +00:00
Adrian Perez
e8d0b13ff5 feat(mcp,editor): Option A+B storage + 10 agent deliverables (Phase 7)
Ships the combined filesystem/Supabase storage adapter + MCP scene
lifecycle tools + Next.js API routes + editor /scene/[id] route, so
an MCP save is directly openable at /scene/<id> without any
injection hack. End-to-end verified: 10/10 e2e steps pass.

Storage (A1/A2/A3):
- SceneStore interface + error classes + slug helpers
- FilesystemSceneStore at $PASCAL_DATA_DIR (defaults XDG/~/.pascal)
  with atomic writes, .index sidecar, optimistic locking
- SupabaseSceneStore with scenes + scene_revisions tables, RLS
  migration SQL, mock-backed unit tests
- createSceneStore(env) auto-selects based on SUPABASE_URL +
  SUPABASE_SERVICE_ROLE_KEY

MCP tools (A4, A8, A9, A10):
- save_scene / load_scene / list_scenes / delete_scene / rename_scene
- list_templates / create_from_template (3 seed templates:
  empty-studio, two-bedroom, garden-house)
- generate_variants (7 mutation kinds, seeded RNG, save=true|false)
- photo_to_scene (vision sampling → scene graph → save)

Editor (A5, A6):
- /api/scenes + /api/scenes/[id] with RFC 7232 If-Match locking
- /scene/[id] and /scenes route pages with save button, SceneLoader
- Removed the window.__pascalScene dev injection hack

Security + UX edges (A7, A8):
- AssetUrl Zod validator: asset:// blob: data:image/ /path https:
  (http://localhost for dev) + PASCAL_ALLOWED_ASSET_ORIGINS env
  allowlist. Hardens scan.url, guide.url, item.asset.src,
  material.texture.url, MaterialMaps.*Map
- Auto-frame camera on empty→non-empty scene transition
  (camera-controls:fit-scene emitter event)

Shared utilities:
- rehydrateSiteChildren() extracted to packages/mcp/src/lib/ and
  used by both create-from-template and generate-variants to work
  around the SiteNode.children-as-objects vs. ids inconsistency
  (CROSS_CUTTING §2)
- Storage + MCP subpath exports added to packages/mcp/package.json
  (CROSS_CUTTING §4)

Tests: 293 pass / 0 fail across 40 files (was 142 pre-Phase-7).
Biome: clean.

Phase-7 e2e script at packages/mcp/test-reports/phase7-e2e.ts:
MCP HTTP + editor Next.js both point at $PASCAL_DATA_DIR =
/tmp/pascal-e2e, save_scene from MCP, GET /api/scenes/<id> from
editor server, /scenes list page renders all saved scenes, scene
page renders SceneLoader, delete_scene works.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:29:28 +02:00
Pascal
5c16aa4225
feat: improve thumbnails, placement, and editor responsiveness (#258)
* wip: backport monorepo PRs 278 280 281 283 284

* refactor(editor): align floorplan panel with monorepo split version
2026-04-17 15:14:40 -04:00
Anton
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
wass08
f2501be2bf remove community 2026-03-13 09:07:46 +01:00
wass08
7359c1fcbf splitting editor and community 2026-03-11 12:16:26 +01:00
wass08
d0f2a1a06f actions command K 2026-03-10 13:35:05 +01:00
Aymeric Rabot
de6bfd8c00 Add react-scan and react-grab dev tools (development only)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-06 18:52:01 -05:00
Aymeric Rabot
48979ec014 fix raycaster layers, polygon drag, slider undo, and grid events
- Enable EDITOR_LAYER on R3F raycaster for proper hit detection
- Fix polygon editor drag using refs and direct position passing
- Handle pointercancel events and fix pointerId access in polygon editor
- Fix slider undo by reverting to start value before resuming temporal state
- Allow grid:move during camera drag so polygon editor works while panning
- Bump better-auth to ^1.5.2 and turbo to ^2.8.12
- Remove explicit return type on createAuth for better inference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:41:19 -05:00
Aymeric Rabot
5ecefbdc06
Feat/ux round 3 (#124)
* Tree: add isLast prop & draw connectors

Introduce an optional isLast prop across all site panel tree node components and TreeNode so children know when they're the last sibling. TreeNodeWrapper now renders vertical and horizontal connector lines (adjusted by depth and isLast) and keeps the toggle button clickable (z-index). Children are passed isLast when mapped, so the UI can stop the vertical line for final siblings. Also bump several deps in apps/editor package.json and update the lockfile accordingly.

* chore: clean up monorepo dependencies and update packages

Move app/library dependencies out of root package.json into their
respective workspaces. Root now only contains monorepo tooling
(turbo, biome, supabase CLI, typescript, portless, ultracite).

Updates:
- next 16.1.0 → 16.1.6
- drizzle-orm ^0.39.0 → ^0.45.1
- drizzle-kit ^0.30.0 → ^0.31.9
- drizzle-zod ^0.5.1 → ^0.8.3
- three-bvh-csg ^0.0.17 → ^0.0.18
- supabase 2.75.3 → 2.76.15
- typescript 5.9.2 → 5.9.3 (all workspaces)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Use semantic theme tokens and enable dark mode

Replace hardcoded zinc color classes with semantic design tokens (text-muted-foreground, text-foreground, border, bg-background, bg-border) across the action menu, camera controls, control modes, and view toggles for consistent theming. Update separators and borders to use bg-border/border-border. Add useEffect in the editor root to add/remove the 'dark' class on document.body and apply 'dark text-foreground' to the root container so the UI renders in dark mode; also import useEffect.

* Persistable sidebar width & resizer

Introduce a zustand store to persist sidebar width (key: `sidebar-preferences`) and track dragging state. Default width is 288px (18rem) and is clamped between 288 and 800px. Wire the store into SidebarProvider to drive the CSS variable for width and expose a data-dragging attribute. Add a SidebarResizer component that handles pointer events to resize the sidebar, toggles dragging state, updates cursor/user-select, and disables transitions while dragging. Small class and structure adjustments ensure the resizer is rendered and resizing behaves smoothly.

* Editor: floating action menu, selection/phase tweaks

Add a FloatingActionMenu (move/duplicate/delete) that attaches to selected 3D nodes and integrates with editor/viewer state; includes new cursor SVG and layout wrapper to use the custom cursor. Improve selection and phase behavior: auto-select first building+level on scene load (moved/centralized in project scene hook and editor init), add resolveBuildingId helper, and enhance SelectionManager to auto-switch between structure/furnish based on clicked nodes and to preserve building/level context when changing selection. Update sidebar tree node click handlers to switch phases for structural vs item nodes and stop hiding nodes by phase (keep tree items visible across phases). Add keyboard escape behavior to clear selections while keeping building/level context and reset selected reference. Misc: register unified event listeners for selection, position floating menu over objects using three.js Box3, and various small integration fixes.

* Add SceneLoader, loading states & editor fixes

Add a SceneLoader component and associated CSS loader styles and wire it into Editor, Viewer and page-level flows so a loading UI displays while project/scene data loads. Replace useLayoutEffect in editor page with a client-mounted useEffect guard to avoid hydration issues. Introduce isSceneLoading state and setter in the project store and set/clear it in useProjectScene; include sceneGraph when creating a new project and clear the scene beforehand.

Other changes: type-guard moving/duplicating logic in FloatingActionMenu and remove duplicated id on clones; refactor auto-selection logic for site/building/level and auto-select build/wall for empty levels in editor index and useProjectScene; optimize ZoneSystem to run per-frame (useFrame) and reduce unnecessary updates to visibility/label positions; add animated active background for layer toggle (motion) in site panel; add keyboard shortcuts to jump between levels (Ctrl/Cmd+ArrowUp/Down); simplify community-hub project-created handler to navigate straight to editor. These changes improve UX during load, enforce safer node operations, and optimize runtime rendering.

* Improve selection logic and refine UI components

Multiple editor and viewer updates:

- Selection: enhance selection-manager to support modifier (Meta/Ctrl) multi-select, compute next selection logic, track modifier keys, prevent grid deselect races, and add debug logs. Adapted selection handlers throughout scene/editor components to pass native events and modifier state.

- Sidebar / Site panel: refactor site panel to inline a LevelReferences UI (replacing the removed references dialog). Add upload flow for scan (.glb/.gltf) and guide images, handling file size/type checks, project asset upload/delete calls, and per-level reference lists. Add MultiSelectionBadge for showing/clearing multi-selection and animated expand/collapse for levels. Several tree-node components now use a shared handleTreeSelection helper and propagate click events properly.

- UI polish & icons: change dark theme color tokens for better contrast; increase button sizes and icon sizes across action menus; swap some lucide icons for image assets (rotate, topview, select, build, mesh, floorplan, level, etc.) and add new public icons.

- PascalRadio: replace popover with a framer-motion expandable panel, add outside-click handling, animated transitions, and minor UI tweaks.

- Other: minor viewer hook/selection-manager updates and tweaks to control modes and view toggles to support image icons and consistent sizing.

These changes improve multi-select reliability, user interactions in the sidebar, and overall visual polish with new icons and animations.

* Fix TypeScript build errors in selection-manager and scene-loader

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 22:09:40 -05:00
Aymeric Rabot
48d5091bb3
UX polish: selection behavior, styling, and site panel improvements (#119)
* Remove .env.local guard; add portless dep

Remove the check that blocked a local .env.local in apps/editor's dev script and simplify the dev startup to source the root .env. Add portless@^0.4.2 to the project dependencies in package.json. Lockfile updated accordingly.

* Improve tool cursors, previews, and contextual tools

Revamp editor tool visuals and behaviour: replace mesh cursors with a new CursorSphere Group (adds ground marker, vertical indicator and optional tool icon tooltip), unify preview colors to #818cf8, add ground-level previews and ghost lines for ceiling and roof tools, and update slab/zone/wall visuals to match. Add automatic build-mode switching and contextual highlighting for structure tools via a new useContextualTools hook, and relax action-menu visibility checks so tool rows are shown even when not in build mode. Minor typing/import adjustments and small opacity/placement tweaks across multiple tool components.

* Keep tools active and refine action-menu styles

Stop auto-deactivating tools in RoofTool and ZoneTool by removing setTool(null) (and setMode('select') in roof). Add hasActiveTool checks and small layout padding to FurnishTools and StructureTools, and update button classes to improve visual emphasis: smoother transitions, stronger active rings/scale, and dimming/grayscale of non-active tools when another tool is active. These changes improve UX by keeping the selected tool active and giving clearer visual feedback in the action menu.

* Improve selection behavior and refresh UI styling

SelectionManager: add global enter/leave/double-click handlers to support cross-phase hovering and auto-switching into structure/furnish on double-click; normalize click handling (explicitly coalesce shiftKey). Remove per-strategy enter/leave listeners.

UI panels & controls: unify and modernize styles across many panels (ceiling, door, item, reference, roof, slab, wall, window) and action buttons — rounded-md, neutral borders, subtle shadows, translucent headers and consistent hover/focus states. Update view toggles icons and toggle styling.

NumberInput: integrate @number-flow/react NumberFlow for formatted value display, add visual drag progress indicator and refine input/label interactions and styling.

Sidebar: replace rename-popover with inline-rename-input and update tree nodes to use inline editing. Add slider-demo and tweak slider implementation. Update package.json accordingly.

* Use Barlow font across editor UI

Add the Google Barlow font and expose it as a CSS variable, update theme font variables in globals.css, and apply the new font across the editor UI. Imports: add Barlow in app/layout.tsx and include its variable on <html>, set body to use font-sans. Apply font-barlow or font-mono classes to headings, labels, numeric readouts and buttons across multiple panels and primitives to standardize typography. Also update button base variant to include font-barlow. Remove the PhaseSwitcher component and its import/usage from the action menu.

* Replace button wrapper with div in LevelItem

Replace the outer <button> around the LevelItem content with a <div> to avoid nesting interactive button elements (and the resulting invalid HTML/interaction issues). Preserves the original classes and onClick/onDoubleClick handlers so behavior remains the same and allows the PopoverTrigger/button children to function correctly.

* Refine site panel list styles and spacing

Update the SitePanel and TreeNode UI to use compact, border-bottom list rows instead of rounded, card-like items. Simplified active/hover states to use bg-accent variants and reduced shadow/ring styles for a cleaner look. Adjusted paddings (pl/px/py) and container layouts (many sections switched to flex-col) and increased tree node indent/paddingRight for consistent alignment. These changes unify spacing and visual hierarchy across levels, buildings, zones and tree nodes.

* Add auto-scroll to selected items and refine icon styles

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:05:02 -05:00
Aymeric Rabot
db05c86120
Add scene graph viewer and persist migration (#115)
Render an interactive Scene Graph in the Settings panel using @visual-json/react. Introduces SceneNode/SceneGraphNode types and buildSceneGraphValue to build a tree (handles missing nodes and cycles), and adds handlers to block drag/drop/context/delete mutations inside the viewer. Adds @visual-json/react to apps/editor package.json and updates the dev script to forbid .env.local and source the root .env instead. Also adds a persistence migration in use-scene to preserve existing nodes and rootNodeIds when the persist version changes.
2026-02-24 00:40:18 -05:00
wass08
373d9310ee fix build 2026-02-23 07:41:17 +09:00
wass08
66b4efba09 fix build 2026-02-20 19:45:15 +09:00
wass08
4572c36da5 threejs version upgrade #91 2026-02-20 16:17:56 +09:00
Aymeric Rabot
867681e1da feat: add env.mjs for centralized env validation (t3-env)
Validates all required env vars at runtime with zod schemas.
Skips validation during build via SKIP_ENV_VALIDATION flag.
Replaces scattered process.env access with typed env imports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-19 01:47:36 -05:00
Aymeric Rabot
23a71c376f feat: avatar upload, connected accounts, round navbar avatar, Vercel analytics
- Avatar upload to Supabase Storage with pencil overlay in settings
- Show username initials as avatar fallback (instead of name initials)
- Round avatar in navbar (rounded-full with natural shadow)
- Connected Accounts section in settings showing Google status
- Connect Google directly from settings without signing out
- Add Vercel Analytics, Speed Insights, and Toolbar
- Update page title to "Pascal Editor"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-19 01:40:17 -05:00
Aymeric Rabot
aa27e0dd7a refactor: move supabase config to repo root, fix port and env setup
- Move supabase/ from packages/db/ to repo root for simpler CLI usage
- Use custom ports (553xx) to avoid conflicts with other local Supabase instances
- Add --env-mode=loose to turbo dev so root .env vars reach Next.js
- Remove hardcoded --port 3000 from next dev (reads PORT env var instead)
- Add .env.example with Supabase env var placeholders
- Add supabase local state dirs to .gitignore

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-18 01:48:53 -05:00
wass08
be7e86975e radio & sfx 2026-02-12 08:57:37 +09:00
wass08
2e8b663001 community feature 2026-02-11 15:23:18 +09:00
wass08
c1ff61ad5b isolate cloud-sync feature 2026-02-11 07:57:10 +09:00
wass08
c7e5aa48c6 auth flow draft 2026-02-10 15:58:34 +09:00
Aymeric Rabot
6c99851006 Refactor asset types and improve UI primitives
Replaces usage of the Asset type with AssetInput across editor components and hooks for consistency with core types. Adds default dimensions fallback for asset placement logic. Refactors UI primitives (button, sidebar, opacity control) to support forwarding refs and asChild prop, and updates imports for primitives. Updates Radix UI dependencies in package.json and bun.lock.
2026-01-30 22:01:25 -05:00
wass08
1f23792f9c camera view 2026-01-22 08:14:42 +09:00
wass08
cba00f7cc7 bring sidebar 2026-01-19 10:17:36 +09:00
wass08
59be752eb4 drafting tools 2026-01-17 08:58:17 +09:00
wass08
d657f4125f bringing back ui components 2026-01-16 10:49:22 +09:00
wass08
45a34d7df6 fix path issues 2026-01-16 09:23:39 +09:00
wass08
7a4d6e397d viewer rendering canvas & scene 2026-01-15 08:47:55 +09:00
wass08
f5391e27fc removing eslint 2026-01-14 09:04:19 +09:00
wass08
c9d84ea126 repo setup 2026-01-14 09:03:07 +09:00