diff --git a/src/assets/images/backgrounds/lake.webp b/src/assets/images/backgrounds/lake.webp
new file mode 100644
index 00000000..f9ca2397
Binary files /dev/null and b/src/assets/images/backgrounds/lake.webp differ
diff --git a/src/assets/images/generic/hyde.jpg b/src/assets/images/generic/hyde.jpg
deleted file mode 100644
index 5d64a36c..00000000
Binary files a/src/assets/images/generic/hyde.jpg and /dev/null differ
diff --git a/src/assets/images/generic/hyde.webp b/src/assets/images/generic/hyde.webp
new file mode 100644
index 00000000..dbcdd44b
Binary files /dev/null and b/src/assets/images/generic/hyde.webp differ
diff --git a/src/components/CanvasEditor/CanvasEditorTools.vue b/src/components/CanvasEditor/CanvasEditorTools.vue
index 8f39b75d..3f06dd72 100644
--- a/src/components/CanvasEditor/CanvasEditorTools.vue
+++ b/src/components/CanvasEditor/CanvasEditorTools.vue
@@ -1,9 +1,9 @@
+
+
+
+
+
+
diff --git a/src/components/DrawingToolbar/index.ts b/src/components/DrawingToolbar/index.ts
new file mode 100644
index 00000000..027644d0
--- /dev/null
+++ b/src/components/DrawingToolbar/index.ts
@@ -0,0 +1,2 @@
+export { default as DrawingToolbar } from './DrawingToolbar.vue'
+export type { DrawingTool, DrawingToolbarButton } from './DrawingToolbar.vue'
diff --git a/src/components/panels/ConfigControls.vue b/src/components/panels/ConfigControls.vue
index 2540e98b..576b6c07 100644
--- a/src/components/panels/ConfigControls.vue
+++ b/src/components/panels/ConfigControls.vue
@@ -27,7 +27,7 @@ const props = defineProps<{
}>()
const isControlSchema = (object: any): object is ControlSchema => {
- if (typeof object !== 'object' || object === null) return false
+ if (typeof object !== 'object' || object === null || Array.isArray(object)) return false
const keys = Object.keys(object)
const controlKeys = [
'min',
@@ -83,6 +83,7 @@ const groups = computed(() => {
const controls: { key: string; path: string; schema: ControlSchema }[] = []
Object.entries(props.schema).forEach(([key, value]) => {
+ if (key.startsWith('__')) return
if (isControlSchema(value)) {
controls.push({ key, path: getFullPath(key), schema: value })
} else {
@@ -93,8 +94,11 @@ const groups = computed(() => {
return { groups: result, controls }
})
-// All group keys for default-open accordion
-const defaultOpenGroups = computed(() => groups.value.groups.map((g) => g.key))
+const defaultOpenGroups = computed(() => {
+ const meta = (props.schema as Record)['__defaultOpenGroups']
+ if (!props.basePath && Array.isArray(meta)) return meta as string[]
+ return groups.value.groups.map((g) => g.key)
+})
const handleSliderUpdate = (path: string, value: number[]) => {
props.onUpdate(path, value[0])
@@ -357,7 +361,6 @@ const handleButtonSelectorUpdate = (path: string, value: string) => {
diff --git a/src/views/Experiments/TexturePainter/config.ts b/src/views/Experiments/TexturePainter/config.ts
new file mode 100644
index 00000000..b39b6443
--- /dev/null
+++ b/src/views/Experiments/TexturePainter/config.ts
@@ -0,0 +1,84 @@
+export {
+ MATERIAL_TYPES,
+ MAIN_MATERIAL_TYPES,
+ MATERIAL_LABELS,
+ MATERIAL_FEATURES,
+ DEFAULT_CONFIG,
+ CONFIG_SCHEMA,
+ getEnabledMaps,
+ SPHERE_SEGMENT_COUNT,
+ PROCEDURAL_TEXTURE_SIZE,
+ BRICK_WIDTH,
+ BRICK_HEIGHT,
+ MORTAR_SIZE,
+ MORTAR_EDGE_OFFSET,
+ MORTAR_EDGE_SIZE,
+ SCENE_BG_COLOR,
+ LIGHT_INTENSITY,
+ AMBIENT_LIGHT_INTENSITY,
+ HEMISPHERE_SKY,
+ HEMISPHERE_GROUND,
+ LIGHT_ORBIT_RADIUS,
+ LIGHT_Z_POSITION,
+ ENV_SKY_COLOR,
+ ENV_GROUND_COLOR,
+ ENV_GROUND_SIZE,
+ ENV_GROUND_Y,
+ ENV_LIGHT_INTENSITY,
+ ENV_LIGHT_POSITION,
+ ENV_LIGHT_Y,
+ ENV_AMBIENT_COLOR,
+ ENV_AMBIENT_INTENSITY,
+ ENV_LIGHT_COLOR
+} from '@/views/Experiments/MaterialsList/materialsListConfig'
+
+export type { MaterialTypeName, MaterialsListConfig } from '@/views/Experiments/MaterialsList/types'
+
+export const PAINTER_SPHERE_RADIUS = 2.5
+export const PAINTER_CANVAS_SIZE = 512
+export const PAINTER_LIGHT_ORBIT_SPEED = 0.3
+export const PAINTER_TARGET_FPS = 60
+export const PAINTER_ORTHO_FRUSTUM = 5.0
+export const PAINTER_ORTHO_NEAR = 0.1
+export const PAINTER_ORTHO_FAR = 100
+export const PAINTER_ORTHO_DISTANCE = 20
+
+export const STORAGE_PREFIX = 'texture-painter'
+
+export type TextureSlotKey = 'diffuse' | 'normal' | 'roughness' | 'ao' | 'displacement' | 'emissive'
+
+export const TEXTURE_SLOTS: TextureSlotKey[] = [
+ 'diffuse',
+ 'normal',
+ 'roughness',
+ 'ao',
+ 'displacement',
+ 'emissive'
+]
+
+export const TEXTURE_SLOT_LABELS: Record = {
+ diffuse: 'Diffuse',
+ normal: 'Normal',
+ roughness: 'Roughness',
+ ao: 'Ambient Occlusion',
+ displacement: 'Displacement',
+ emissive: 'Emissive'
+}
+
+export const TEXTURE_SLOT_PALETTE: Record = {
+ diffuse: ['#cc8866', '#884433', '#ffffff', '#000000'],
+ normal: ['#8080ff', '#404080', '#ffffff'],
+ roughness: ['#ffffff', '#000000', '#888888'],
+ ao: ['#ffffff', '#000000', 'rgba(0,0,0,0.4)'],
+ displacement: ['#cccccc', '#000000', '#ffffff'],
+ emissive: ['#ff6600', '#000000', '#ff3300']
+}
+
+export const TEXTURE_SLOT_DEFAULT_COLOR: Record = {
+ diffuse: '#cc8866',
+ normal: '#8080ff',
+ roughness: '#ffffff',
+ ao: '#ffffff',
+ displacement: '#cccccc',
+ emissive: '#ff6600'
+}