diff --git a/packages/frontend/assets/room/objects/stanchion-pole/stanchion-pole.blend b/packages/frontend/assets/room/objects/stanchion-pole/stanchion-pole.blend new file mode 100644 index 0000000000..93c25a9d96 Binary files /dev/null and b/packages/frontend/assets/room/objects/stanchion-pole/stanchion-pole.blend differ diff --git a/packages/frontend/assets/room/objects/stanchion-pole/stanchion-pole.glb b/packages/frontend/assets/room/objects/stanchion-pole/stanchion-pole.glb new file mode 100644 index 0000000000..aad6bd29ce Binary files /dev/null and b/packages/frontend/assets/room/objects/stanchion-pole/stanchion-pole.glb differ diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 18e51bf585..0c1e79f7ac 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -17,10 +17,10 @@ }, "dependencies": { "@analytics/google-analytics": "1.1.0", - "@babylonjs/core": "9.5.0", - "@babylonjs/inspector": "9.5.0", - "@babylonjs/loaders": "9.5.0", - "@babylonjs/materials": "9.5.0", + "@babylonjs/core": "9.5.1", + "@babylonjs/inspector": "9.5.1", + "@babylonjs/loaders": "9.5.1", + "@babylonjs/materials": "9.5.1", "@discordapp/twemoji": "16.0.1", "@github/webauthn-json": "2.1.1", "@mcaptcha/core-glue": "0.1.0-alpha-5", diff --git a/packages/frontend/src/world/room/object-defs.ts b/packages/frontend/src/world/room/object-defs.ts index e963b5a71f..385bb3bc79 100644 --- a/packages/frontend/src/world/room/object-defs.ts +++ b/packages/frontend/src/world/room/object-defs.ts @@ -83,6 +83,7 @@ import { speaker } from './objects/speaker.js'; import { speakerStand } from './objects/speakerStand.js'; import { spotLight } from './objects/spotLight.js'; import { sprayer } from './objects/sprayer.js'; +import { stanchionPole } from './objects/stanchionPole.js'; import { steelRack } from './objects/steelRack.js'; import { stormGlass } from './objects/stormGlass.js'; import { tableSalt } from './objects/tableSalt.js'; @@ -213,6 +214,7 @@ export const OBJECT_DEFS = [ spotLight, lowPartitionBar, descriptionPlate, + stanchionPole, ]; export function getObjectDef(type: string): typeof OBJECT_DEFS[number] { diff --git a/packages/frontend/src/world/room/objects/lavaLamp.ts b/packages/frontend/src/world/room/objects/lavaLamp.ts index 11d0cedb3a..0619bc7a48 100644 --- a/packages/frontend/src/world/room/objects/lavaLamp.ts +++ b/packages/frontend/src/world/room/objects/lavaLamp.ts @@ -98,48 +98,52 @@ export const lavaLamp = defineObject({ let animationObserver: BABYLON.Observer; + const anim = new BABYLON.Animation('lavaLampLightAnim', 'position.y', 60, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE); + anim.setKeys([ + { frame: 0, value: cm(11) }, + { frame: 800, value: cm(38) }, + ]); + sphere.animations = [anim]; + scene.beginAnimation(sphere, 0, 800, true); + sphere2.animations = [anim]; + scene.beginAnimation(sphere2, 0, 800, true, 0.65); + sphere3.animations = [anim]; + scene.beginAnimation(sphere3, 0, 800, true, 0.6); + + animationObserver = scene.onAfterAnimationsObservable.add(() => { + room?.sr.updateMesh([sphere, sphere2, sphere3], false); + }); + + const emitter = new BABYLON.TransformNode('emitter', scene); + emitter.parent = root; + emitter.position = new BABYLON.Vector3(0, cm(10), 0); + const ps = new BABYLON.ParticleSystem('', 32, scene); + ps.particleTexture = new BABYLON.Texture('/client-assets/room/objects/lava-lamp/bubble.png'); + ps.emitter = emitter; + ps.isLocal = true; + ps.minEmitBox = new BABYLON.Vector3(cm(-1), 0, cm(-1)); + ps.maxEmitBox = new BABYLON.Vector3(cm(1), 0, cm(1)); + ps.minEmitPower = cm(1); + ps.maxEmitPower = cm(2.5); + ps.minLifeTime = 12; + ps.maxLifeTime = 12; + ps.minSize = cm(0.25); + ps.maxSize = cm(1.25); + ps.direction1 = new BABYLON.Vector3(0, 1, 0); + ps.direction2 = new BABYLON.Vector3(0, 1, 0); + ps.emitRate = 1; + ps.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD; + ps.color1 = new BABYLON.Color4(1, 1, 1, 1); + ps.color2 = new BABYLON.Color4(1, 1, 1, 0.75); + ps.colorDead = new BABYLON.Color4(1, 1, 1, 0); + ps.preWarmCycles = 100; + ps.start(); + + room?.sr.fixParticleSystem(ps); + return { onInited: () => { - const anim = new BABYLON.Animation('lavaLampLightAnim', 'position.y', 60, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE); - anim.setKeys([ - { frame: 0, value: cm(11) }, - { frame: 800, value: cm(38) }, - ]); - sphere.animations = [anim]; - scene.beginAnimation(sphere, 0, 800, true); - sphere2.animations = [anim]; - scene.beginAnimation(sphere2, 0, 800, true, 0.65); - sphere3.animations = [anim]; - scene.beginAnimation(sphere3, 0, 800, true, 0.6); - animationObserver = scene.onAfterAnimationsObservable.add(() => { - room?.sr.updateMesh([sphere, sphere2, sphere3], false); - }); - - const emitter = new BABYLON.TransformNode('emitter', scene); - emitter.parent = root; - emitter.position = new BABYLON.Vector3(0, cm(10), 0); - const ps = new BABYLON.ParticleSystem('', 32, scene); - ps.particleTexture = new BABYLON.Texture('/client-assets/room/objects/lava-lamp/bubble.png'); - ps.emitter = emitter; - ps.isLocal = true; - ps.minEmitBox = new BABYLON.Vector3(cm(-1), 0, cm(-1)); - ps.maxEmitBox = new BABYLON.Vector3(cm(1), 0, cm(1)); - ps.minEmitPower = cm(1); - ps.maxEmitPower = cm(2.5); - ps.minLifeTime = 12; - ps.maxLifeTime = 12; - ps.minSize = cm(0.25); - ps.maxSize = cm(1.25); - ps.direction1 = new BABYLON.Vector3(0, 1, 0); - ps.direction2 = new BABYLON.Vector3(0, 1, 0); - ps.emitRate = 1; - ps.blendMode = BABYLON.ParticleSystem.BLENDMODE_ADD; - ps.color1 = new BABYLON.Color4(1, 1, 1, 1); - ps.color2 = new BABYLON.Color4(1, 1, 1, 0.75); - ps.colorDead = new BABYLON.Color4(1, 1, 1, 0); - ps.preWarmCycles = 100; - ps.start(); }, interactions: {}, onOptionsUpdated: ([k, v]) => { diff --git a/packages/frontend/src/world/room/objects/pictureFrame.ts b/packages/frontend/src/world/room/objects/pictureFrame.ts index f7415c86f8..02e4c9ea2a 100644 --- a/packages/frontend/src/world/room/objects/pictureFrame.ts +++ b/packages/frontend/src/world/room/objects/pictureFrame.ts @@ -60,6 +60,10 @@ export const pictureFrame = defineObject({ max: 1, step: 0.01, }, + withCover: { + type: 'boolean', + label: 'With cover', + }, customPicture: { type: 'image', label: 'Custom picture', @@ -78,6 +82,7 @@ export const pictureFrame = defineObject({ depth: 0, matHThickness: 0.35, matVThickness: 0.35, + withCover: true, customPicture: null, fit: 'cover', }, @@ -160,6 +165,13 @@ export const pictureFrame = defineObject({ applyDepth(); + const applyWithCover = () => { + coverMesh.isVisible = options.withCover; + model.updated(); + }; + + applyWithCover(); + const applyCustomPicture = () => new Promise((resolve) => { if (options.customPicture != null) { pictureMaterial.unfreeze(); @@ -199,26 +211,17 @@ export const pictureFrame = defineObject({ }, onOptionsUpdated: ([k, v]) => { - if (k === 'frameColor') { - applyFrameColor(); - } - if (k === 'width' || k === 'height') { - applySize(); - } - if (k === 'frameThickness') { - applyFrameThickness(); - } - if (k === 'depth') { - applyDepth(); - } - if (k === 'matHThickness' || k === 'matVThickness') { - applyMatThickness(); - } - if (k === 'customPicture') { - applyCustomPicture(); - } - if (k === 'fit') { - applyFit(); + switch (k) { + case 'frameColor': applyFrameColor(); break; + case 'width': + case 'height': applySize(); break; + case 'frameThickness': applyFrameThickness(); break; + case 'matHThickness': + case 'matVThickness': applyMatThickness(); break; + case 'depth': applyDepth(); break; + case 'withCover': applyWithCover(); break; + case 'customPicture': + case 'fit': applyCustomPicture(); break; } }, interactions: {}, diff --git a/packages/frontend/src/world/room/objects/stanchionPole.ts b/packages/frontend/src/world/room/objects/stanchionPole.ts new file mode 100644 index 0000000000..041344c465 --- /dev/null +++ b/packages/frontend/src/world/room/objects/stanchionPole.ts @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import * as BABYLON from '@babylonjs/core'; +import { defineObject } from '../object.js'; + +export const stanchionPole = defineObject({ + id: 'stanchionPole', + name: 'stanchionPole', + options: { + schema: { + bodyColor: { + type: 'color', + label: 'Body color', + }, + ropeColor: { + type: 'color', + label: 'Rope color', + }, + }, + default: { + bodyColor: [0.8, 0.39, 0.1], + ropeColor: [0.21, 0.0, 0.0], + }, + }, + placement: 'floor', + hasCollisions: false, + hasTexture: false, + createInstance: ({ options, model }) => { + const bodyMaterial = model.findMaterial('__X_BODY__'); + + const applyBodyColor = () => { + const [r, g, b] = options.bodyColor; + bodyMaterial.albedoColor = new BABYLON.Color3(r, g, b); + }; + + applyBodyColor(); + + const ropeMaterial = model.findMaterial('__X_ROPE__'); + + const applyRopeColor = () => { + const [r, g, b] = options.ropeColor; + ropeMaterial.albedoColor = new BABYLON.Color3(r, g, b); + }; + + applyRopeColor(); + + return { + onOptionsUpdated: ([k, v]) => { + switch (k) { + case 'bodyColor': applyBodyColor(); break; + case 'ropeColor': applyRopeColor(); break; + } + }, + interactions: {}, + }; + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52f961f98f..3ca4b5cdfa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -612,17 +612,17 @@ importers: specifier: 1.1.0 version: 1.1.0 '@babylonjs/core': - specifier: 9.5.0 - version: 9.5.0 + specifier: 9.5.1 + version: 9.5.1 '@babylonjs/inspector': - specifier: 9.5.0 - version: 9.5.0(ff8a1bb88ff981e3db6a2e8a0a3f9750) + specifier: 9.5.1 + version: 9.5.1(160203920591168ac4221ec379e95c1a) '@babylonjs/loaders': - specifier: 9.5.0 - version: 9.5.0(@babylonjs/core@9.5.0)(babylonjs-gltf2interface@8.51.2) + specifier: 9.5.1 + version: 9.5.1(@babylonjs/core@9.5.1)(babylonjs-gltf2interface@8.51.2) '@babylonjs/materials': - specifier: 9.5.0 - version: 9.5.0(@babylonjs/core@9.5.0) + specifier: 9.5.1 + version: 9.5.1(@babylonjs/core@9.5.1) '@discordapp/twemoji': specifier: 16.0.1 version: 16.0.1 @@ -1735,8 +1735,8 @@ packages: peerDependencies: '@babylonjs/core': ^8.0.0 - '@babylonjs/core@9.5.0': - resolution: {integrity: sha512-DTqkOTueTp/xSw/VTVzrxLpBWjamVIKXbAbgqDHRR/V3Am5F5LRGscaWjWgPc5INv7HD2zTln/lyWdm47KQkgQ==} + '@babylonjs/core@9.5.1': + resolution: {integrity: sha512-T3qzihiGqwKZitQgLxqjLhNDRmaQe/Fp8lxinw1ZMaZeErSdWNDgmHtReuxG1/X2XZ0cbYkJkZF/99flNzlX4Q==} '@babylonjs/gui-editor@8.51.2': resolution: {integrity: sha512-+kG9551b0iPK/BcPhdK3QUlaA+BJ9pt3LGiWkhyEMKYfZ0dJRjjmoFZuCAehlYU9sxEiWf1C/y96BrPt2QodIA==} @@ -1751,8 +1751,8 @@ packages: peerDependencies: '@babylonjs/core': ^8.0.0 - '@babylonjs/inspector@9.5.0': - resolution: {integrity: sha512-YP6LgiUJShwotk7t9iYQdU3qVfWmIiwZ3zJi0Ci3A4T0enulaf6dM1eK31gImp1mH01N3ZcnvTJ5y0UZ34mVog==} + '@babylonjs/inspector@9.5.1': + resolution: {integrity: sha512-J5gASGTJ66wC2iHf1KWH74vTIPYEEy0UoWFh+YHRvJk9dl8ncV4EtVdW6GfUZNZlSs0fBpLPYG4D9T9YicT2Xg==} hasBin: true peerDependencies: '@babylonjs/addons': ^9.0.0 @@ -1770,14 +1770,14 @@ packages: react-dom: '>=16.14.0 <20.0.0' usehooks-ts: ^3.1.1 - '@babylonjs/loaders@9.5.0': - resolution: {integrity: sha512-e2PqqPQ2A6xCJ6yW2NtcCzCKfN7neJjpxCUWBXqVUc268QnC1DNV49PM6bVpzNzTqzYjapMR9u5apcvAWo2iYQ==} + '@babylonjs/loaders@9.5.1': + resolution: {integrity: sha512-Si22HIUlWyP5EuzN1MIEOLSY6K07yjEvFeO3GwZA5v+nGzU/MbVCPKtIKasQ72D0WLABfFHEO6cu24XhjkPGHQ==} peerDependencies: '@babylonjs/core': ^9.0.0 babylonjs-gltf2interface: ^9.0.0 - '@babylonjs/materials@9.5.0': - resolution: {integrity: sha512-zKXs5UBqMGhDcpGhlIKvOuMPd77Pm6myAv0xEi0d7UL4dGk0u86bs4dQO2kqXGstf3bwzR3fNvljAuhOrDYflg==} + '@babylonjs/materials@9.5.1': + resolution: {integrity: sha512-jVtuZxKP7PGolJiC3REKEK/1dFz+Qf8y7YWOuQ//GlWYYBCXwz+3C6asCCvmuLOA6aRIRWEm8oElj/8pqE8+PQ==} peerDependencies: '@babylonjs/core': ^9.0.0 @@ -11866,32 +11866,32 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@babylonjs/addons@8.51.2(@babylonjs/core@9.5.0)': + '@babylonjs/addons@8.51.2(@babylonjs/core@9.5.1)': dependencies: - '@babylonjs/core': 9.5.0 + '@babylonjs/core': 9.5.1 - '@babylonjs/core@9.5.0': {} + '@babylonjs/core@9.5.1': {} - '@babylonjs/gui-editor@8.51.2(@babylonjs/core@9.5.0)(@babylonjs/gui@8.51.2(@babylonjs/core@9.5.0))(@types/react-dom@19.2.3(@types/react@19.2.2))(@types/react@19.2.2)': + '@babylonjs/gui-editor@8.51.2(@babylonjs/core@9.5.1)(@babylonjs/gui@8.51.2(@babylonjs/core@9.5.1))(@types/react-dom@19.2.3(@types/react@19.2.2))(@types/react@19.2.2)': dependencies: - '@babylonjs/core': 9.5.0 - '@babylonjs/gui': 8.51.2(@babylonjs/core@9.5.0) + '@babylonjs/core': 9.5.1 + '@babylonjs/gui': 8.51.2(@babylonjs/core@9.5.1) '@types/react': 19.2.2 '@types/react-dom': 19.2.3(@types/react@19.2.2) - '@babylonjs/gui@8.51.2(@babylonjs/core@9.5.0)': + '@babylonjs/gui@8.51.2(@babylonjs/core@9.5.1)': dependencies: - '@babylonjs/core': 9.5.0 + '@babylonjs/core': 9.5.1 - '@babylonjs/inspector@9.5.0(ff8a1bb88ff981e3db6a2e8a0a3f9750)': + '@babylonjs/inspector@9.5.1(160203920591168ac4221ec379e95c1a)': dependencies: - '@babylonjs/addons': 8.51.2(@babylonjs/core@9.5.0) - '@babylonjs/core': 9.5.0 - '@babylonjs/gui': 8.51.2(@babylonjs/core@9.5.0) - '@babylonjs/gui-editor': 8.51.2(@babylonjs/core@9.5.0)(@babylonjs/gui@8.51.2(@babylonjs/core@9.5.0))(@types/react-dom@19.2.3(@types/react@19.2.2))(@types/react@19.2.2) - '@babylonjs/loaders': 9.5.0(@babylonjs/core@9.5.0)(babylonjs-gltf2interface@8.51.2) - '@babylonjs/materials': 9.5.0(@babylonjs/core@9.5.0) - '@babylonjs/serializers': 8.51.2(@babylonjs/core@9.5.0)(babylonjs-gltf2interface@8.51.2) + '@babylonjs/addons': 8.51.2(@babylonjs/core@9.5.1) + '@babylonjs/core': 9.5.1 + '@babylonjs/gui': 8.51.2(@babylonjs/core@9.5.1) + '@babylonjs/gui-editor': 8.51.2(@babylonjs/core@9.5.1)(@babylonjs/gui@8.51.2(@babylonjs/core@9.5.1))(@types/react-dom@19.2.3(@types/react@19.2.2))(@types/react@19.2.2) + '@babylonjs/loaders': 9.5.1(@babylonjs/core@9.5.1)(babylonjs-gltf2interface@8.51.2) + '@babylonjs/materials': 9.5.1(@babylonjs/core@9.5.1) + '@babylonjs/serializers': 8.51.2(@babylonjs/core@9.5.1)(babylonjs-gltf2interface@8.51.2) '@fluentui-contrib/react-resize-handle': 0.8.4(@fluentui/react-components@9.73.0(@types/react-dom@19.2.3(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(scheduler@0.27.0))(@types/react-dom@19.2.3(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@fluentui-contrib/react-virtualizer': 0.5.4(@fluentui/react-shared-contexts@9.26.1(@types/react@19.2.2)(react@19.2.5))(@types/react-dom@19.2.3(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@fluentui/react-components': 9.73.0(@types/react-dom@19.2.3(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(scheduler@0.27.0) @@ -11900,18 +11900,18 @@ snapshots: react-dom: 19.2.5(react@19.2.5) usehooks-ts: 3.1.1(react@19.2.5) - '@babylonjs/loaders@9.5.0(@babylonjs/core@9.5.0)(babylonjs-gltf2interface@8.51.2)': + '@babylonjs/loaders@9.5.1(@babylonjs/core@9.5.1)(babylonjs-gltf2interface@8.51.2)': dependencies: - '@babylonjs/core': 9.5.0 + '@babylonjs/core': 9.5.1 babylonjs-gltf2interface: 8.51.2 - '@babylonjs/materials@9.5.0(@babylonjs/core@9.5.0)': + '@babylonjs/materials@9.5.1(@babylonjs/core@9.5.1)': dependencies: - '@babylonjs/core': 9.5.0 + '@babylonjs/core': 9.5.1 - '@babylonjs/serializers@8.51.2(@babylonjs/core@9.5.0)(babylonjs-gltf2interface@8.51.2)': + '@babylonjs/serializers@8.51.2(@babylonjs/core@9.5.1)(babylonjs-gltf2interface@8.51.2)': dependencies: - '@babylonjs/core': 9.5.0 + '@babylonjs/core': 9.5.1 babylonjs-gltf2interface: 8.51.2 '@bcoe/v8-coverage@1.0.2': {}