diff --git a/packages/frontend/assets/room/objects/wall-shelf/textures/wood.png b/packages/frontend/assets/room/objects/wall-shelf/textures/wood.png
new file mode 100644
index 0000000000..3d0c47a25a
Binary files /dev/null and b/packages/frontend/assets/room/objects/wall-shelf/textures/wood.png differ
diff --git a/packages/frontend/assets/room/objects/wall-shelf/wall-shelf.blend b/packages/frontend/assets/room/objects/wall-shelf/wall-shelf.blend
new file mode 100644
index 0000000000..42392dbdc0
Binary files /dev/null and b/packages/frontend/assets/room/objects/wall-shelf/wall-shelf.blend differ
diff --git a/packages/frontend/assets/room/objects/wall-shelf/wall-shelf.glb b/packages/frontend/assets/room/objects/wall-shelf/wall-shelf.glb
new file mode 100644
index 0000000000..04228ca431
Binary files /dev/null and b/packages/frontend/assets/room/objects/wall-shelf/wall-shelf.glb differ
diff --git a/packages/frontend/src/pages/room.vue b/packages/frontend/src/pages/room.vue
index f679fbef08..33a0ba5851 100644
--- a/packages/frontend/src/pages/room.vue
+++ b/packages/frontend/src/pages/room.vue
@@ -33,6 +33,9 @@ SPDX-License-Identifier: AGPL-3.0-only
{ const c = getRgb(v); if (c != null) engine.updateObjectOption(engine.selected.value.objectId, k, c); }">
+
+ engine.updateObjectOption(engine.selected.value.objectId, k, v)">
+
@@ -602,5 +605,7 @@ definePage(() => ({
right: 16px;
z-index: 1;
padding: 16px;
+ box-sizing: border-box;
+ width: 300px;
}
diff --git a/packages/frontend/src/utility/room/engine.ts b/packages/frontend/src/utility/room/engine.ts
index b4b0ba07fc..2272a60bd5 100644
--- a/packages/frontend/src/utility/room/engine.ts
+++ b/packages/frontend/src/utility/room/engine.ts
@@ -25,7 +25,7 @@ import { registerBuiltInLoaders } from '@babylonjs/loaders/dynamic';
import { BoundingBoxRenderer } from '@babylonjs/core/Rendering/boundingBoxRenderer';
import { GridMaterial } from '@babylonjs/materials';
import { ShowInspector } from '@babylonjs/inspector';
-import { reactive, ref, shallowRef, watch } from 'vue';
+import { reactive, ref, shallowRef, triggerRef, watch } from 'vue';
import { genId } from '../id.js';
import { getObjectDef } from './object-defs.js';
import { HorizontalCameraKeyboardMoveInput } from './utility.js';
@@ -78,16 +78,16 @@ type ColorOptionSchema = {
label: string;
};
-type SelectOptionSchema = {
- type: 'select';
+type EnumOptionSchema = {
+ type: 'enum';
label: string;
enum: string[];
};
-type OptionsSchema = Record;
+type OptionsSchema = Record;
type GetOptionsSchemaValues = {
- [K in keyof T]: T[K] extends NumberOptionSchema ? number : T[K] extends ColorOptionSchema ? [number, number, number] : T[K] extends SelectOptionSchema ? T[K]['enum'][number] : never;
+ [K in keyof T]: T[K] extends NumberOptionSchema ? number : T[K] extends ColorOptionSchema ? [number, number, number] : T[K] extends EnumOptionSchema ? T[K]['enum'][number] : never;
};
type ObjectDef = {
@@ -1213,6 +1213,10 @@ export class RoomEngine {
const obji = this.objectInstances.get(objectId);
if (obji == null) return;
obji.onOptionsUpdated?.([key, value]);
+
+ if (this.selected.value?.objectId === objectId) {
+ triggerRef(this.selected);
+ }
}
public resize() {
diff --git a/packages/frontend/src/utility/room/object-defs.ts b/packages/frontend/src/utility/room/object-defs.ts
index 01693026a8..1c50f321a6 100644
--- a/packages/frontend/src/utility/room/object-defs.ts
+++ b/packages/frontend/src/utility/room/object-defs.ts
@@ -39,6 +39,7 @@ import { tabletopCalendar } from './objects/tabletopCalendar.js';
import { tabletopDigitalClock } from './objects/tabletopDigitalClock.js';
import { tv } from './objects/tv.js';
import { wallClock } from './objects/wallClock.js';
+import { wallShelf } from './objects/wallShelf.js';
import { woodSoundAbsorbingPanel } from './objects/woodSoundAbsorbingPanel.js';
export const OBJECT_DEFS = [
@@ -78,6 +79,7 @@ export const OBJECT_DEFS = [
tabletopDigitalClock,
tv,
wallClock,
+ wallShelf,
woodSoundAbsorbingPanel,
];
diff --git a/packages/frontend/src/utility/room/objects/tabletopDigitalClock.ts b/packages/frontend/src/utility/room/objects/tabletopDigitalClock.ts
index 74ec2f9772..d75a920393 100644
--- a/packages/frontend/src/utility/room/objects/tabletopDigitalClock.ts
+++ b/packages/frontend/src/utility/room/objects/tabletopDigitalClock.ts
@@ -13,7 +13,7 @@ export const tabletopDigitalClock = defineObject({
options: {
schema: {
bodyStyle: {
- type: 'select',
+ type: 'enum',
label: 'Body Style',
enum: ['color', 'wood'],
},
@@ -37,7 +37,7 @@ export const tabletopDigitalClock = defineObject({
const [r, g, b] = options.bodyColor;
bodyMaterial.albedoColor = new BABYLON.Color3(r, g, b);
} else {
- bodyMaterial.albedoTexture = room.scene.getTextureByName('tabletop_digital_clock_wood');
+
}
};
diff --git a/packages/frontend/src/utility/room/objects/wallShelf.ts b/packages/frontend/src/utility/room/objects/wallShelf.ts
new file mode 100644
index 0000000000..d72914708f
--- /dev/null
+++ b/packages/frontend/src/utility/room/objects/wallShelf.ts
@@ -0,0 +1,76 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import * as BABYLON from '@babylonjs/core';
+import { defineObject } from '../engine.js';
+
+export const wallShelf = defineObject({
+ id: 'wallShelf',
+ name: 'Wall Shelf',
+ options: {
+ schema: {
+ style: {
+ type: 'enum',
+ label: 'Style',
+ enum: ['A', 'B'],
+ },
+ boardStyle: {
+ type: 'enum',
+ label: 'Board style',
+ enum: ['color', 'wood'],
+ },
+ boardColor: {
+ type: 'color',
+ label: 'Board color',
+ },
+ },
+ default: {
+ style: 'A',
+ boardStyle: 'wood',
+ boardColor: [1, 1, 1],
+ },
+ },
+ placement: 'side',
+ createInstance: ({ room, options, root }) => {
+ const applyStyle = () => {
+ const aMeshes = root.getChildMeshes().filter(m => m.name.includes('__X_VARIATION_A__'));
+ const bMeshes = root.getChildMeshes().filter(m => m.name.includes('__X_VARIATION_B__'));
+
+ for (const m of aMeshes) {
+ (m as BABYLON.Mesh).setEnabled(options.style === 'A');
+ }
+ for (const m of bMeshes) {
+ (m as BABYLON.Mesh).setEnabled(options.style === 'B');
+ }
+ };
+
+ applyStyle();
+
+ const bodyMesh = root.getChildMeshes().find(m => m.name.includes('__X_BOARD__')) as BABYLON.Mesh;
+ const bodyMaterial = bodyMesh.material as BABYLON.PBRMaterial;
+ const bodyTexture = bodyMaterial.albedoTexture as BABYLON.Texture;
+
+ const applyBoardColor = () => {
+ const [r, g, b] = options.boardColor;
+ bodyMaterial.albedoColor = new BABYLON.Color3(r, g, b);
+
+ if (options.boardStyle === 'color') {
+ bodyMaterial.albedoTexture = null;
+ } else {
+ bodyMaterial.albedoTexture = bodyTexture;
+ }
+ };
+
+ applyBoardColor();
+
+ return {
+ onOptionsUpdated: ([k, v]) => {
+ applyStyle();
+ applyBoardColor();
+ },
+ interactions: {},
+ };
+ },
+});