item scale

This commit is contained in:
wass08
2026-02-23 10:59:42 +09:00
parent 3894d7c8bf
commit d15f601107
11 changed files with 143 additions and 38 deletions
@@ -1,10 +1,10 @@
'use client'
import { type AnyNode, ItemNode, useScene } from '@pascal-app/core'
import { getScaledDimensions, type AnyNode, ItemNode, useScene } from '@pascal-app/core'
import { useViewer } from '@pascal-app/viewer'
import { Copy, Move, Trash2, X } from 'lucide-react'
import { Copy, Link, Link2Off, Move, Trash2, X } from 'lucide-react'
import Image from 'next/image'
import { useCallback } from 'react'
import { useCallback, useState } from 'react'
import useEditor from '@/store/use-editor'
import { NumberInput } from '@/components/ui/primitives/number-input'
import { sfxEmitter } from '@/lib/sfx-bus'
@@ -23,6 +23,8 @@ export function ItemPanel() {
? (nodes[selectedId as AnyNode['id']] as ItemNode | undefined)
: undefined
const [uniformScale, setUniformScale] = useState(true)
const handleUpdate = useCallback(
(updates: Partial<ItemNode>) => {
if (!selectedId || !node) return
@@ -188,13 +190,75 @@ export function ItemPanel() {
</div>
</div>
{/* Dimensions (read-only) */}
{/* Scale */}
<div className="space-y-2">
<div className="flex items-center justify-between">
<label className="font-medium text-muted-foreground text-xs uppercase tracking-wide">
Scale
</label>
<button
type="button"
className="rounded p-1 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground cursor-pointer"
onClick={() => setUniformScale((v) => !v)}
title={uniformScale ? 'Unlock axes' : 'Lock axes'}
>
{uniformScale ? <Link className="h-3.5 w-3.5" /> : <Link2Off className="h-3.5 w-3.5" />}
</button>
</div>
{uniformScale ? (
<NumberInput
label="XYZ"
value={Math.round(node.scale[0] * 100) / 100}
onChange={(value) => {
const v = Math.max(0.01, value)
handleUpdate({ scale: [v, v, v] })
}}
precision={2}
step={0.1}
/>
) : (
<div className="grid grid-cols-3 gap-2">
<NumberInput
label="X"
value={Math.round(node.scale[0] * 100) / 100}
onChange={(value) => {
handleUpdate({ scale: [Math.max(0.01, value), node.scale[1], node.scale[2]] })
}}
precision={2}
step={0.1}
/>
<NumberInput
label="Y"
value={Math.round(node.scale[1] * 100) / 100}
onChange={(value) => {
handleUpdate({ scale: [node.scale[0], Math.max(0.01, value), node.scale[2]] })
}}
precision={2}
step={0.1}
/>
<NumberInput
label="Z"
value={Math.round(node.scale[2] * 100) / 100}
onChange={(value) => {
handleUpdate({ scale: [node.scale[0], node.scale[1], Math.max(0.01, value)] })
}}
precision={2}
step={0.1}
/>
</div>
)}
</div>
{/* Dimensions (effective, read-only) */}
<div className="space-y-2">
<label className="font-medium text-muted-foreground text-xs uppercase tracking-wide">
Dimensions
</label>
<div className="rounded border border-border bg-muted/50 px-3 py-2 text-sm">
{node.asset.dimensions[0]}m × {node.asset.dimensions[1]}m × {node.asset.dimensions[2]}m
{(() => {
const [w, h, d] = getScaledDimensions(node)
return `${Math.round(w * 100) / 100}m × ${Math.round(h * 100) / 100}m × ${Math.round(d * 100) / 100}m`
})()}
</div>
</div>
</div>