Chairs have no rotation controls (rotatable flag on configs)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 12:48:54 -04:00
parent 8c92def919
commit d98ce8ddb7
5 changed files with 29 additions and 24 deletions
+2 -1
View File
@@ -15,7 +15,7 @@ Layout and editing UI. No optimizer yet.
**Editing (Phase 2)**
- Click an item to select it (blue outline); click empty floor to deselect (Escape/Done too). Dragging still moves. Selecting opens the item panel in the sidebar (replaces tiles / type menu).
- Item panel: Rotate 90 button + free angle wheel (0-359, wraps); Lock/Unlock; Delete (also Delete/Backspace key, ignored while typing in an input); "Seats at this table" wheel for tables (per-item override, "Reset to default" link when overridden); Size wheels (0.3-6 m, 0.1 steps; screens show only Length).
- Item panel (chairs have no rotation controls; every other type does): Rotate 90 button + free angle wheel (0-359, wraps); Lock/Unlock; Delete (also Delete/Backspace key, ignored while typing in an input); "Seats at this table" wheel for tables (per-item override, "Reset to default" link when overridden); Size wheels (0.3-6 m, 0.1 steps; screens show only Length).
- Rotation turns around the item's center and collision/wall clamping use the rotated bounding box (`boundsOf`). A rotate/size change is pushed back inside the walls, then rejected if it would overlap (`tryUpdate`).
- Locked items can't be dragged or rotated and show a padlock. (Size, seats and delete are still allowed on locked items.)
- Delete frees inventory automatically (remaining is derived from `items`).
@@ -54,6 +54,7 @@ interface FurnitureTypeConfig {
id: FurnitureType; name: string; shape: Shape;
defaultWidth: number; defaultHeight: number; // meters
isTable: boolean;
rotatable: boolean; // chairs: false (no rotation controls)
available: number; // inventory count
seatsPerUnit?: number; // type-level seats
}
+1
View File
@@ -162,6 +162,7 @@ export default function App() {
defaultWidth: d.width,
defaultHeight: d.height,
isTable: d.isTable,
rotatable: true,
available: d.available,
seatsPerUnit: d.seats,
},
+22 -20
View File
@@ -46,26 +46,28 @@ export function ItemPanel({ item, config, onPatch, onDelete, onClose }: Props) {
{item.locked ? " 🔒" : ""}
</div>
<div>
<div style={label}>Rotation</div>
<Wheel
value={item.rotation}
min={0}
max={359}
wrap
rows={3}
disabled={item.locked}
format={(v) => `${v}°`}
onChange={(v) => patch({ rotation: v })}
/>
<button
style={{ ...btn, marginTop: 8, width: "100%", opacity: item.locked ? 0.45 : 1 }}
disabled={item.locked}
onClick={() => patch({ rotation: (item.rotation + 90) % 360 })}
>
Rotate 90°
</button>
</div>
{config.rotatable && (
<div>
<div style={label}>Rotation</div>
<Wheel
value={item.rotation}
min={0}
max={359}
wrap
rows={3}
disabled={item.locked}
format={(v) => `${v}°`}
onChange={(v) => patch({ rotation: v })}
/>
<button
style={{ ...btn, marginTop: 8, width: "100%", opacity: item.locked ? 0.45 : 1 }}
disabled={item.locked}
onClick={() => patch({ rotation: (item.rotation + 90) % 360 })}
>
Rotate 90°
</button>
</div>
)}
{config.isTable && (
<div>
+3 -3
View File
@@ -19,9 +19,9 @@ export type Action =
| { kind: "addConfig"; config: FurnitureTypeConfig };
const BUILT_IN: FurnitureTypeConfig[] = [
{ id: "chair", name: "Chair", shape: "chair", defaultWidth: 0.5, defaultHeight: 0.5, isTable: false, available: 20 },
{ id: "table", name: "Table", shape: "table", defaultWidth: 1.8, defaultHeight: 0.8, isTable: true, available: 6, seatsPerUnit: 8 },
{ id: "screen", name: "Screen", shape: "screen", defaultWidth: 2, defaultHeight: 0.2, isTable: false, available: 2 },
{ id: "chair", name: "Chair", shape: "chair", defaultWidth: 0.5, defaultHeight: 0.5, isTable: false, rotatable: false, available: 20 },
{ id: "table", name: "Table", shape: "table", defaultWidth: 1.8, defaultHeight: 0.8, isTable: true, rotatable: true, available: 6, seatsPerUnit: 8 },
{ id: "screen", name: "Screen", shape: "screen", defaultWidth: 2, defaultHeight: 0.2, isTable: false, rotatable: true, available: 2 },
];
export const initialState: LayoutState = {
+1
View File
@@ -36,6 +36,7 @@ export interface FurnitureTypeConfig {
defaultWidth: number; // meters
defaultHeight: number;
isTable: boolean;
rotatable: boolean; // false = no rotation controls (chairs)
available: number; // inventory count
seatsPerUnit?: number; // type-level seats (tables, couches...)
}