This commit is contained in:
syuilo 2026-05-23 13:32:51 +09:00
commit 99f998cf60
8 changed files with 87 additions and 37 deletions

View file

@ -59,7 +59,10 @@ type ColorOptionSchema = {
type EnumOptionSchema = {
type: 'enum';
label: string;
enum: string[];
enum: {
label: string;
value: string | number;
}[];
};
type RangeOptionSchema = {
@ -96,7 +99,7 @@ type GetRawOptionsSchemaValues<T extends OptionsSchema> = {
T[K] extends BooleanOptionSchema ? boolean :
T[K] extends StringOptionSchema ? string :
T[K] extends ColorOptionSchema ? [number, number, number] :
T[K] extends EnumOptionSchema ? T[K]['enum'][number] :
T[K] extends EnumOptionSchema ? T[K]['enum'][number]['value'] :
T[K] extends RangeOptionSchema ? number :
T[K] extends ImageOptionSchema ? string | null :
T[K] extends SeedOptionSchema ? number :
@ -108,7 +111,7 @@ type GetConvertedOptionsSchemaValues<T extends OptionsSchema> = {
T[K] extends BooleanOptionSchema ? boolean :
T[K] extends StringOptionSchema ? string :
T[K] extends ColorOptionSchema ? [number, number, number] :
T[K] extends EnumOptionSchema ? T[K]['enum'][number] :
T[K] extends EnumOptionSchema ? T[K]['enum'][number]['value'] :
T[K] extends RangeOptionSchema ? number :
T[K] extends ImageOptionSchema ? { url: string; } | null :
T[K] extends SeedOptionSchema ? number :
@ -121,12 +124,12 @@ export type SnapshotRenderingHelperWrapper = {
fixParticleSystem: (ps: BABYLON.ParticleSystem) => void;
};
export type ObjectDef<OpSc extends OptionsSchema | undefined = undefined> = {
export type ObjectDef<OpSc extends OptionsSchema = OptionsSchema> = {
id: string;
name: string;
options: {
schema: OpSc extends undefined ? OptionsSchema : NonNullable<OpSc>;
default: OpSc extends undefined ? RawOptions : GetRawOptionsSchemaValues<NonNullable<OpSc>>;
schema: string extends keyof OpSc ? OptionsSchema : OpSc;
default: string extends keyof OpSc ? RawOptions : GetRawOptionsSchemaValues<OpSc>;
};
placement: 'top' | 'side' | 'bottom' | 'wall' | 'ceiling' | 'floor';
hasCollisions?: boolean;
@ -135,7 +138,7 @@ export type ObjectDef<OpSc extends OptionsSchema | undefined = undefined> = {
//groupingMeshes: string[]; // multi-materialなメッシュは複数のメッシュに分割されるが、それだと不便な場合に追加の親メッシュでグルーピングするための指定
isChair?: boolean;
treatLoaderResult?: (loaderResult: BABYLON.AssetContainer) => void;
path?: (options: OpSc extends undefined ? ConvertedOptions : Readonly<GetConvertedOptionsSchemaValues<NonNullable<OpSc>>>) => string;
path?: (options: string extends keyof OpSc ? ConvertedOptions : Readonly<GetConvertedOptionsSchemaValues<OpSc>>) => string;
createInstance: (args: {
scene: BABYLON.Scene;
// TODO: snapshot renderingの関心を隠蔽した方が綺麗かもしれない
@ -143,7 +146,7 @@ export type ObjectDef<OpSc extends OptionsSchema | undefined = undefined> = {
sr: SnapshotRenderingHelperWrapper;
lc: BABYLON.ClusteredLightContainer | null;
root: BABYLON.TransformNode;
options: OpSc extends undefined ? ConvertedOptions : Readonly<GetConvertedOptionsSchemaValues<NonNullable<OpSc>>>;
options: string extends keyof OpSc ? ConvertedOptions : Readonly<GetConvertedOptionsSchemaValues<OpSc>>;
model: ModelManager;
id: string;
timer: Timer;
@ -151,7 +154,7 @@ export type ObjectDef<OpSc extends OptionsSchema | undefined = undefined> = {
stickyMarkerMeshUpdated?: (mesh: BABYLON.Mesh) => void;
sitChair?: () => void;
reloadModel: () => void;
}) => RoomObjectInstance<OpSc extends undefined ? ConvertedOptions : GetConvertedOptionsSchemaValues<NonNullable<OpSc>>> | Promise<RoomObjectInstance<OpSc extends undefined ? ConvertedOptions : GetConvertedOptionsSchemaValues<NonNullable<OpSc>>>>; // TODO: createInstanceをasyncにするのではなく、別にreadyみたいなものを返させる
}) => RoomObjectInstance<string extends keyof OpSc ? ConvertedOptions : GetConvertedOptionsSchemaValues<OpSc>> | Promise<RoomObjectInstance<OpSc extends undefined ? ConvertedOptions : GetConvertedOptionsSchemaValues<OpSc>>>; // TODO: createInstanceをasyncにするのではなく、別にreadyみたいなものを返させる
};
export function defineObject<const OpSc extends OptionsSchema>(def: ObjectDef<OpSc>): ObjectDef<OpSc> {

View file

@ -15,7 +15,22 @@ export const books = defineObject({
variation: {
type: 'enum',
label: 'Variation',
enum: ['A', 'B', 'C', 'D', 'E'],
enum: [{
label: 'A',
value: 'A',
}, {
label: 'B',
value: 'B',
}, {
label: 'C',
value: 'C',
}, {
label: 'D',
value: 'D',
}, {
label: 'E',
value: 'E',
}],
},
},
default: {

View file

@ -14,7 +14,13 @@ export const issyoubin = defineObject({
variation: {
type: 'enum',
label: 'Variation',
enum: ['misuki', 'ai'],
enum: [{
label: 'Misuki',
value: 'misuki',
}, {
label: 'AI',
value: 'ai',
}],
},
},
default: {
@ -54,9 +60,7 @@ export const issyoubin = defineObject({
return {
onOptionsUpdated: ([k, v]) => {
switch (k) {
case 'variation':
applyVariation();
break;
case 'variation': applyVariation(); break;
}
},
interactions: {},

View file

@ -14,7 +14,13 @@ export const petBottle = defineObject({
variation: {
type: 'enum',
label: 'Variation',
enum: ['mineral-water', 'green-tea'],
enum: [{
label: 'Mineral Water',
value: 'mineral-water',
}, {
label: 'Green Tea',
value: 'green-tea',
}],
},
withCap: {
type: 'boolean',

View file

@ -20,7 +20,13 @@ export const randomBooks = defineObject({
variation: {
type: 'enum',
label: 'Variation',
enum: ['mix', 'mix-plain'],
enum: [{
label: 'Mix',
value: 'mix',
}, {
label: 'Mix (Plain)',
value: 'mix-plain',
}],
},
count: {
type: 'range',

View file

@ -23,7 +23,13 @@ export const steelRack = defineObject({
widthAndDepthVariation: {
type: 'enum',
label: 'W x D',
enum: ['60-35', '90-35'],
enum: [{
label: '60 x 35',
value: '60-35',
}, {
label: '90 x 35',
value: '90-35',
}],
},
height: {
type: 'range',

View file

@ -12,11 +12,6 @@ export const tabletopDigitalClock = defineObject({
name: 'Tabletop Digital Clock',
options: {
schema: {
bodyStyle: {
type: 'enum',
label: 'Body Style',
enum: ['color', 'wood'],
},
bodyColor: {
type: 'color',
label: 'Body Color',
@ -27,7 +22,6 @@ export const tabletopDigitalClock = defineObject({
},
},
default: {
bodyStyle: 'color',
bodyColor: [0.45, 0.8, 0],
lcdColor: [1, 1, 1],
},
@ -87,12 +81,8 @@ export const tabletopDigitalClock = defineObject({
const bodyMaterial = bodyMesh.material as BABYLON.PBRMaterial;
const applyBodyColor = () => {
if (options.bodyStyle === 'color') {
const [r, g, b] = options.bodyColor;
bodyMaterial.albedoColor = new BABYLON.Color3(r, g, b);
} else {
}
const [r, g, b] = options.bodyColor;
bodyMaterial.albedoColor = new BABYLON.Color3(r, g, b);
};
const applyLcdColor = () => {
@ -127,10 +117,9 @@ export const tabletopDigitalClock = defineObject({
}, 1000);
},
onOptionsUpdated: ([k, v]) => {
if (k === 'bodyColor') {
applyBodyColor();
} else if (k === 'lcdColor') {
applyLcdColor();
switch (k) {
case 'bodyColor': applyBodyColor(); break;
case 'lcdColor': applyLcdColor(); break;
}
},
interactions: {},

View file

@ -14,12 +14,30 @@ export const wallShelf = defineObject({
style: {
type: 'enum',
label: 'Style',
enum: ['A', 'B', 'C', 'D'],
enum: [{
label: 'A',
value: 'A',
}, {
label: 'B',
value: 'B',
}, {
label: 'C',
value: 'C',
}, {
label: 'D',
value: 'D',
}],
},
boardStyle: {
type: 'enum',
label: 'Board style',
enum: ['color', 'wood'],
enum: [{
label: 'Wood',
value: 'wood',
}, {
label: 'Color',
value: 'color',
}],
},
boardColor: {
type: 'color',
@ -77,8 +95,11 @@ export const wallShelf = defineObject({
return {
onOptionsUpdated: ([k, v]) => {
applyStyle();
applyBoardColor();
switch (k) {
case 'style': applyStyle(); break;
case 'boardStyle':
case 'boardColor': applyBoardColor(); break;
}
},
interactions: {},
};