@operato/property-panel 10.0.0-beta.15 → 10.0.0-beta.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [10.0.0-beta.18](https://github.com/hatiolab/operato/compare/v10.0.0-beta.17...v10.0.0-beta.18) (2026-03-25)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### :rocket: New Features
|
|
10
|
+
|
|
11
|
+
* **property-panel:** cameraFloorConstraint UI 추가 ([8bb94e5](https://github.com/hatiolab/operato/commit/8bb94e59f8e356a9deb755a82e91939fcf2df7e6))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
6
15
|
## [10.0.0-beta.15](https://github.com/hatiolab/operato/compare/v10.0.0-beta.14...v10.0.0-beta.15) (2026-03-22)
|
|
7
16
|
|
|
8
17
|
|
|
@@ -82,6 +82,14 @@ export class PropertyScene3D extends AbstractProperty {
|
|
|
82
82
|
${o.label}
|
|
83
83
|
</option>`)}
|
|
84
84
|
</select>
|
|
85
|
+
|
|
86
|
+
<input
|
|
87
|
+
id="cb-floor-constraint"
|
|
88
|
+
type="checkbox"
|
|
89
|
+
value-key="cameraFloorConstraint"
|
|
90
|
+
.checked=${!!value.cameraFloorConstraint}
|
|
91
|
+
/>
|
|
92
|
+
<label for="cb-floor-constraint">Floor Constraint (Viewer)</label>
|
|
85
93
|
</div>
|
|
86
94
|
</fieldset>
|
|
87
95
|
`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"property-scene3d.js","sourceRoot":"","sources":["../../../../src/property-panel/threed/property-scene3d.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/input/ox-input-color.js'\n\nimport './property-material3d.js'\n\nimport { css, html } from 'lit'\nimport { property } from 'lit/decorators.js'\n\nimport { Properties, Scene } from '@hatiolab/things-scene'\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\n\nimport { AbstractProperty } from '../abstract-property.js'\n\nconst LIGHTING_PRESETS: Record<string, Record<string, unknown>> = {\n Neutral: {\n hemiIntensity: 0.6,\n dirLightEnabled: true,\n dirLightColor: '#ffffff',\n dirLightIntensity: 0.5\n },\n Studio: {\n hemiIntensity: 0.5,\n dirLightEnabled: true,\n dirLightColor: '#ffffff',\n dirLightIntensity: 0.6\n },\n Bright: {\n hemiIntensity: 0.8,\n dirLightEnabled: true,\n dirLightColor: '#ffffff',\n dirLightIntensity: 0.7\n },\n Warm: {\n hemiIntensity: 0.5,\n dirLightEnabled: true,\n dirLightColor: '#ffcc88',\n dirLightIntensity: 0.4\n },\n Cool: {\n hemiIntensity: 0.5,\n dirLightEnabled: true,\n dirLightColor: '#cce0ff',\n dirLightIntensity: 0.4\n },\n Flat: {\n hemiIntensity: 0.8,\n dirLightEnabled: false,\n dirLightColor: '#ffffff',\n dirLightIntensity: 0\n }\n}\n\n/**\n * Scene-level 3D settings for model-layer.\n * Includes 3D mode, camera, renderer, lighting, presets, and floor configuration.\n */\nexport class PropertyScene3D extends AbstractProperty {\n static styles = [\n PropertyGridStyles,\n css`\n .preset-buttons {\n grid-column: 1 / -1;\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n padding: 2px 0;\n }\n\n .preset-buttons button {\n flex: 1;\n min-width: 60px;\n padding: 4px 6px;\n border: 1px solid var(--md-sys-color-outline, #ccc);\n border-radius: 4px;\n background: var(--md-sys-color-surface, #fff);\n color: var(--md-sys-color-on-surface, #333);\n font-size: 11px;\n cursor: pointer;\n }\n\n .preset-buttons button:hover {\n background: var(--md-sys-color-primary-container, #e0e0e0);\n }\n\n .range-with-value {\n grid-column: 9 / -1;\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .range-with-value input[type='range'] {\n flex: 1;\n border: none;\n background: transparent;\n padding: 0;\n }\n\n .range-with-value span {\n min-width: 2.5em;\n text-align: right;\n font-size: 11px;\n color: var(--md-sys-color-on-secondary-container);\n }\n\n .bookmark-slots {\n grid-column: 1 / -1;\n display: grid;\n grid-template-columns: repeat(9, 1fr);\n gap: 2px;\n padding: 4px 0 0;\n }\n\n .bookmark-slot {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 24px;\n border-radius: 3px;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n color: var(--md-sys-color-outline, #999);\n background: var(--md-sys-color-surface-variant, #f0f0f0);\n border: 1px solid transparent;\n user-select: none;\n transition: all 0.12s ease;\n }\n\n .bookmark-slot:hover {\n background: var(--md-sys-color-secondary-container, #e0e0e0);\n }\n\n .bookmark-slot.filled {\n color: var(--md-sys-color-primary, #6750A4);\n background: var(--md-sys-color-primary-container, #EADDFF);\n border-color: var(--md-sys-color-primary, #6750A4);\n font-weight: 700;\n }\n\n .bookmark-slot:active {\n transform: scale(0.9);\n }\n\n .bookmark-slot.saving {\n animation: bookmark-fill 0.6s linear forwards;\n }\n\n @keyframes bookmark-fill {\n from { box-shadow: inset 24px 0 0 0 transparent; }\n to { box-shadow: inset 24px 0 0 0 var(--md-sys-color-primary-container, #EADDFF); }\n }\n\n .bookmark-slot.saved {\n animation: bookmark-saved 0.3s ease;\n }\n\n @keyframes bookmark-saved {\n 0% { transform: scale(1); }\n 50% { transform: scale(1.2); }\n 100% { transform: scale(1); }\n }\n `\n ]\n\n @property({ type: Object }) value?: Properties\n @property({ type: Object }) scene: Scene | null = null\n\n render() {\n const value = this.value || {}\n\n return html`\n ${this._renderMode(value)} ${this._renderBookmarks(value)} ${this._renderRenderer(value)}\n ${this._renderSky(value)}\n ${this._renderHemisphereLight(value)} ${this._renderKeyLight(value)} ${this._renderLightingPresets()}\n ${this._renderFloor(value)}\n `\n }\n\n private _renderMode(value: Properties) {\n return html`\n <fieldset>\n <legend>3D Mode</legend>\n <div class=\"property-grid\">\n <input id=\"cb-threed\" type=\"checkbox\" value-key=\"threed\" .checked=${!!value.threed} />\n <label for=\"cb-threed\">Enable 3D</label>\n\n <label>Viewer Auto</label>\n <select value-key=\"cameraAutoPlay\">\n ${[\n { value: '', label: 'None' },\n { value: 'orbit', label: 'Orbit' },\n { value: 'play', label: 'Play Bookmarks' }\n ].map(\n o =>\n html`<option value=${o.value} ?selected=${(value.cameraAutoPlay || '') === o.value}>\n ${o.label}\n </option>`\n )}\n </select>\n </div>\n </fieldset>\n `\n }\n\n private _renderBookmarks(value: Properties) {\n const bookmarks: (any | null)[] = value.cameraBookmarks || []\n\n return html`\n <fieldset>\n <legend>Bookmarks</legend>\n <div class=\"property-grid\">\n <div class=\"bookmark-slots\">\n ${[1, 2, 3, 4, 5, 6, 7, 8, 9].map(i => {\n const filled = !!bookmarks[i]\n return html`\n <div\n class=\"bookmark-slot ${filled ? 'filled' : ''}\"\n title=${filled ? 'Click: Go / Long-click: Overwrite / Right-click: Delete' : 'Long-click: Save current camera'}\n @click=${(e: MouseEvent) => { if (filled) { this._bookmarkAction('navigate', i); const t = e.currentTarget as HTMLElement; t.classList.add('saved'); setTimeout(() => t.classList.remove('saved'), 300) } }}\n @contextmenu=${(e: Event) => { e.preventDefault(); if (filled) this._bookmarkAction('clear', i) }}\n @mousedown=${(e: MouseEvent) => this._onBookmarkMouseDown(e, i)}\n @mouseup=${() => this._onBookmarkMouseUp()}\n @mouseleave=${() => this._onBookmarkMouseUp()}\n >${i}</div>\n `\n })}\n </div>\n </div>\n </fieldset>\n `\n }\n\n private _longPressTimer?: ReturnType<typeof setTimeout>\n private _pressTarget?: HTMLElement\n\n private _onBookmarkMouseDown(e: MouseEvent, index: number) {\n if (e.button !== 0) return\n const target = e.currentTarget as HTMLElement\n this._pressTarget = target\n\n // 롱클릭 시작: filling 애니메이션\n target.classList.add('saving')\n\n this._longPressTimer = setTimeout(() => {\n this._longPressTimer = undefined\n target.classList.remove('saving')\n this._bookmarkAction('save', index)\n\n // 저장 완료 피드백\n target.classList.add('saved')\n setTimeout(() => target.classList.remove('saved'), 300)\n }, 600)\n }\n\n private _onBookmarkMouseUp() {\n if (this._longPressTimer) {\n clearTimeout(this._longPressTimer)\n this._longPressTimer = undefined\n }\n if (this._pressTarget) {\n this._pressTarget.classList.remove('saving')\n this._pressTarget = undefined\n }\n }\n\n private _bookmarkAction(action: 'save' | 'navigate' | 'clear', index: number) {\n const root = this.scene?.root as any\n const cap = root?._threeCapability\n if (!cap) return\n\n if (action === 'save') {\n cap.saveCameraToSlot(index)\n } else if (action === 'navigate') {\n cap.animateToSlot(index)\n } else if (action === 'clear') {\n cap.bookmarkManager.clearSlot(index)\n root.set('cameraBookmarks', cap.bookmarkManager.exportSlots())\n }\n\n this.requestUpdate()\n }\n\n private _renderRenderer(value: Properties) {\n return html`\n <fieldset>\n <legend>Renderer</legend>\n <div class=\"property-grid\">\n <input id=\"cb-antialias\" type=\"checkbox\" value-key=\"antialias\" .checked=${value.antialias !== false} />\n <label for=\"cb-antialias\">Anti-alias</label>\n\n <label>Precision</label>\n <select value-key=\"precision\">\n ${[\n { value: 'highp', label: 'High' },\n { value: 'mediump', label: 'Medium' },\n { value: 'lowp', label: 'Low' }\n ].map(\n o =>\n html`<option value=${o.value} ?selected=${(value.precision || 'highp') === o.value}>\n ${o.label}\n </option>`\n )}\n </select>\n </div>\n </fieldset>\n `\n }\n\n private _renderSky(value: Properties) {\n const skyOptions = [\n { value: '', label: 'None' },\n { value: 'color', label: 'Color' },\n { value: 'studio', label: 'Studio' },\n { value: 'warehouse', label: 'Warehouse' },\n { value: 'factory', label: 'Factory' },\n { value: 'office', label: 'Office' },\n { value: 'home', label: 'Home' },\n ]\n\n return html`\n <fieldset>\n <legend>Sky</legend>\n <div class=\"property-grid\">\n <label>Preset</label>\n <select value-key=\"sky\">\n ${skyOptions.map(\n o => html`<option value=${o.value} ?selected=${(value.sky || '') === o.value}>${o.label}</option>`\n )}\n </select>\n\n ${value.sky === 'color'\n ? html`\n <label>Color</label>\n <ox-input-color value-key=\"skyColor\" .value=${value.skyColor || '#87ceeb'}> </ox-input-color>\n `\n : ''}\n </div>\n </fieldset>\n `\n }\n\n private _renderHemisphereLight(value: Properties) {\n return html`\n <fieldset>\n <legend>Hemisphere Light</legend>\n <div class=\"property-grid\">\n <label>Intensity</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"3\"\n step=\"0.1\"\n value-key=\"hemiIntensity\"\n .value=${String(value.hemiIntensity ?? 0.6)}\n />\n <span>${(value.hemiIntensity ?? 0.6).toFixed(1)}</span>\n </div>\n </div>\n </fieldset>\n `\n }\n\n private _renderKeyLight(value: Properties) {\n return html`\n <fieldset>\n <legend>Key Light</legend>\n <div class=\"property-grid\">\n <input\n id=\"cb-dirlight\"\n type=\"checkbox\"\n value-key=\"dirLightEnabled\"\n .checked=${value.dirLightEnabled !== false}\n />\n <label for=\"cb-dirlight\">Enabled</label>\n\n <label>Color</label>\n <ox-input-color value-key=\"dirLightColor\" .value=${value.dirLightColor || '#ffffff'}> </ox-input-color>\n\n <label>Intensity</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"3\"\n step=\"0.1\"\n value-key=\"dirLightIntensity\"\n .value=${String(value.dirLightIntensity ?? 0.5)}\n />\n <span>${(value.dirLightIntensity ?? 0.5).toFixed(1)}</span>\n </div>\n </div>\n </fieldset>\n `\n }\n\n private _renderLightingPresets() {\n return html`\n <fieldset>\n <legend>Lighting Presets</legend>\n <div class=\"property-grid\">\n <div class=\"preset-buttons\">\n ${Object.entries(LIGHTING_PRESETS).map(\n ([name, values]) =>\n html`<button @click=${() => this._applyLightingPreset(values)}>${name}</button>`\n )}\n </div>\n </div>\n </fieldset>\n `\n }\n\n private _renderFloor(value: Properties) {\n return html`\n <property-material3d\n legend=\"Floor Material\"\n .value=${value.floorMaterial3d || { receiveShadow: true }}\n @property-change=${this._onFloorMaterialChange}\n >\n </property-material3d>\n `\n }\n\n private _applyLightingPreset(values: Record<string, unknown>) {\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: values\n })\n )\n }\n\n private _onFloorMaterialChange(e: CustomEvent) {\n e.stopPropagation()\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: { floorMaterial3d: e.detail.material3d }\n })\n )\n }\n\n}\n"]}
|
|
1
|
+
{"version":3,"file":"property-scene3d.js","sourceRoot":"","sources":["../../../../src/property-panel/threed/property-scene3d.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/input/ox-input-color.js'\n\nimport './property-material3d.js'\n\nimport { css, html } from 'lit'\nimport { property } from 'lit/decorators.js'\n\nimport { Properties, Scene } from '@hatiolab/things-scene'\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\n\nimport { AbstractProperty } from '../abstract-property.js'\n\nconst LIGHTING_PRESETS: Record<string, Record<string, unknown>> = {\n Neutral: {\n hemiIntensity: 0.6,\n dirLightEnabled: true,\n dirLightColor: '#ffffff',\n dirLightIntensity: 0.5\n },\n Studio: {\n hemiIntensity: 0.5,\n dirLightEnabled: true,\n dirLightColor: '#ffffff',\n dirLightIntensity: 0.6\n },\n Bright: {\n hemiIntensity: 0.8,\n dirLightEnabled: true,\n dirLightColor: '#ffffff',\n dirLightIntensity: 0.7\n },\n Warm: {\n hemiIntensity: 0.5,\n dirLightEnabled: true,\n dirLightColor: '#ffcc88',\n dirLightIntensity: 0.4\n },\n Cool: {\n hemiIntensity: 0.5,\n dirLightEnabled: true,\n dirLightColor: '#cce0ff',\n dirLightIntensity: 0.4\n },\n Flat: {\n hemiIntensity: 0.8,\n dirLightEnabled: false,\n dirLightColor: '#ffffff',\n dirLightIntensity: 0\n }\n}\n\n/**\n * Scene-level 3D settings for model-layer.\n * Includes 3D mode, camera, renderer, lighting, presets, and floor configuration.\n */\nexport class PropertyScene3D extends AbstractProperty {\n static styles = [\n PropertyGridStyles,\n css`\n .preset-buttons {\n grid-column: 1 / -1;\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n padding: 2px 0;\n }\n\n .preset-buttons button {\n flex: 1;\n min-width: 60px;\n padding: 4px 6px;\n border: 1px solid var(--md-sys-color-outline, #ccc);\n border-radius: 4px;\n background: var(--md-sys-color-surface, #fff);\n color: var(--md-sys-color-on-surface, #333);\n font-size: 11px;\n cursor: pointer;\n }\n\n .preset-buttons button:hover {\n background: var(--md-sys-color-primary-container, #e0e0e0);\n }\n\n .range-with-value {\n grid-column: 9 / -1;\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .range-with-value input[type='range'] {\n flex: 1;\n border: none;\n background: transparent;\n padding: 0;\n }\n\n .range-with-value span {\n min-width: 2.5em;\n text-align: right;\n font-size: 11px;\n color: var(--md-sys-color-on-secondary-container);\n }\n\n .bookmark-slots {\n grid-column: 1 / -1;\n display: grid;\n grid-template-columns: repeat(9, 1fr);\n gap: 2px;\n padding: 4px 0 0;\n }\n\n .bookmark-slot {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 24px;\n border-radius: 3px;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n color: var(--md-sys-color-outline, #999);\n background: var(--md-sys-color-surface-variant, #f0f0f0);\n border: 1px solid transparent;\n user-select: none;\n transition: all 0.12s ease;\n }\n\n .bookmark-slot:hover {\n background: var(--md-sys-color-secondary-container, #e0e0e0);\n }\n\n .bookmark-slot.filled {\n color: var(--md-sys-color-primary, #6750A4);\n background: var(--md-sys-color-primary-container, #EADDFF);\n border-color: var(--md-sys-color-primary, #6750A4);\n font-weight: 700;\n }\n\n .bookmark-slot:active {\n transform: scale(0.9);\n }\n\n .bookmark-slot.saving {\n animation: bookmark-fill 0.6s linear forwards;\n }\n\n @keyframes bookmark-fill {\n from { box-shadow: inset 24px 0 0 0 transparent; }\n to { box-shadow: inset 24px 0 0 0 var(--md-sys-color-primary-container, #EADDFF); }\n }\n\n .bookmark-slot.saved {\n animation: bookmark-saved 0.3s ease;\n }\n\n @keyframes bookmark-saved {\n 0% { transform: scale(1); }\n 50% { transform: scale(1.2); }\n 100% { transform: scale(1); }\n }\n `\n ]\n\n @property({ type: Object }) value?: Properties\n @property({ type: Object }) scene: Scene | null = null\n\n render() {\n const value = this.value || {}\n\n return html`\n ${this._renderMode(value)} ${this._renderBookmarks(value)} ${this._renderRenderer(value)}\n ${this._renderSky(value)}\n ${this._renderHemisphereLight(value)} ${this._renderKeyLight(value)} ${this._renderLightingPresets()}\n ${this._renderFloor(value)}\n `\n }\n\n private _renderMode(value: Properties) {\n return html`\n <fieldset>\n <legend>3D Mode</legend>\n <div class=\"property-grid\">\n <input id=\"cb-threed\" type=\"checkbox\" value-key=\"threed\" .checked=${!!value.threed} />\n <label for=\"cb-threed\">Enable 3D</label>\n\n <label>Viewer Auto</label>\n <select value-key=\"cameraAutoPlay\">\n ${[\n { value: '', label: 'None' },\n { value: 'orbit', label: 'Orbit' },\n { value: 'play', label: 'Play Bookmarks' }\n ].map(\n o =>\n html`<option value=${o.value} ?selected=${(value.cameraAutoPlay || '') === o.value}>\n ${o.label}\n </option>`\n )}\n </select>\n\n <input\n id=\"cb-floor-constraint\"\n type=\"checkbox\"\n value-key=\"cameraFloorConstraint\"\n .checked=${!!value.cameraFloorConstraint}\n />\n <label for=\"cb-floor-constraint\">Floor Constraint (Viewer)</label>\n </div>\n </fieldset>\n `\n }\n\n private _renderBookmarks(value: Properties) {\n const bookmarks: (any | null)[] = value.cameraBookmarks || []\n\n return html`\n <fieldset>\n <legend>Bookmarks</legend>\n <div class=\"property-grid\">\n <div class=\"bookmark-slots\">\n ${[1, 2, 3, 4, 5, 6, 7, 8, 9].map(i => {\n const filled = !!bookmarks[i]\n return html`\n <div\n class=\"bookmark-slot ${filled ? 'filled' : ''}\"\n title=${filled ? 'Click: Go / Long-click: Overwrite / Right-click: Delete' : 'Long-click: Save current camera'}\n @click=${(e: MouseEvent) => { if (filled) { this._bookmarkAction('navigate', i); const t = e.currentTarget as HTMLElement; t.classList.add('saved'); setTimeout(() => t.classList.remove('saved'), 300) } }}\n @contextmenu=${(e: Event) => { e.preventDefault(); if (filled) this._bookmarkAction('clear', i) }}\n @mousedown=${(e: MouseEvent) => this._onBookmarkMouseDown(e, i)}\n @mouseup=${() => this._onBookmarkMouseUp()}\n @mouseleave=${() => this._onBookmarkMouseUp()}\n >${i}</div>\n `\n })}\n </div>\n </div>\n </fieldset>\n `\n }\n\n private _longPressTimer?: ReturnType<typeof setTimeout>\n private _pressTarget?: HTMLElement\n\n private _onBookmarkMouseDown(e: MouseEvent, index: number) {\n if (e.button !== 0) return\n const target = e.currentTarget as HTMLElement\n this._pressTarget = target\n\n // 롱클릭 시작: filling 애니메이션\n target.classList.add('saving')\n\n this._longPressTimer = setTimeout(() => {\n this._longPressTimer = undefined\n target.classList.remove('saving')\n this._bookmarkAction('save', index)\n\n // 저장 완료 피드백\n target.classList.add('saved')\n setTimeout(() => target.classList.remove('saved'), 300)\n }, 600)\n }\n\n private _onBookmarkMouseUp() {\n if (this._longPressTimer) {\n clearTimeout(this._longPressTimer)\n this._longPressTimer = undefined\n }\n if (this._pressTarget) {\n this._pressTarget.classList.remove('saving')\n this._pressTarget = undefined\n }\n }\n\n private _bookmarkAction(action: 'save' | 'navigate' | 'clear', index: number) {\n const root = this.scene?.root as any\n const cap = root?._threeCapability\n if (!cap) return\n\n if (action === 'save') {\n cap.saveCameraToSlot(index)\n } else if (action === 'navigate') {\n cap.animateToSlot(index)\n } else if (action === 'clear') {\n cap.bookmarkManager.clearSlot(index)\n root.set('cameraBookmarks', cap.bookmarkManager.exportSlots())\n }\n\n this.requestUpdate()\n }\n\n private _renderRenderer(value: Properties) {\n return html`\n <fieldset>\n <legend>Renderer</legend>\n <div class=\"property-grid\">\n <input id=\"cb-antialias\" type=\"checkbox\" value-key=\"antialias\" .checked=${value.antialias !== false} />\n <label for=\"cb-antialias\">Anti-alias</label>\n\n <label>Precision</label>\n <select value-key=\"precision\">\n ${[\n { value: 'highp', label: 'High' },\n { value: 'mediump', label: 'Medium' },\n { value: 'lowp', label: 'Low' }\n ].map(\n o =>\n html`<option value=${o.value} ?selected=${(value.precision || 'highp') === o.value}>\n ${o.label}\n </option>`\n )}\n </select>\n </div>\n </fieldset>\n `\n }\n\n private _renderSky(value: Properties) {\n const skyOptions = [\n { value: '', label: 'None' },\n { value: 'color', label: 'Color' },\n { value: 'studio', label: 'Studio' },\n { value: 'warehouse', label: 'Warehouse' },\n { value: 'factory', label: 'Factory' },\n { value: 'office', label: 'Office' },\n { value: 'home', label: 'Home' },\n ]\n\n return html`\n <fieldset>\n <legend>Sky</legend>\n <div class=\"property-grid\">\n <label>Preset</label>\n <select value-key=\"sky\">\n ${skyOptions.map(\n o => html`<option value=${o.value} ?selected=${(value.sky || '') === o.value}>${o.label}</option>`\n )}\n </select>\n\n ${value.sky === 'color'\n ? html`\n <label>Color</label>\n <ox-input-color value-key=\"skyColor\" .value=${value.skyColor || '#87ceeb'}> </ox-input-color>\n `\n : ''}\n </div>\n </fieldset>\n `\n }\n\n private _renderHemisphereLight(value: Properties) {\n return html`\n <fieldset>\n <legend>Hemisphere Light</legend>\n <div class=\"property-grid\">\n <label>Intensity</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"3\"\n step=\"0.1\"\n value-key=\"hemiIntensity\"\n .value=${String(value.hemiIntensity ?? 0.6)}\n />\n <span>${(value.hemiIntensity ?? 0.6).toFixed(1)}</span>\n </div>\n </div>\n </fieldset>\n `\n }\n\n private _renderKeyLight(value: Properties) {\n return html`\n <fieldset>\n <legend>Key Light</legend>\n <div class=\"property-grid\">\n <input\n id=\"cb-dirlight\"\n type=\"checkbox\"\n value-key=\"dirLightEnabled\"\n .checked=${value.dirLightEnabled !== false}\n />\n <label for=\"cb-dirlight\">Enabled</label>\n\n <label>Color</label>\n <ox-input-color value-key=\"dirLightColor\" .value=${value.dirLightColor || '#ffffff'}> </ox-input-color>\n\n <label>Intensity</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"3\"\n step=\"0.1\"\n value-key=\"dirLightIntensity\"\n .value=${String(value.dirLightIntensity ?? 0.5)}\n />\n <span>${(value.dirLightIntensity ?? 0.5).toFixed(1)}</span>\n </div>\n </div>\n </fieldset>\n `\n }\n\n private _renderLightingPresets() {\n return html`\n <fieldset>\n <legend>Lighting Presets</legend>\n <div class=\"property-grid\">\n <div class=\"preset-buttons\">\n ${Object.entries(LIGHTING_PRESETS).map(\n ([name, values]) =>\n html`<button @click=${() => this._applyLightingPreset(values)}>${name}</button>`\n )}\n </div>\n </div>\n </fieldset>\n `\n }\n\n private _renderFloor(value: Properties) {\n return html`\n <property-material3d\n legend=\"Floor Material\"\n .value=${value.floorMaterial3d || { receiveShadow: true }}\n @property-change=${this._onFloorMaterialChange}\n >\n </property-material3d>\n `\n }\n\n private _applyLightingPreset(values: Record<string, unknown>) {\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: values\n })\n )\n }\n\n private _onFloorMaterialChange(e: CustomEvent) {\n e.stopPropagation()\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: { floorMaterial3d: e.detail.material3d }\n })\n )\n }\n\n}\n"]}
|