@tableslayer/ui 0.1.3 → 0.1.4
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/package.json +2 -13
- package/src/lib/components/Avatar/Avatar.svelte +82 -0
- package/src/lib/components/Avatar/AvatarFileInput.svelte +85 -0
- package/src/lib/components/Avatar/AvatarPopover.svelte +34 -0
- package/src/lib/components/Avatar/index.ts +4 -0
- package/src/lib/components/Avatar/types.ts +24 -0
- package/src/lib/components/BrushSizeSlider/BrushSizeSlider.svelte +174 -0
- package/src/lib/components/BrushSizeSlider/index.ts +1 -0
- package/src/lib/components/Button/Button.svelte +182 -0
- package/src/lib/components/Button/ConfirmActionButton.svelte +98 -0
- package/src/lib/components/Button/IconButton.svelte +121 -0
- package/src/lib/components/Button/RadioButton.svelte +93 -0
- package/src/lib/components/Button/index.ts +5 -0
- package/src/lib/components/Button/types.ts +54 -0
- package/src/lib/components/CardFan/CardFan.svelte +165 -0
- package/src/lib/components/CardFan/index.ts +2 -0
- package/src/lib/components/CardFan/types.ts +6 -0
- package/src/lib/components/CodeBlock/Code.svelte +7 -0
- package/src/lib/components/CodeBlock/CodeBlock.svelte +102 -0
- package/src/lib/components/CodeBlock/index.ts +3 -0
- package/src/lib/components/CodeBlock/types.ts +10 -0
- package/src/lib/components/ColorMode/ColorMode.svelte +8 -0
- package/src/lib/components/ColorMode/index.ts +2 -0
- package/src/lib/components/ColorMode/types.ts +12 -0
- package/src/lib/components/ColorPicker/ColorPicker.svelte +838 -0
- package/src/lib/components/ColorPicker/ColorPickerSwatch.svelte +32 -0
- package/src/lib/components/ColorPicker/index.ts +3 -0
- package/src/lib/components/ColorPicker/types.ts +51 -0
- package/src/lib/components/ContextMenu/ContextMenu.svelte +86 -0
- package/src/lib/components/ContextMenu/index.ts +2 -0
- package/src/lib/components/ContextMenu/types.ts +15 -0
- package/src/lib/components/DrawingSliders/DrawingSliders.svelte +379 -0
- package/src/lib/components/DrawingSliders/index.ts +1 -0
- package/src/lib/components/Editor/Editor.svelte +825 -0
- package/src/lib/components/Editor/index.ts +1 -0
- package/src/lib/components/FogSliders/FogSliders.svelte +33 -0
- package/src/lib/components/FogSliders/index.ts +1 -0
- package/src/lib/components/Hr/Hr.svelte +15 -0
- package/src/lib/components/Hr/index.ts +1 -0
- package/src/lib/components/Icon/Icon.svelte +6 -0
- package/src/lib/components/Icon/index.ts +2 -0
- package/src/lib/components/Icon/types.ts +20 -0
- package/src/lib/components/Input/DualInputSlider.svelte +126 -0
- package/src/lib/components/Input/FileInput.svelte +176 -0
- package/src/lib/components/Input/FormControl.svelte +150 -0
- package/src/lib/components/Input/FormError.svelte +37 -0
- package/src/lib/components/Input/Input.svelte +56 -0
- package/src/lib/components/Input/InputCheckbox.svelte +99 -0
- package/src/lib/components/Input/InputSlider.svelte +86 -0
- package/src/lib/components/Input/Label.svelte +19 -0
- package/src/lib/components/Input/index.ts +9 -0
- package/src/lib/components/Input/types.ts +39 -0
- package/src/lib/components/Link/Link.svelte +41 -0
- package/src/lib/components/Link/LinkBox.svelte +20 -0
- package/src/lib/components/Link/LinkOverlay.svelte +23 -0
- package/src/lib/components/Link/index.ts +4 -0
- package/src/lib/components/Link/types.ts +17 -0
- package/src/lib/components/Loading/Loader.svelte +60 -0
- package/src/lib/components/Loading/Skeleton.svelte +9 -0
- package/src/lib/components/Loading/index.ts +2 -0
- package/src/lib/components/Logo/Logo.svelte +16 -0
- package/src/lib/components/Logo/index.ts +1 -0
- package/src/lib/components/MarkerTooltip/MarkerTooltip.svelte +435 -0
- package/src/lib/components/MarkerTooltip/index.ts +1 -0
- package/src/lib/components/Menu/SelectorMenu.svelte +280 -0
- package/src/lib/components/Menu/index.ts +2 -0
- package/src/lib/components/Menu/types.ts +17 -0
- package/src/lib/components/MyCounterButton.svelte +11 -0
- package/src/lib/components/Panel/index.ts +2 -0
- package/src/lib/components/Panel/panel.svelte +18 -0
- package/src/lib/components/Panel/types.ts +8 -0
- package/src/lib/components/PersistButton/PersistButton.svelte +100 -0
- package/src/lib/components/PersistButton/index.ts +1 -0
- package/src/lib/components/Popover/Popover.svelte +81 -0
- package/src/lib/components/Popover/index.ts +2 -0
- package/src/lib/components/Popover/types.ts +19 -0
- package/src/lib/components/PropsTable/PropsTable.svelte +107 -0
- package/src/lib/components/RadialMenu/EffectPreview.svelte +36 -0
- package/src/lib/components/RadialMenu/EffectPreviewScene.svelte +194 -0
- package/src/lib/components/RadialMenu/RadialMenu.svelte +503 -0
- package/src/lib/components/RadialMenu/RadialMenuItem.svelte +176 -0
- package/src/lib/components/RadialMenu/index.ts +2 -0
- package/src/lib/components/RadialMenu/types.ts +35 -0
- package/src/lib/components/Select/Select.svelte +342 -0
- package/src/lib/components/Select/index.ts +2 -0
- package/src/lib/components/Select/types.ts +22 -0
- package/src/lib/components/Spacer/Spacer.svelte +14 -0
- package/src/lib/components/Spacer/index.ts +2 -0
- package/src/lib/components/Spacer/types.ts +5 -0
- package/src/lib/components/Stage/components/AnnotationLayer/AnnotationLayer.svelte +445 -0
- package/src/lib/components/Stage/components/AnnotationLayer/AnnotationMaterial.svelte +167 -0
- package/src/lib/components/Stage/components/AnnotationLayer/types.ts +196 -0
- package/src/lib/components/Stage/components/CursorLayer/CursorLayer.svelte +148 -0
- package/src/lib/components/Stage/components/CursorLayer/cursor.svg +26 -0
- package/src/lib/components/Stage/components/CursorLayer/index.ts +2 -0
- package/src/lib/components/Stage/components/CursorLayer/types.ts +23 -0
- package/src/lib/components/Stage/components/DrawingLayer/DrawingMaterial.svelte +364 -0
- package/src/lib/components/Stage/components/DrawingLayer/types.ts +65 -0
- package/src/lib/components/Stage/components/EdgeOverlayLayer/EdgeOverlayLayer.svelte +72 -0
- package/src/lib/components/Stage/components/EdgeOverlayLayer/types.ts +34 -0
- package/src/lib/components/Stage/components/FogLayer/FogLayer.svelte +75 -0
- package/src/lib/components/Stage/components/FogLayer/types.ts +51 -0
- package/src/lib/components/Stage/components/FogOfWarLayer/FogOfWarLayer.svelte +249 -0
- package/src/lib/components/Stage/components/FogOfWarLayer/FogOfWarMaterial.svelte +200 -0
- package/src/lib/components/Stage/components/FogOfWarLayer/types.ts +116 -0
- package/src/lib/components/Stage/components/GridLayer/GridLayer.svelte +20 -0
- package/src/lib/components/Stage/components/GridLayer/GridMaterial.svelte +69 -0
- package/src/lib/components/Stage/components/GridLayer/types.ts +79 -0
- package/src/lib/components/Stage/components/LayerInput/LayerInput.svelte +300 -0
- package/src/lib/components/Stage/components/MapLayer/MapLayer.svelte +196 -0
- package/src/lib/components/Stage/components/MapLayer/dataSources/GifDataSource.ts +265 -0
- package/src/lib/components/Stage/components/MapLayer/dataSources/IMapDataSource.ts +55 -0
- package/src/lib/components/Stage/components/MapLayer/dataSources/ImageDataSource.ts +87 -0
- package/src/lib/components/Stage/components/MapLayer/dataSources/VideoDataSource.ts +150 -0
- package/src/lib/components/Stage/components/MapLayer/dataSources/dataSourceFactory.ts +48 -0
- package/src/lib/components/Stage/components/MapLayer/dataSources/index.ts +16 -0
- package/src/lib/components/Stage/components/MapLayer/types.ts +58 -0
- package/src/lib/components/Stage/components/MarkerLayer/MarkerLayer.svelte +398 -0
- package/src/lib/components/Stage/components/MarkerLayer/MarkerToken.svelte +262 -0
- package/src/lib/components/Stage/components/MarkerLayer/types.ts +126 -0
- package/src/lib/components/Stage/components/MeasurementLayer/MeasurementLayer.svelte +364 -0
- package/src/lib/components/Stage/components/MeasurementLayer/MeasurementManager.svelte +473 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/BaseMeasurement.ts +427 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/BeamMeasurement.ts +105 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/CircleMeasurement.ts +98 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/ConeMeasurement.ts +163 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/LineMeasurement.ts +102 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/RectangleMeasurement.ts +120 -0
- package/src/lib/components/Stage/components/MeasurementLayer/measurements/index.ts +7 -0
- package/src/lib/components/Stage/components/MeasurementLayer/types.ts +94 -0
- package/src/lib/components/Stage/components/MeasurementLayer/utils/canvasDrawing.ts +357 -0
- package/src/lib/components/Stage/components/MeasurementLayer/utils/distanceCalculations.ts +170 -0
- package/src/lib/components/Stage/components/ParticleSystem/ParticleSystem.svelte +220 -0
- package/src/lib/components/Stage/components/ParticleSystem/particles/atlases/ash.png +0 -0
- package/src/lib/components/Stage/components/ParticleSystem/particles/atlases/leaves.png +0 -0
- package/src/lib/components/Stage/components/ParticleSystem/particles/atlases/rain.png +0 -0
- package/src/lib/components/Stage/components/ParticleSystem/particles/atlases/snow.png +0 -0
- package/src/lib/components/Stage/components/ParticleSystem/rng.js +20 -0
- package/src/lib/components/Stage/components/ParticleSystem/types.ts +95 -0
- package/src/lib/components/Stage/components/PerformanceDebugger/PerformanceDebugger.svelte +144 -0
- package/src/lib/components/Stage/components/PerformanceDebugger/index.ts +1 -0
- package/src/lib/components/Stage/components/PerformanceOverlay/PerformanceOverlay.svelte +208 -0
- package/src/lib/components/Stage/components/PerformanceOverlay/index.ts +1 -0
- package/src/lib/components/Stage/components/PointerInputManager/PointerInputManager.svelte +201 -0
- package/src/lib/components/Stage/components/Scene/Scene.svelte +651 -0
- package/src/lib/components/Stage/components/Scene/luts.ts +24 -0
- package/src/lib/components/Stage/components/Scene/types.ts +225 -0
- package/src/lib/components/Stage/components/Stage/Stage.svelte +332 -0
- package/src/lib/components/Stage/components/Stage/types.ts +136 -0
- package/src/lib/components/Stage/components/WeatherLayer/WeatherLayer.svelte +135 -0
- package/src/lib/components/Stage/components/WeatherLayer/presets/AshPreset.ts +71 -0
- package/src/lib/components/Stage/components/WeatherLayer/presets/LeavesPreset.ts +70 -0
- package/src/lib/components/Stage/components/WeatherLayer/presets/RainPreset.ts +68 -0
- package/src/lib/components/Stage/components/WeatherLayer/presets/SnowPreset.ts +70 -0
- package/src/lib/components/Stage/components/WeatherLayer/presets/index.ts +6 -0
- package/src/lib/components/Stage/components/WeatherLayer/types.ts +35 -0
- package/src/lib/components/Stage/helpers/clippingPlaneStore.svelte.ts +28 -0
- package/src/lib/components/Stage/helpers/debugState.svelte.ts +18 -0
- package/src/lib/components/Stage/helpers/grid.ts +548 -0
- package/src/lib/components/Stage/helpers/lazyBrush.ts +171 -0
- package/src/lib/components/Stage/helpers/performanceMetrics.svelte.ts +220 -0
- package/src/lib/components/Stage/helpers/utils.ts +21 -0
- package/src/lib/components/Stage/index.ts +49 -0
- package/src/lib/components/Stage/shaders/AnnotationEffects.frag +1070 -0
- package/src/lib/components/Stage/shaders/Annotations.frag +29 -0
- package/src/lib/components/Stage/shaders/Drawing.frag +83 -0
- package/src/lib/components/Stage/shaders/Drawing.vert +5 -0
- package/src/lib/components/Stage/shaders/Fog.frag +147 -0
- package/src/lib/components/Stage/shaders/FractalNoise.frag +96 -0
- package/src/lib/components/Stage/shaders/GridShader.frag +174 -0
- package/src/lib/components/Stage/shaders/Overlay.frag +23 -0
- package/src/lib/components/Stage/shaders/Overlay.vert +0 -0
- package/src/lib/components/Stage/shaders/Particles.frag +27 -0
- package/src/lib/components/Stage/shaders/Particles.vert +51 -0
- package/src/lib/components/Stage/shaders/ToolOutline.frag +59 -0
- package/src/lib/components/Stage/shaders/default.vert +8 -0
- package/src/lib/components/Stage/types.ts +4 -0
- package/src/lib/components/Table/Table.svelte +16 -0
- package/src/lib/components/Table/Td.svelte +17 -0
- package/src/lib/components/Table/Th.svelte +18 -0
- package/src/lib/components/Table/index.ts +4 -0
- package/src/lib/components/Table/types.ts +14 -0
- package/src/lib/components/Text/Text.svelte +23 -0
- package/src/lib/components/Text/index.ts +2 -0
- package/src/lib/components/Text/types.ts +12 -0
- package/src/lib/components/Title/Title.svelte +54 -0
- package/src/lib/components/Title/index.ts +2 -0
- package/src/lib/components/Title/types.ts +9 -0
- package/src/lib/components/Toast/Toast.svelte +155 -0
- package/src/lib/components/Toast/index.ts +5 -0
- package/src/lib/components/Toast/toastCookie.ts +24 -0
- package/src/lib/components/Toast/types.ts +6 -0
- package/src/lib/components/ToolTip/ToolTip.svelte +70 -0
- package/src/lib/components/ToolTip/index.ts +2 -0
- package/src/lib/components/ToolTip/types.ts +14 -0
- package/src/lib/components/index.ts +32 -0
- package/src/lib/components/types.ts +0 -0
- package/src/lib/index.ts +2 -0
- package/src/lib/styles/globals.css +108 -0
- package/src/lib/styles/normalize.css +9 -0
- package/src/lib/styles/reset.css +133 -0
- package/src/lib/styles/utilities.css +179 -0
- package/src/lib/styles/vars.css +1103 -0
- package/src/lib/types/awareness.ts +17 -0
- package/src/lib/utils/rle.ts +217 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
import { T, useTask, useLoader } from '@threlte/core';
|
|
4
|
+
import { ParticleData } from './types';
|
|
5
|
+
import type { ParticleSystemProps } from './types';
|
|
6
|
+
import { RNG } from './rng';
|
|
7
|
+
|
|
8
|
+
import fragmentShader from '../../shaders/Particles.frag?raw';
|
|
9
|
+
import vertexShader from '../../shaders/Particles.vert?raw';
|
|
10
|
+
import { DEG2RAD } from 'three/src/math/MathUtils';
|
|
11
|
+
import { onDestroy, untrack } from 'svelte';
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
props: ParticleSystemProps;
|
|
15
|
+
opacity?: number;
|
|
16
|
+
intensity?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const { props, opacity, intensity }: Props = $props();
|
|
20
|
+
|
|
21
|
+
let mesh: THREE.Mesh | undefined = $state(undefined);
|
|
22
|
+
let geometry: THREE.BufferGeometry | undefined = $state(undefined);
|
|
23
|
+
|
|
24
|
+
$effect.pre(() => {
|
|
25
|
+
const rng = new RNG(0);
|
|
26
|
+
const count = Math.round(props.maxParticleCount * (intensity ?? 1));
|
|
27
|
+
|
|
28
|
+
// Initialize particle attributes - 4 vertices per quad
|
|
29
|
+
const positions = new Float32Array(count * 12); // 4 vertices * 3 coords
|
|
30
|
+
const centers = new Float32Array(count * 8); // 1 center * 2 coords
|
|
31
|
+
const uvs = new Float32Array(count * 8); // 4 vertices * 2 coords
|
|
32
|
+
const indices = new Uint32Array(count * 6); // 2 triangles * 3 vertices
|
|
33
|
+
const ageOffsets = new Float32Array(count * 4); // 4 vertices
|
|
34
|
+
|
|
35
|
+
const particle = ParticleData[props.type];
|
|
36
|
+
|
|
37
|
+
// Initialize particles
|
|
38
|
+
for (let i = 0; i < count; i++) {
|
|
39
|
+
const radius = rng.random() * (props.spawnArea.maxRadius - props.spawnArea.minRadius) + props.spawnArea.minRadius;
|
|
40
|
+
const angle = rng.random() * 2 * Math.PI;
|
|
41
|
+
const x = radius * Math.cos(angle);
|
|
42
|
+
const y = radius * Math.sin(angle);
|
|
43
|
+
const z = -1.001;
|
|
44
|
+
|
|
45
|
+
// Quad vertex positions (same for all 4 corners initially)
|
|
46
|
+
const baseIdx = i * 12;
|
|
47
|
+
|
|
48
|
+
// Generate random size for this particle
|
|
49
|
+
let size = rng.random() * (props.size.max - props.size.min) + props.size.min;
|
|
50
|
+
let width = size * props.scale.x;
|
|
51
|
+
let height = size * props.scale.y;
|
|
52
|
+
|
|
53
|
+
const rotation = new THREE.Euler(0, 0, props.rotation.offset * DEG2RAD);
|
|
54
|
+
rotation.z += props.rotation.alignRadially ? angle : 0;
|
|
55
|
+
rotation.z += props.rotation.randomize ? rng.random() * 360 : 0;
|
|
56
|
+
|
|
57
|
+
const v1 = new THREE.Vector3(-width / 2, -height / 2, 0);
|
|
58
|
+
const v2 = new THREE.Vector3(width / 2, -height / 2, 0);
|
|
59
|
+
const v3 = new THREE.Vector3(-width / 2, height / 2, 0);
|
|
60
|
+
const v4 = new THREE.Vector3(width / 2, height / 2, 0);
|
|
61
|
+
|
|
62
|
+
v1.applyEuler(rotation);
|
|
63
|
+
v2.applyEuler(rotation);
|
|
64
|
+
v3.applyEuler(rotation);
|
|
65
|
+
v4.applyEuler(rotation);
|
|
66
|
+
|
|
67
|
+
v1.add(new THREE.Vector3(x, y, z));
|
|
68
|
+
v2.add(new THREE.Vector3(x, y, z));
|
|
69
|
+
v3.add(new THREE.Vector3(x, y, z));
|
|
70
|
+
v4.add(new THREE.Vector3(x, y, z));
|
|
71
|
+
|
|
72
|
+
// Set quad corners with size offset
|
|
73
|
+
positions[baseIdx] = v1.x; // Bottom left x
|
|
74
|
+
positions[baseIdx + 1] = v1.y; // Bottom left y
|
|
75
|
+
positions[baseIdx + 2] = v1.z; // Bottom left z
|
|
76
|
+
|
|
77
|
+
positions[baseIdx + 3] = v2.x; // Bottom right x
|
|
78
|
+
positions[baseIdx + 4] = v2.y; // Bottom right y
|
|
79
|
+
positions[baseIdx + 5] = v2.z; // Bottom right z
|
|
80
|
+
|
|
81
|
+
positions[baseIdx + 6] = v3.x; // Top left x
|
|
82
|
+
positions[baseIdx + 7] = v3.y; // Top left y
|
|
83
|
+
positions[baseIdx + 8] = v3.z; // Top left z
|
|
84
|
+
|
|
85
|
+
positions[baseIdx + 9] = v4.x; // Top right x
|
|
86
|
+
positions[baseIdx + 10] = v4.y; // Top right y
|
|
87
|
+
positions[baseIdx + 11] = v4.z; // Top right z
|
|
88
|
+
|
|
89
|
+
// Set center position
|
|
90
|
+
const centerIdx = i * 8;
|
|
91
|
+
centers[centerIdx] = x;
|
|
92
|
+
centers[centerIdx + 1] = y;
|
|
93
|
+
centers[centerIdx + 2] = x;
|
|
94
|
+
centers[centerIdx + 3] = y;
|
|
95
|
+
centers[centerIdx + 4] = x;
|
|
96
|
+
centers[centerIdx + 5] = y;
|
|
97
|
+
centers[centerIdx + 6] = x;
|
|
98
|
+
centers[centerIdx + 7] = y;
|
|
99
|
+
|
|
100
|
+
// Calculate random frame from texture atlas
|
|
101
|
+
const frame = Math.floor(rng.random() * (particle.columns * particle.rows));
|
|
102
|
+
const col = frame % particle.columns;
|
|
103
|
+
const row = Math.floor(frame / particle.columns);
|
|
104
|
+
|
|
105
|
+
// Calculate UV coordinates for this frame
|
|
106
|
+
const uv0 = new THREE.Vector2(col / particle.columns, row / particle.rows);
|
|
107
|
+
const uv1 = new THREE.Vector2((col + 1) / particle.columns, (row + 1) / particle.rows);
|
|
108
|
+
|
|
109
|
+
// UV coordinates for quad
|
|
110
|
+
const uvBaseIdx = i * 8;
|
|
111
|
+
uvs[uvBaseIdx] = uv0.x; // bottom left
|
|
112
|
+
uvs[uvBaseIdx + 1] = uv0.y;
|
|
113
|
+
uvs[uvBaseIdx + 2] = uv1.x; // bottom right
|
|
114
|
+
uvs[uvBaseIdx + 3] = uv0.y;
|
|
115
|
+
uvs[uvBaseIdx + 4] = uv0.x; // top left
|
|
116
|
+
uvs[uvBaseIdx + 5] = uv1.y;
|
|
117
|
+
uvs[uvBaseIdx + 6] = uv1.x; // top right
|
|
118
|
+
uvs[uvBaseIdx + 7] = uv1.y;
|
|
119
|
+
|
|
120
|
+
// Indices for two triangles
|
|
121
|
+
const indexBaseIdx = i * 6;
|
|
122
|
+
const vertexBaseIdx = i * 4;
|
|
123
|
+
indices[indexBaseIdx] = vertexBaseIdx;
|
|
124
|
+
indices[indexBaseIdx + 1] = vertexBaseIdx + 1;
|
|
125
|
+
indices[indexBaseIdx + 2] = vertexBaseIdx + 2;
|
|
126
|
+
indices[indexBaseIdx + 3] = vertexBaseIdx + 1;
|
|
127
|
+
indices[indexBaseIdx + 4] = vertexBaseIdx + 3;
|
|
128
|
+
indices[indexBaseIdx + 5] = vertexBaseIdx + 2;
|
|
129
|
+
|
|
130
|
+
// Random attributes (same for all vertices of quad)
|
|
131
|
+
const ageOffset = rng.random() * props.lifetime;
|
|
132
|
+
|
|
133
|
+
for (let v = 0; v < 4; v++) {
|
|
134
|
+
ageOffsets[i * 4 + v] = ageOffset;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
untrack(() => {
|
|
139
|
+
geometry = new THREE.BufferGeometry();
|
|
140
|
+
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
|
|
141
|
+
geometry.setAttribute('center', new THREE.BufferAttribute(centers, 2));
|
|
142
|
+
geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));
|
|
143
|
+
geometry.setAttribute('ageOffset', new THREE.BufferAttribute(ageOffsets, 1));
|
|
144
|
+
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
return () => {
|
|
148
|
+
geometry?.dispose();
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const material = new THREE.ShaderMaterial();
|
|
153
|
+
const loader = useLoader(THREE.TextureLoader);
|
|
154
|
+
|
|
155
|
+
// Track current texture for disposal
|
|
156
|
+
let currentTexture: THREE.Texture | null = $state(null);
|
|
157
|
+
|
|
158
|
+
// Add cleanup on component destruction
|
|
159
|
+
onDestroy(() => {
|
|
160
|
+
geometry?.dispose();
|
|
161
|
+
if (currentTexture) {
|
|
162
|
+
currentTexture.dispose();
|
|
163
|
+
currentTexture = null;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Create a derived value for uniforms that updates when props change
|
|
168
|
+
const uniforms = $derived({
|
|
169
|
+
uTime: { value: 0 },
|
|
170
|
+
uTexture: { value: currentTexture },
|
|
171
|
+
uOpacity: { value: opacity },
|
|
172
|
+
uColor: { value: new THREE.Color(props.color) },
|
|
173
|
+
|
|
174
|
+
uLifetime: { value: props.lifetime },
|
|
175
|
+
uAngularVelocity: { value: props.rotation.velocity },
|
|
176
|
+
uInitialVelocity: { value: props.initialVelocity },
|
|
177
|
+
uLinearForceAmplitude: { value: props.force.linear },
|
|
178
|
+
uExponentialForceAmplitude: { value: props.force.exponential },
|
|
179
|
+
uSinusoidalForceAmplitude: { value: props.force.sinusoidal.amplitude },
|
|
180
|
+
uSinusoidalForceFrequency: { value: props.force.sinusoidal.frequency },
|
|
181
|
+
uFadeInTime: { value: props.fadeInTime },
|
|
182
|
+
uFadeOutTime: { value: props.fadeOutTime },
|
|
183
|
+
uScale: { value: props.scale }
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
$effect(() => {
|
|
187
|
+
loader.load(ParticleData[props.type].url).then((newTexture) => {
|
|
188
|
+
untrack(() => {
|
|
189
|
+
currentTexture?.dispose();
|
|
190
|
+
currentTexture = newTexture;
|
|
191
|
+
|
|
192
|
+
if (material.uniforms.uTexture) {
|
|
193
|
+
material.uniforms.uTexture.value = newTexture;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Update material uniforms whenever they change
|
|
200
|
+
$effect(() => {
|
|
201
|
+
Object.assign(material.uniforms, uniforms);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
useTask((dt) => {
|
|
205
|
+
material.uniforms.uTime.value += dt;
|
|
206
|
+
});
|
|
207
|
+
</script>
|
|
208
|
+
|
|
209
|
+
<T.Mesh bind:ref={mesh} {geometry}>
|
|
210
|
+
<T.ShaderMaterial
|
|
211
|
+
is={material}
|
|
212
|
+
{vertexShader}
|
|
213
|
+
{fragmentShader}
|
|
214
|
+
transparent={true}
|
|
215
|
+
depthWrite={false}
|
|
216
|
+
depthTest={false}
|
|
217
|
+
blending={THREE.NormalBlending}
|
|
218
|
+
side={THREE.DoubleSide}
|
|
219
|
+
/>
|
|
220
|
+
</T.Mesh>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class RNG {
|
|
2
|
+
m_w = 123456789;
|
|
3
|
+
m_z = 987654321;
|
|
4
|
+
mask = 0xffffffff;
|
|
5
|
+
|
|
6
|
+
constructor(seed) {
|
|
7
|
+
this.m_w = (123456789 + seed) & this.mask;
|
|
8
|
+
this.m_z = (987654321 - seed) & this.mask;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Returns number between 0 (inclusive) and 1.0 (exclusive),
|
|
12
|
+
// just like Math.random().
|
|
13
|
+
random() {
|
|
14
|
+
this.m_z = (36969 * (this.m_z & 65535) + (this.m_z >> 16)) & this.mask;
|
|
15
|
+
this.m_w = (18000 * (this.m_w & 65535) + (this.m_w >> 16)) & this.mask;
|
|
16
|
+
let result = ((this.m_z << 16) + (this.m_w & 65535)) >>> 0;
|
|
17
|
+
result /= 4294967296;
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import ash from './particles/atlases/ash.png';
|
|
2
|
+
import leaves from './particles/atlases/leaves.png';
|
|
3
|
+
import rain from './particles/atlases/rain.png';
|
|
4
|
+
import snow from './particles/atlases/snow.png';
|
|
5
|
+
|
|
6
|
+
export enum ParticleType {
|
|
7
|
+
Snow = 1,
|
|
8
|
+
Rain = 2,
|
|
9
|
+
Leaves = 3,
|
|
10
|
+
Ash = 4
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const ParticleData = {
|
|
14
|
+
[ParticleType.Snow]: {
|
|
15
|
+
url: snow,
|
|
16
|
+
size: 768,
|
|
17
|
+
columns: 3,
|
|
18
|
+
rows: 3
|
|
19
|
+
},
|
|
20
|
+
[ParticleType.Rain]: {
|
|
21
|
+
url: rain,
|
|
22
|
+
size: 768,
|
|
23
|
+
columns: 3,
|
|
24
|
+
rows: 3
|
|
25
|
+
},
|
|
26
|
+
[ParticleType.Leaves]: {
|
|
27
|
+
url: leaves,
|
|
28
|
+
size: 768,
|
|
29
|
+
columns: 3,
|
|
30
|
+
rows: 3
|
|
31
|
+
},
|
|
32
|
+
[ParticleType.Ash]: {
|
|
33
|
+
url: ash,
|
|
34
|
+
size: 768,
|
|
35
|
+
columns: 3,
|
|
36
|
+
rows: 3
|
|
37
|
+
}
|
|
38
|
+
} as const;
|
|
39
|
+
|
|
40
|
+
export interface ParticleSystemProps {
|
|
41
|
+
maxParticleCount: number;
|
|
42
|
+
type: ParticleType;
|
|
43
|
+
lifetime: number;
|
|
44
|
+
color: string;
|
|
45
|
+
opacity: number;
|
|
46
|
+
fadeInTime: number;
|
|
47
|
+
fadeOutTime: number;
|
|
48
|
+
initialVelocity: {
|
|
49
|
+
x: number;
|
|
50
|
+
y: number;
|
|
51
|
+
z: number;
|
|
52
|
+
};
|
|
53
|
+
force: {
|
|
54
|
+
linear: {
|
|
55
|
+
x: number;
|
|
56
|
+
y: number;
|
|
57
|
+
z: number;
|
|
58
|
+
};
|
|
59
|
+
exponential: {
|
|
60
|
+
x: number;
|
|
61
|
+
y: number;
|
|
62
|
+
z: number;
|
|
63
|
+
};
|
|
64
|
+
sinusoidal: {
|
|
65
|
+
amplitude: {
|
|
66
|
+
x: number;
|
|
67
|
+
y: number;
|
|
68
|
+
z: number;
|
|
69
|
+
};
|
|
70
|
+
frequency: {
|
|
71
|
+
x: number;
|
|
72
|
+
y: number;
|
|
73
|
+
z: number;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
rotation: {
|
|
78
|
+
alignRadially: boolean;
|
|
79
|
+
offset: number;
|
|
80
|
+
velocity: number;
|
|
81
|
+
randomize: boolean;
|
|
82
|
+
};
|
|
83
|
+
scale: {
|
|
84
|
+
x: number;
|
|
85
|
+
y: number;
|
|
86
|
+
};
|
|
87
|
+
size: {
|
|
88
|
+
min: number;
|
|
89
|
+
max: number;
|
|
90
|
+
};
|
|
91
|
+
spawnArea: {
|
|
92
|
+
minRadius: number;
|
|
93
|
+
maxRadius: number;
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import PerformanceOverlay from '../PerformanceOverlay/PerformanceOverlay.svelte';
|
|
4
|
+
import { resetMetrics } from '../../helpers/performanceMetrics.svelte';
|
|
5
|
+
import { debugState, setDebugEnabled } from '../../helpers/debugState.svelte';
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
/** Key combination to toggle (default: F9) */
|
|
9
|
+
shortcut?: string;
|
|
10
|
+
/** Callback when debug state changes (optional, for external notification) */
|
|
11
|
+
onToggle?: (enabled: boolean) => void;
|
|
12
|
+
/** Disabled layers for A/B testing */
|
|
13
|
+
disabledLayers?: string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { shortcut = 'F9', onToggle, disabledLayers = [] }: Props = $props();
|
|
17
|
+
|
|
18
|
+
let showHelp = $state(false);
|
|
19
|
+
|
|
20
|
+
// Use the global debug state
|
|
21
|
+
const enabled = $derived(debugState.enableMetrics);
|
|
22
|
+
|
|
23
|
+
const parseShortcut = (shortcut: string) => {
|
|
24
|
+
const parts = shortcut.split('+').map((p) => p.trim());
|
|
25
|
+
const modifiers = ['shift', 'ctrl', 'control', 'alt', 'meta', 'cmd'];
|
|
26
|
+
const keyPart = parts.find((p) => !modifiers.includes(p.toLowerCase())) || '';
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
shift: parts.some((p) => p.toLowerCase() === 'shift'),
|
|
30
|
+
ctrl: parts.some((p) => p.toLowerCase() === 'ctrl' || p.toLowerCase() === 'control'),
|
|
31
|
+
alt: parts.some((p) => p.toLowerCase() === 'alt'),
|
|
32
|
+
meta: parts.some((p) => p.toLowerCase() === 'meta' || p.toLowerCase() === 'cmd'),
|
|
33
|
+
// Preserve case for function keys (F9, F10, etc.)
|
|
34
|
+
key: keyPart.match(/^[fF]\d+$/) ? keyPart.toUpperCase() : keyPart.toLowerCase()
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const shortcutConfig = parseShortcut(shortcut);
|
|
39
|
+
|
|
40
|
+
const formatShortcut = () => {
|
|
41
|
+
const parts = [];
|
|
42
|
+
if (shortcutConfig.shift) parts.push('Shift');
|
|
43
|
+
if (shortcutConfig.ctrl) parts.push('Ctrl');
|
|
44
|
+
if (shortcutConfig.alt) parts.push('Alt');
|
|
45
|
+
if (shortcutConfig.meta) parts.push('Cmd');
|
|
46
|
+
// Function keys display as-is (F9), others uppercase
|
|
47
|
+
parts.push(shortcutConfig.key.match(/^F\d+$/) ? shortcutConfig.key : shortcutConfig.key.toUpperCase());
|
|
48
|
+
return parts.join(' + ');
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const isFormElement = (element: Element | null): boolean => {
|
|
52
|
+
if (!element) return false;
|
|
53
|
+
const tagName = element.tagName;
|
|
54
|
+
return (
|
|
55
|
+
tagName === 'INPUT' ||
|
|
56
|
+
tagName === 'TEXTAREA' ||
|
|
57
|
+
tagName === 'SELECT' ||
|
|
58
|
+
(element as HTMLElement).isContentEditable
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
63
|
+
// Don't trigger while typing in form elements
|
|
64
|
+
if (isFormElement(document.activeElement)) return;
|
|
65
|
+
|
|
66
|
+
// Function keys (F1-F12) are case-sensitive in e.key, others we compare lowercase
|
|
67
|
+
const isFunctionKey = shortcutConfig.key.match(/^F\d+$/);
|
|
68
|
+
const keyMatches = isFunctionKey ? e.key === shortcutConfig.key : e.key.toLowerCase() === shortcutConfig.key;
|
|
69
|
+
|
|
70
|
+
const matchesShortcut =
|
|
71
|
+
e.shiftKey === shortcutConfig.shift &&
|
|
72
|
+
e.ctrlKey === shortcutConfig.ctrl &&
|
|
73
|
+
e.altKey === shortcutConfig.alt &&
|
|
74
|
+
e.metaKey === shortcutConfig.meta &&
|
|
75
|
+
keyMatches;
|
|
76
|
+
|
|
77
|
+
if (matchesShortcut) {
|
|
78
|
+
e.preventDefault();
|
|
79
|
+
const newEnabled = !debugState.enableMetrics;
|
|
80
|
+
setDebugEnabled(newEnabled);
|
|
81
|
+
onToggle?.(newEnabled);
|
|
82
|
+
|
|
83
|
+
if (newEnabled) {
|
|
84
|
+
resetMetrics();
|
|
85
|
+
showHelp = true;
|
|
86
|
+
setTimeout(() => (showHelp = false), 2000);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
onMount(() => {
|
|
92
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
93
|
+
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
/** Get debug props to spread into Stage props */
|
|
97
|
+
export const getDebugProps = () => ({
|
|
98
|
+
enableStats: debugState.enableMetrics,
|
|
99
|
+
loggingRate: 1000,
|
|
100
|
+
enableMetrics: debugState.enableMetrics,
|
|
101
|
+
logMetricsToConsole: debugState.logMetricsToConsole,
|
|
102
|
+
disabledLayers
|
|
103
|
+
});
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
{#if enabled}
|
|
107
|
+
<PerformanceOverlay visible={true} {disabledLayers} />
|
|
108
|
+
{/if}
|
|
109
|
+
|
|
110
|
+
{#if showHelp}
|
|
111
|
+
<div class="performanceDebugger__help">
|
|
112
|
+
Performance metrics enabled. Press {formatShortcut()} to disable.
|
|
113
|
+
</div>
|
|
114
|
+
{/if}
|
|
115
|
+
|
|
116
|
+
<style>
|
|
117
|
+
.performanceDebugger__help {
|
|
118
|
+
position: absolute;
|
|
119
|
+
bottom: 1rem;
|
|
120
|
+
left: 50%;
|
|
121
|
+
transform: translateX(-50%);
|
|
122
|
+
background: var(--fg);
|
|
123
|
+
color: var(--bg);
|
|
124
|
+
font-family: var(--font-sans);
|
|
125
|
+
font-size: 0.75rem;
|
|
126
|
+
padding: 0.5rem 1rem;
|
|
127
|
+
border-radius: var(--radius-2);
|
|
128
|
+
box-shadow: var(--shadow-2);
|
|
129
|
+
z-index: 1000;
|
|
130
|
+
pointer-events: none;
|
|
131
|
+
animation: performanceDebuggerFadeIn 0.2s var(--ease-out-3);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@keyframes performanceDebuggerFadeIn {
|
|
135
|
+
from {
|
|
136
|
+
opacity: 0;
|
|
137
|
+
transform: translateX(-50%) translateY(0.5rem);
|
|
138
|
+
}
|
|
139
|
+
to {
|
|
140
|
+
opacity: 1;
|
|
141
|
+
transform: translateX(-50%) translateY(0);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as PerformanceDebugger } from './PerformanceDebugger.svelte';
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
performanceMetrics,
|
|
4
|
+
getAverageFps,
|
|
5
|
+
get1PercentLowFps,
|
|
6
|
+
getFrameTimes
|
|
7
|
+
} from '../../helpers/performanceMetrics.svelte';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
visible?: boolean;
|
|
11
|
+
disabledLayers?: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const { visible = true, disabledLayers = [] }: Props = $props();
|
|
15
|
+
|
|
16
|
+
const metrics = $derived(performanceMetrics.value);
|
|
17
|
+
const frameTimes = $derived(getFrameTimes());
|
|
18
|
+
const avgFps = $derived(getAverageFps());
|
|
19
|
+
const lowFps = $derived(get1PercentLowFps());
|
|
20
|
+
|
|
21
|
+
// Graph dimensions
|
|
22
|
+
const GRAPH_WIDTH = 200;
|
|
23
|
+
const GRAPH_HEIGHT = 60;
|
|
24
|
+
const MAX_FRAME_TIME = 50; // Cap at 50ms (20fps) for graph scale
|
|
25
|
+
|
|
26
|
+
// Generate SVG path for frame time graph
|
|
27
|
+
const graphPath = $derived(() => {
|
|
28
|
+
if (frameTimes.length < 2) return '';
|
|
29
|
+
|
|
30
|
+
const points = frameTimes.map((ft, i) => {
|
|
31
|
+
const x = (i / (frameTimes.length - 1)) * GRAPH_WIDTH;
|
|
32
|
+
const y = GRAPH_HEIGHT - Math.min(ft / MAX_FRAME_TIME, 1) * GRAPH_HEIGHT;
|
|
33
|
+
return `${x},${y}`;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return `M${points.join(' L')}`;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Color based on FPS
|
|
40
|
+
const fpsColor = $derived(() => {
|
|
41
|
+
const fps = metrics.fps;
|
|
42
|
+
if (fps >= 55) return 'var(--fgSuccess)';
|
|
43
|
+
if (fps >= 30) return 'var(--fgWarning)';
|
|
44
|
+
return 'var(--fgDanger)';
|
|
45
|
+
});
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
{#if visible}
|
|
49
|
+
<div class="perfOverlay">
|
|
50
|
+
<div class="perfOverlay__header">Performance</div>
|
|
51
|
+
|
|
52
|
+
<div class="perfOverlay__section">
|
|
53
|
+
<div class="perfOverlay__row">
|
|
54
|
+
<span class="perfOverlay__label">FPS</span>
|
|
55
|
+
<span class="perfOverlay__value" style="color: {fpsColor()}">{metrics.fps.toFixed(0)}</span>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="perfOverlay__row">
|
|
58
|
+
<span class="perfOverlay__label">Avg</span>
|
|
59
|
+
<span class="perfOverlay__value">{avgFps.toFixed(0)}</span>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="perfOverlay__row">
|
|
62
|
+
<span class="perfOverlay__label">1% Low</span>
|
|
63
|
+
<span class="perfOverlay__value">{lowFps.toFixed(0)}</span>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="perfOverlay__graph">
|
|
68
|
+
<svg width={GRAPH_WIDTH} height={GRAPH_HEIGHT} class="perfOverlay__svg">
|
|
69
|
+
<!-- 60fps line (16.67ms) -->
|
|
70
|
+
<line
|
|
71
|
+
x1="0"
|
|
72
|
+
y1={GRAPH_HEIGHT - (16.67 / MAX_FRAME_TIME) * GRAPH_HEIGHT}
|
|
73
|
+
x2={GRAPH_WIDTH}
|
|
74
|
+
y2={GRAPH_HEIGHT - (16.67 / MAX_FRAME_TIME) * GRAPH_HEIGHT}
|
|
75
|
+
stroke="var(--fgSuccess)"
|
|
76
|
+
stroke-opacity="0.3"
|
|
77
|
+
stroke-width="1"
|
|
78
|
+
stroke-dasharray="4,4"
|
|
79
|
+
/>
|
|
80
|
+
<!-- 30fps line (33.33ms) -->
|
|
81
|
+
<line
|
|
82
|
+
x1="0"
|
|
83
|
+
y1={GRAPH_HEIGHT - (33.33 / MAX_FRAME_TIME) * GRAPH_HEIGHT}
|
|
84
|
+
x2={GRAPH_WIDTH}
|
|
85
|
+
y2={GRAPH_HEIGHT - (33.33 / MAX_FRAME_TIME) * GRAPH_HEIGHT}
|
|
86
|
+
stroke="var(--fgWarning)"
|
|
87
|
+
stroke-opacity="0.3"
|
|
88
|
+
stroke-width="1"
|
|
89
|
+
stroke-dasharray="4,4"
|
|
90
|
+
/>
|
|
91
|
+
<!-- Frame time path -->
|
|
92
|
+
<path d={graphPath()} fill="none" stroke="var(--fgPrimary)" stroke-width="1.5" />
|
|
93
|
+
</svg>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<div class="perfOverlay__section">
|
|
97
|
+
<div class="perfOverlay__row">
|
|
98
|
+
<span class="perfOverlay__label">Frame</span>
|
|
99
|
+
<span class="perfOverlay__value">{metrics.frameTime.toFixed(2)}ms</span>
|
|
100
|
+
</div>
|
|
101
|
+
<div class="perfOverlay__row">
|
|
102
|
+
<span class="perfOverlay__label">Composer</span>
|
|
103
|
+
<span class="perfOverlay__value">{metrics.composerTime.toFixed(2)}ms</span>
|
|
104
|
+
</div>
|
|
105
|
+
<div class="perfOverlay__row">
|
|
106
|
+
<span class="perfOverlay__label">Overlay</span>
|
|
107
|
+
<span class="perfOverlay__value">{metrics.overlayTime.toFixed(2)}ms</span>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div class="perfOverlay__section">
|
|
112
|
+
<div class="perfOverlay__row">
|
|
113
|
+
<span class="perfOverlay__label">Draw calls</span>
|
|
114
|
+
<span class="perfOverlay__value">{metrics.drawCalls}</span>
|
|
115
|
+
</div>
|
|
116
|
+
<div class="perfOverlay__row">
|
|
117
|
+
<span class="perfOverlay__label">Triangles</span>
|
|
118
|
+
<span class="perfOverlay__value">{metrics.triangles}</span>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="perfOverlay__row">
|
|
121
|
+
<span class="perfOverlay__label">Textures</span>
|
|
122
|
+
<span class="perfOverlay__value">{metrics.textures}</span>
|
|
123
|
+
</div>
|
|
124
|
+
<div class="perfOverlay__row">
|
|
125
|
+
<span class="perfOverlay__label">Geometries</span>
|
|
126
|
+
<span class="perfOverlay__value">{metrics.geometries}</span>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
{#if disabledLayers.length > 0}
|
|
131
|
+
<div class="perfOverlay__section">
|
|
132
|
+
<div class="perfOverlay__sublabel">Disabled layers</div>
|
|
133
|
+
{#each disabledLayers as layer}
|
|
134
|
+
<div class="perfOverlay__disabledLayer">{layer}</div>
|
|
135
|
+
{/each}
|
|
136
|
+
</div>
|
|
137
|
+
{/if}
|
|
138
|
+
</div>
|
|
139
|
+
{/if}
|
|
140
|
+
|
|
141
|
+
<style>
|
|
142
|
+
.perfOverlay {
|
|
143
|
+
position: absolute;
|
|
144
|
+
top: 0.5rem;
|
|
145
|
+
left: 0.5rem;
|
|
146
|
+
background: rgba(0, 0, 0, 0.85);
|
|
147
|
+
color: var(--fg);
|
|
148
|
+
font-family: var(--font-mono);
|
|
149
|
+
font-size: 0.75rem;
|
|
150
|
+
padding: 0.5rem;
|
|
151
|
+
border-radius: var(--radius-2);
|
|
152
|
+
z-index: 1000;
|
|
153
|
+
pointer-events: none;
|
|
154
|
+
min-width: 14rem;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.perfOverlay__header {
|
|
158
|
+
font-weight: var(--font-weight-7);
|
|
159
|
+
margin-bottom: 0.5rem;
|
|
160
|
+
padding-bottom: 0.25rem;
|
|
161
|
+
border-bottom: 1px solid var(--fgMuted);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.perfOverlay__section {
|
|
165
|
+
margin-bottom: 0.5rem;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.perfOverlay__section:last-child {
|
|
169
|
+
margin-bottom: 0;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.perfOverlay__row {
|
|
173
|
+
display: flex;
|
|
174
|
+
justify-content: space-between;
|
|
175
|
+
line-height: var(--font-lineheight-2);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.perfOverlay__label {
|
|
179
|
+
color: var(--fgMuted);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.perfOverlay__value {
|
|
183
|
+
font-weight: var(--font-weight-5);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.perfOverlay__sublabel {
|
|
187
|
+
color: var(--fgMuted);
|
|
188
|
+
font-size: 0.625rem;
|
|
189
|
+
margin-bottom: 0.125rem;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.perfOverlay__disabledLayer {
|
|
193
|
+
color: var(--fgWarning);
|
|
194
|
+
font-size: 0.625rem;
|
|
195
|
+
padding-left: 0.5rem;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.perfOverlay__graph {
|
|
199
|
+
margin: 0.5rem 0;
|
|
200
|
+
background: rgba(255, 255, 255, 0.05);
|
|
201
|
+
border-radius: var(--radius-1);
|
|
202
|
+
overflow: hidden;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.perfOverlay__svg {
|
|
206
|
+
display: block;
|
|
207
|
+
}
|
|
208
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as PerformanceOverlay } from './PerformanceOverlay.svelte';
|