Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b2203e008 | ||
|
|
a3cefc3c79 | ||
|
|
1c3a811154 |
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "JE-Skin",
|
"name": "JE-Skin",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "JE-Skin",
|
"name": "JE-Skin",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "JE-Skin",
|
"name": "JE-Skin",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
2
src-tauri/Cargo.lock
generated
@@ -4,7 +4,7 @@ version = 4
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "JE-Skin"
|
name = "JE-Skin"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "JE-Skin"
|
name = "JE-Skin"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
description = "A Tauri App"
|
description = "A Tauri App"
|
||||||
authors = ["you"]
|
authors = ["you"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 906 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 906 KiB After Width: | Height: | Size: 28 KiB |
BIN
src-tauri/icons/16x16.png
Normal file
|
After Width: | Height: | Size: 715 B |
BIN
src-tauri/icons/192x192.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
src-tauri/icons/256x256.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 906 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
src-tauri/icons/512x512.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
src-tauri/icons/64x64.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src-tauri/icons/Square107x107Logo.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
src-tauri/icons/Square142x142Logo.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src-tauri/icons/Square150x150Logo.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src-tauri/icons/Square284x284Logo.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
src-tauri/icons/Square30x30Logo.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src-tauri/icons/Square310x310Logo.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
src-tauri/icons/Square44x44Logo.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
src-tauri/icons/Square71x71Logo.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
src-tauri/icons/Square89x89Logo.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
src-tauri/icons/StoreLogo.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
</adaptive-icon>
|
||||||
BIN
src-tauri/icons/android/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
src-tauri/icons/android/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 63 KiB |
BIN
src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#fff</color>
|
||||||
|
</resources>
|
||||||
BIN
src-tauri/icons/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src-tauri/icons/icon.icns
Normal file
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 906 KiB After Width: | Height: | Size: 81 KiB |
BIN
src-tauri/icons/ios/AppIcon-20x20@1x.png
Normal file
|
After Width: | Height: | Size: 806 B |
BIN
src-tauri/icons/ios/AppIcon-20x20@2x-1.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src-tauri/icons/ios/AppIcon-20x20@2x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src-tauri/icons/ios/AppIcon-20x20@3x.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
src-tauri/icons/ios/AppIcon-29x29@1x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
src-tauri/icons/ios/AppIcon-29x29@2x-1.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src-tauri/icons/ios/AppIcon-29x29@2x.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src-tauri/icons/ios/AppIcon-29x29@3x.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
src-tauri/icons/ios/AppIcon-40x40@1x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src-tauri/icons/ios/AppIcon-40x40@2x-1.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
src-tauri/icons/ios/AppIcon-40x40@2x.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
src-tauri/icons/ios/AppIcon-40x40@3x.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
src-tauri/icons/ios/AppIcon-512@2x.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
src-tauri/icons/ios/AppIcon-60x60@2x.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
src-tauri/icons/ios/AppIcon-60x60@3x.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src-tauri/icons/ios/AppIcon-76x76@1x.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
src-tauri/icons/ios/AppIcon-76x76@2x.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
306
src-tauri/program.log2026-04-08
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
[2026-04-08T03:07:37Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:07:37Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:09:47Z [37mDEBUG[0m tao::platform_impl::platform::event_loop::runner] NewEvents emitted without explicit RedrawEventsCleared
|
||||||
|
[2026-04-08T03:09:47Z [37mDEBUG[0m tao::platform_impl::platform::event_loop::runner] RedrawEventsCleared emitted without explicit MainEventsCleared
|
||||||
|
[2026-04-08T03:12:49Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:12:49Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:15:23Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:15:23Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:15:36Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:15:36Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:15:36Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:15:36Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:15:36Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:15:55Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 1704 frames
|
||||||
|
[2026-04-08T03:16:08Z [37mDEBUG[0m tao::platform_impl::platform::event_loop::runner] NewEvents emitted without explicit RedrawEventsCleared
|
||||||
|
[2026-04-08T03:16:08Z [37mDEBUG[0m tao::platform_impl::platform::event_loop::runner] RedrawEventsCleared emitted without explicit MainEventsCleared
|
||||||
|
[2026-04-08T03:17:59Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:17:59Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:17:59Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:17:59Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:17:59Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:18:04Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 485 frames
|
||||||
|
[2026-04-08T03:18:13Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:18:13Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:18:13Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:18:13Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:18:13Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:24:54Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:24:54Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:25:10Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:25:10Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:25:10Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:25:10Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:25:10Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:25:24Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 1226 frames
|
||||||
|
[2026-04-08T03:30:00Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:30:00Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:30:00Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:30:00Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:30:00Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:30:56Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:30:56Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:31:17Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:31:17Z [37mDEBUG[0m mio_serial] switching COM1 to asynchronous mode
|
||||||
|
[2026-04-08T03:31:17Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:31:17Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:31:17Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:31:20Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 0 frames
|
||||||
|
[2026-04-08T03:31:22Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:31:22Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:31:22Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:31:22Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:31:22Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:34:36Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:34:36Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:34:42Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:34:42Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:34:42Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:34:42Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:34:42Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:34:47Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 457 frames
|
||||||
|
[2026-04-08T03:34:55Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:34:55Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:34:55Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:34:55Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:34:55Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:36:11Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:36:11Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:36:25Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:36:25Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:36:25Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:36:25Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:36:25Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:38:27Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:38:27Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:40:51Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:40:51Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:41:05Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:41:05Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:41:05Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:41:05Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:41:05Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:42:25Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:42:25Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:39:52Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:39:52Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:41:00Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:41:00Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:41:05Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:41:05Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:41:05Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:41:05Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:41:05Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T05:44:17Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:44:17Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:44:22Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:44:22Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:44:22Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:44:22Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:44:22Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T05:48:46Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:48:46Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:48:56Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:48:56Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:48:56Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:48:56Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:48:56Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T05:51:41Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:51:41Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:51:45Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:51:45Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:51:45Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:51:45Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:51:45Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T05:52:07Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:52:07Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:53:57Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:53:57Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:54:02Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:54:02Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:54:02Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:54:02Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:54:02Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T05:57:11Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:57:11Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:57:23Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:57:23Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:57:23Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:57:23Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:57:23Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T05:59:05Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:59:05Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:59:21Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:59:21Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:59:21Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:59:21Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:59:21Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T06:03:12Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:03:12Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:03:33Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T06:03:33Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T06:03:33Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T06:03:33Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T06:03:33Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T06:03:50Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 1610 frames
|
||||||
|
[2026-04-08T06:04:02Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T06:04:02Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T06:04:02Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T06:04:02Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T06:04:02Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T06:19:31Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:19:31Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:23:22Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:23:22Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:25:37Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:25:37Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:26:54Z [37mDEBUG[0m tao::platform_impl::platform::event_loop::runner] NewEvents emitted without explicit RedrawEventsCleared
|
||||||
|
[2026-04-08T06:26:54Z [37mDEBUG[0m tao::platform_impl::platform::event_loop::runner] RedrawEventsCleared emitted without explicit MainEventsCleared
|
||||||
|
[2026-04-08T06:27:17Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:27:17Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:27:26Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:27:26Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:27:27Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:27:27Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:27:28Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:27:28Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:27:29Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:27:29Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:27:30Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:27:30Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:28:58Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:28:58Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:29:37Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:29:37Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:41:34Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:41:34Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:43:41Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:43:41Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:46:02Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:46:02Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:47:57Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:47:57Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:48:25Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:48:25Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:08:08Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:08:08Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:08:29Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:08:29Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:08:29Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:08:29Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:08:29Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:08:33Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 381 frames
|
||||||
|
[2026-04-08T07:08:42Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:08:42Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:08:42Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:08:42Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:08:42Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:11:03Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:11:03Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:11:12Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:11:12Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:11:12Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:11:12Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:11:12Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:11:16Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 276 frames
|
||||||
|
[2026-04-08T07:14:06Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:14:06Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:14:06Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:14:06Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:14:06Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:14:08Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 183 frames
|
||||||
|
[2026-04-08T07:16:20Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:16:20Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:16:52Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:16:52Z [37mDEBUG[0m mio_serial] switching COM1 to asynchronous mode
|
||||||
|
[2026-04-08T07:16:52Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:16:52Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:16:52Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:16:52Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 0 frames
|
||||||
|
[2026-04-08T07:16:56Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:16:56Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:16:56Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:16:56Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:16:56Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:17:36Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:17:36Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:17:47Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:17:47Z [37mDEBUG[0m mio_serial] switching COM1 to asynchronous mode
|
||||||
|
[2026-04-08T07:17:47Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:17:47Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:17:47Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:17:49Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 0 frames
|
||||||
|
[2026-04-08T07:17:53Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:17:53Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:17:53Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:17:53Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:17:53Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:18:08Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:18:08Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:18:50Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:18:50Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:18:57Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:18:57Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:19:10Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:19:10Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:19:14Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:19:14Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:19:14Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:19:14Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:19:14Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:19:17Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 227 frames
|
||||||
|
[2026-04-08T07:19:29Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:19:29Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:19:29Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:19:29Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:19:29Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:19:38Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:19:38Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:19:56Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:19:56Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:20:10Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:20:10Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:20:10Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:20:10Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:20:10Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:20:41Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:20:41Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:20:46Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:20:46Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:20:46Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:20:46Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:20:46Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:20:57Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:20:57Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:22:12Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:22:12Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:22:30Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:22:30Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:22:30Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:22:30Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:22:30Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:22:38Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:22:38Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:23:10Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:23:10Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:23:18Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:23:18Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:23:18Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:23:18Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:23:18Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:23:24Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:23:24Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:33:13Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:33:13Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:33:18Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:33:18Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:33:18Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:33:18Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:33:18Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:33:24Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 499 frames
|
||||||
|
[2026-04-08T07:33:31Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:33:31Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:33:31Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:33:31Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:33:31Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:34:06Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 3160 frames
|
||||||
@@ -77,6 +77,40 @@ pub struct SerialConnectionState {
|
|||||||
last_record: Mutex<Option<SharedTactileRecording>>
|
last_record: Mutex<Option<SharedTactileRecording>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn shutdown_active_session(
|
||||||
|
state: &SerialConnectionState,
|
||||||
|
) -> Result<Option<(String, SharedTactileRecording)>, SerialError> {
|
||||||
|
let session = {
|
||||||
|
let mut guard = state.session.lock().map_err(|_| SerialError::StateError)?;
|
||||||
|
guard.take()
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(SerialSession {
|
||||||
|
port,
|
||||||
|
cancel,
|
||||||
|
task,
|
||||||
|
current_record,
|
||||||
|
}) = session else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
cancel.cancel();
|
||||||
|
let _ = task.await;
|
||||||
|
|
||||||
|
let frame_count = current_record
|
||||||
|
.lock()
|
||||||
|
.map(|record| record.frames.len())
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
info!("last_record has {} frames", frame_count);
|
||||||
|
|
||||||
|
if let Ok(mut last_record) = state.last_record.lock() {
|
||||||
|
*last_record = Some(current_record.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some((port, current_record)))
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn serial_enum() -> Result<Vec<String>, SerialError> {
|
pub fn serial_enum() -> Result<Vec<String>, SerialError> {
|
||||||
let ports = available_ports()
|
let ports = available_ports()
|
||||||
@@ -190,17 +224,7 @@ pub async fn serial_connect(
|
|||||||
pub async fn serial_disconnect(
|
pub async fn serial_disconnect(
|
||||||
state: State<'_, SerialConnectionState>,
|
state: State<'_, SerialConnectionState>,
|
||||||
) -> Result<SerialConnectResponse, SerialError> {
|
) -> Result<SerialConnectResponse, SerialError> {
|
||||||
let session = {
|
let Some((port, _current_record)) = shutdown_active_session(&state).await?
|
||||||
let mut guard = state.session.lock().map_err(|_| SerialError::StateError)?;
|
|
||||||
guard.take()
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(SerialSession {
|
|
||||||
port,
|
|
||||||
cancel,
|
|
||||||
task,
|
|
||||||
current_record,
|
|
||||||
}) = session
|
|
||||||
else {
|
else {
|
||||||
return Ok(SerialConnectResponse {
|
return Ok(SerialConnectResponse {
|
||||||
port: String::new(),
|
port: String::new(),
|
||||||
@@ -209,19 +233,6 @@ pub async fn serial_disconnect(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
cancel.cancel();
|
|
||||||
let _ = task.await;
|
|
||||||
let frame_count = current_record.lock().map(|record| {
|
|
||||||
record.frames.len()
|
|
||||||
}).unwrap_or(0);
|
|
||||||
|
|
||||||
info!("last_record has {} frames", frame_count);
|
|
||||||
|
|
||||||
if let Ok(mut last_record) = state.last_record.lock() {
|
|
||||||
*last_record = Some(current_record);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Ok(SerialConnectResponse {
|
Ok(SerialConnectResponse {
|
||||||
port,
|
port,
|
||||||
connected: false,
|
connected: false,
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use tauri::{AppHandle, Manager, WebviewWindow};
|
use super::serial::SerialConnectionState;
|
||||||
|
use crate::commands::serial::shutdown_active_session;
|
||||||
|
use tauri::{AppHandle, Manager, State, WebviewWindow};
|
||||||
|
|
||||||
fn main_window(app: &AppHandle) -> Result<WebviewWindow, String> {
|
fn main_window(app: &AppHandle) -> Result<WebviewWindow, String> {
|
||||||
app.get_webview_window("main")
|
app.get_webview_window("main")
|
||||||
@@ -25,8 +27,14 @@ pub fn win_toggle_maximize(app: AppHandle) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn win_close(app: AppHandle) -> Result<(), String> {
|
pub async fn win_close(
|
||||||
main_window(&app)?
|
app: AppHandle,
|
||||||
.close()
|
state: State<'_, SerialConnectionState>,
|
||||||
.map_err(|error| error.to_string())
|
) -> Result<(), String> {
|
||||||
|
shutdown_active_session(&state)
|
||||||
|
.await
|
||||||
|
.map_err(|error| error.to_string())?;
|
||||||
|
|
||||||
|
app.exit(0);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::debug;
|
||||||
use tauri_demo_lib::log::setup_logger;
|
use tauri_demo_lib::log::setup_logger;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ const FRAME_BUFFER_MIN_LENGTH: usize = 15;
|
|||||||
|
|
||||||
pub struct TactileACodec {
|
pub struct TactileACodec {
|
||||||
buffer: Vec<u8>,
|
buffer: Vec<u8>,
|
||||||
frame_nb: u64,
|
|
||||||
expected_data_len: usize,
|
expected_data_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +64,6 @@ impl TactileACodec {
|
|||||||
pub fn new(cols: usize, rows: usize) -> TactileACodec {
|
pub fn new(cols: usize, rows: usize) -> TactileACodec {
|
||||||
Self {
|
Self {
|
||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
frame_nb: 0,
|
|
||||||
expected_data_len: cols * rows * 2,
|
expected_data_len: cols * rows * 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,7 +75,14 @@ impl TactileACodec {
|
|||||||
|
|
||||||
let vals: Vec<i32> = data
|
let vals: Vec<i32> = data
|
||||||
.chunks_exact(2)
|
.chunks_exact(2)
|
||||||
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]) as i32)
|
.map(|chunk| {
|
||||||
|
let raw = u16::from_le_bytes([chunk[0], chunk[1]]) as i32;
|
||||||
|
if raw < 15 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
raw
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect::<Vec<i32>>();
|
.collect::<Vec<i32>>();
|
||||||
|
|
||||||
Ok(vals)
|
Ok(vals)
|
||||||
@@ -236,7 +241,6 @@ impl FrameHandler<TactileAFrame, i32> for TactileAHandler {
|
|||||||
match frame {
|
match frame {
|
||||||
TactileAFrame::Rep(rep) => {
|
TactileAFrame::Rep(rep) => {
|
||||||
let vals = TactileACodec::parse_data_frame(&rep.payload)?;
|
let vals = TactileACodec::parse_data_frame(&rep.payload)?;
|
||||||
debug!("vals is {:?}", vals);
|
|
||||||
Ok(Some(vals))
|
Ok(Some(vals))
|
||||||
}
|
}
|
||||||
_ => Ok(None),
|
_ => Ok(None),
|
||||||
@@ -252,7 +256,7 @@ impl TactileACsvExporter {
|
|||||||
|
|
||||||
impl CsvExporter<TactileARepFrame> for TactileACsvExporter {
|
impl CsvExporter<TactileARepFrame> for TactileACsvExporter {
|
||||||
type Error = CodecError;
|
type Error = CodecError;
|
||||||
fn csv_header(&self, recording: &Recording<TactileARepFrame>) -> Vec<String> {
|
fn csv_header(&self, _recording: &Recording<TactileARepFrame>) -> Vec<String> {
|
||||||
let mut header: Vec<String> = Vec::new();
|
let mut header: Vec<String> = Vec::new();
|
||||||
for i in 0..self.channels {
|
for i in 0..self.channels {
|
||||||
header.push(format!("channel{}", i + 1));
|
header.push(format!("channel{}", i + 1));
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ use tokio_util::sync::CancellationToken;
|
|||||||
use std::future::pending;
|
use std::future::pending;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use log::{info, debug};
|
|
||||||
use crate::serial_core::record::{FrameTiming, RecordedFrame};
|
use crate::serial_core::record::{FrameTiming, RecordedFrame};
|
||||||
|
|
||||||
pub enum PollMode<F> {
|
pub enum PollMode<F> {
|
||||||
@@ -158,9 +157,9 @@ impl PollRequester<TactileAFrame> for TactileAPollRequester {
|
|||||||
|
|
||||||
pub async fn run_serial<C, H, T, F>(
|
pub async fn run_serial<C, H, T, F>(
|
||||||
app: AppHandle,
|
app: AppHandle,
|
||||||
mut port: SerialStream,
|
port: SerialStream,
|
||||||
mut codec: C,
|
codec: C,
|
||||||
mut handler: H,
|
handler: H,
|
||||||
session_started_at: Instant,
|
session_started_at: Instant,
|
||||||
recording: Arc<Mutex<Recording<F>>>,
|
recording: Arc<Mutex<Recording<F>>>,
|
||||||
cancel: CancellationToken,
|
cancel: CancellationToken,
|
||||||
@@ -265,7 +264,8 @@ where
|
|||||||
|
|
||||||
let display_values = if let Some(vals) = decode_res.as_ref() {
|
let display_values = if let Some(vals) = decode_res.as_ref() {
|
||||||
let summary = vals.iter().copied().sum::<i32>();
|
let summary = vals.iter().copied().sum::<i32>();
|
||||||
chart_state.record_summary(summary as f32);
|
let force = raw_to_g1(summary as u32);
|
||||||
|
chart_state.record_summary(force as f32);
|
||||||
chart_state.record_pressure_matrix(vals.as_slice());
|
chart_state.record_pressure_matrix(vals.as_slice());
|
||||||
Some(vec![summary])
|
Some(vec![summary])
|
||||||
} else {
|
} else {
|
||||||
@@ -281,3 +281,36 @@ where
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn raw_to_g1(raw: u32) -> f64 {
|
||||||
|
const X: [u32; 11] = [
|
||||||
|
0, 74602, 105503, 131459, 153512, 172041, 193794, 218947, 240580, 295118, 332346,
|
||||||
|
];
|
||||||
|
|
||||||
|
const Y: [f64; 11] = [
|
||||||
|
0.0, 160.0, 260.0, 360.0, 460.0, 560.0, 660.0, 860.0, 1060.0, 1560.0, 2060.0,
|
||||||
|
];
|
||||||
|
|
||||||
|
let n = X.len();
|
||||||
|
if raw <= X[0] {
|
||||||
|
return Y[0] / 100.0;
|
||||||
|
}
|
||||||
|
if raw >= X[n - 1] {
|
||||||
|
return Y[n - 1] / 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut left = 0;
|
||||||
|
let mut right = n - 1;
|
||||||
|
|
||||||
|
while left + 1 < right {
|
||||||
|
let mid = (left + right) / 2;
|
||||||
|
if raw < X[mid] {
|
||||||
|
right = mid;
|
||||||
|
} else {
|
||||||
|
left = mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ratio = (raw - X[left]) as f64 / (X[right] - X[left]) as f64;
|
||||||
|
Y[left] / 100.0 + ratio * (Y[right] - Y[left]) / 100.0
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "JE-Skin",
|
"productName": "JE-Skin",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"identifier": "com.lenn.tauri-serial",
|
"identifier": "com.lenn.tauri-serial",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "npm run dev",
|
"beforeDevCommand": "npm run dev",
|
||||||
@@ -27,10 +27,10 @@
|
|||||||
"targets": "all",
|
"targets": "all",
|
||||||
"icon": [
|
"icon": [
|
||||||
"icons/32x32.png",
|
"icons/32x32.png",
|
||||||
"icons/128x128.png",
|
"icons/128x128.png",
|
||||||
"icons/128x128@2x.png",
|
"icons/128x128@2x.png",
|
||||||
"icons/icon.ico",
|
"icons/icon.icns",
|
||||||
"icons/icon.png"
|
"icons/icon.ico"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,15 +14,11 @@
|
|||||||
HudSignalPanel,
|
HudSignalPanel,
|
||||||
HudSummary,
|
HudSummary,
|
||||||
LocaleCode,
|
LocaleCode,
|
||||||
PressureColorMapPreset,
|
MatrixDisplayMode,
|
||||||
StageStatusTone
|
PressureColorMapPreset
|
||||||
} from "$lib/types/hud";
|
} from "$lib/types/hud";
|
||||||
|
|
||||||
export let title = "";
|
|
||||||
export let hint = "";
|
|
||||||
export let locale: LocaleCode = "zh-CN";
|
export let locale: LocaleCode = "zh-CN";
|
||||||
export let statusText = "";
|
|
||||||
export let statusTone: StageStatusTone = "idle";
|
|
||||||
export let leftPanels: HudSignalPanel[] = [];
|
export let leftPanels: HudSignalPanel[] = [];
|
||||||
export let rightPanels: HudSignalPanel[] = [];
|
export let rightPanels: HudSignalPanel[] = [];
|
||||||
export let summary: HudSummary;
|
export let summary: HudSummary;
|
||||||
@@ -44,6 +40,7 @@
|
|||||||
export let rangeMin = 0;
|
export let rangeMin = 0;
|
||||||
export let rangeMax = 16000;
|
export let rangeMax = 16000;
|
||||||
export let colorMapPreset: PressureColorMapPreset = "emerald";
|
export let colorMapPreset: PressureColorMapPreset = "emerald";
|
||||||
|
export let matrixDisplayMode: MatrixDisplayMode = "dots";
|
||||||
export let colorMapOptions: HudColorMapOption[] = [];
|
export let colorMapOptions: HudColorMapOption[] = [];
|
||||||
export let replaySectionLabel = "";
|
export let replaySectionLabel = "";
|
||||||
export let replayPlayLabel = "";
|
export let replayPlayLabel = "";
|
||||||
@@ -60,7 +57,6 @@
|
|||||||
export let showPrecisionTestPanel = false;
|
export let showPrecisionTestPanel = false;
|
||||||
|
|
||||||
let stagePlaneEl: HTMLDivElement | undefined;
|
let stagePlaneEl: HTMLDivElement | undefined;
|
||||||
let topOverlayEl: HTMLDivElement | undefined;
|
|
||||||
let panelZoneEl: HTMLDivElement | undefined;
|
let panelZoneEl: HTMLDivElement | undefined;
|
||||||
let leftStackEl: HTMLDivElement | undefined;
|
let leftStackEl: HTMLDivElement | undefined;
|
||||||
let rightStackEl: HTMLDivElement | undefined;
|
let rightStackEl: HTMLDivElement | undefined;
|
||||||
@@ -85,6 +81,7 @@
|
|||||||
$: replaySide = summarySide === "left" ? "right" : "left";
|
$: replaySide = summarySide === "left" ? "right" : "left";
|
||||||
$: replayToggleButtonText = replayIsPlaying ? replayPauseLabel : replayPlayLabel;
|
$: replayToggleButtonText = replayIsPlaying ? replayPauseLabel : replayPlayLabel;
|
||||||
$: replayProgressPercent = Math.round(Math.min(1, Math.max(0, replayProgress)) * 100);
|
$: replayProgressPercent = Math.round(Math.min(1, Math.max(0, replayProgress)) * 100);
|
||||||
|
$: summaryCurveVisible = summary.points.length > 0 && summary.points.some((value) => Number.isFinite(value) && Math.abs(value) >= 0.0001);
|
||||||
$: splitMatrixTitle = locale === "zh-CN" ? "数字矩阵" : "Matrix";
|
$: splitMatrixTitle = locale === "zh-CN" ? "数字矩阵" : "Matrix";
|
||||||
$: splitMatrixHint = locale === "zh-CN" ? "实时压力数据 / 数字矩阵" : "Live pressure matrix";
|
$: splitMatrixHint = locale === "zh-CN" ? "实时压力数据 / 数字矩阵" : "Live pressure matrix";
|
||||||
|
|
||||||
@@ -107,15 +104,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function recomputePanelLayout(): void {
|
function recomputePanelLayout(): void {
|
||||||
if (!stagePlaneEl || !topOverlayEl) {
|
if (!stagePlaneEl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const planeRect = stagePlaneEl.getBoundingClientRect();
|
panelZoneTopPx = showPrecisionTestPanel ? 24 : 16;
|
||||||
const overlayRect = topOverlayEl.getBoundingClientRect();
|
|
||||||
const overlayBottom = overlayRect.bottom - planeRect.top;
|
|
||||||
const upperTopLimit = Math.max(72, Math.round(stagePlaneEl.clientHeight * 0.34));
|
|
||||||
panelZoneTopPx = clamp(Math.round(overlayBottom + 8), 56, upperTopLimit);
|
|
||||||
|
|
||||||
const panelZoneBottomPx = panelZoneEl ? toPxNumber(getComputedStyle(panelZoneEl).bottom) : 0;
|
const panelZoneBottomPx = panelZoneEl ? toPxNumber(getComputedStyle(panelZoneEl).bottom) : 0;
|
||||||
const zoneHeight = Math.max(0, stagePlaneEl.clientHeight - panelZoneTopPx - panelZoneBottomPx);
|
const zoneHeight = Math.max(0, stagePlaneEl.clientHeight - panelZoneTopPx - panelZoneBottomPx);
|
||||||
@@ -159,10 +152,6 @@
|
|||||||
resizeObserver.observe(stagePlaneEl);
|
resizeObserver.observe(stagePlaneEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (topOverlayEl) {
|
|
||||||
resizeObserver.observe(topOverlayEl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (leftStackEl) {
|
if (leftStackEl) {
|
||||||
resizeObserver.observe(leftStackEl);
|
resizeObserver.observe(leftStackEl);
|
||||||
}
|
}
|
||||||
@@ -187,19 +176,6 @@
|
|||||||
bind:this={stagePlaneEl}
|
bind:this={stagePlaneEl}
|
||||||
style="--panel-zone-top-dyn: {panelZoneTopPx}px; --rail-scale-left: {leftRailScale}; --rail-scale-right: {rightRailScale};"
|
style="--panel-zone-top-dyn: {panelZoneTopPx}px; --rail-scale-left: {leftRailScale}; --rail-scale-right: {rightRailScale};"
|
||||||
>
|
>
|
||||||
{#if !showPrecisionTestPanel}
|
|
||||||
<div class="stage-top-overlay" bind:this={topOverlayEl}>
|
|
||||||
<div class="stage-meta">
|
|
||||||
<p class="meta-label">WebGL2 Stage</p>
|
|
||||||
<h2>{title}</h2>
|
|
||||||
<p class="meta-hint">{hint}</p>
|
|
||||||
</div>
|
|
||||||
<p class="runtime-status" class:is-ok={statusTone === "ok"} class:is-warn={statusTone === "warn"}>
|
|
||||||
{statusText}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if showPrecisionTestPanel}
|
{#if showPrecisionTestPanel}
|
||||||
<div class="split-game-wrap">
|
<div class="split-game-wrap">
|
||||||
<section class="split-panel split-matrix-panel">
|
<section class="split-panel split-matrix-panel">
|
||||||
@@ -210,12 +186,14 @@
|
|||||||
<div class="split-panel-body">
|
<div class="split-panel-body">
|
||||||
{#key `${matrixRows}x${matrixCols}:${colorMapPreset}:split`}
|
{#key `${matrixRows}x${matrixCols}:${colorMapPreset}:split`}
|
||||||
<PressureMatrixViewer
|
<PressureMatrixViewer
|
||||||
|
{summary}
|
||||||
{pressureMatrix}
|
{pressureMatrix}
|
||||||
{matrixRows}
|
{matrixRows}
|
||||||
{matrixCols}
|
{matrixCols}
|
||||||
{rangeMin}
|
{rangeMin}
|
||||||
{rangeMax}
|
{rangeMax}
|
||||||
{colorMapPreset}
|
{colorMapPreset}
|
||||||
|
{matrixDisplayMode}
|
||||||
showStatsPanel={true}
|
showStatsPanel={true}
|
||||||
/>
|
/>
|
||||||
{/key}
|
{/key}
|
||||||
@@ -238,12 +216,14 @@
|
|||||||
<div class="canvas-wrap">
|
<div class="canvas-wrap">
|
||||||
{#key `${matrixRows}x${matrixCols}:${colorMapPreset}`}
|
{#key `${matrixRows}x${matrixCols}:${colorMapPreset}`}
|
||||||
<PressureMatrixViewer
|
<PressureMatrixViewer
|
||||||
|
{summary}
|
||||||
{pressureMatrix}
|
{pressureMatrix}
|
||||||
{matrixRows}
|
{matrixRows}
|
||||||
{matrixCols}
|
{matrixCols}
|
||||||
{rangeMin}
|
{rangeMin}
|
||||||
{rangeMax}
|
{rangeMax}
|
||||||
{colorMapPreset}
|
{colorMapPreset}
|
||||||
|
{matrixDisplayMode}
|
||||||
showStatsPanel={true}
|
showStatsPanel={true}
|
||||||
/>
|
/>
|
||||||
{/key}
|
{/key}
|
||||||
@@ -290,7 +270,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#if summary.points.length > 0 && summarySide === "left"}
|
{#if summaryCurveVisible && summarySide === "left"}
|
||||||
<div
|
<div
|
||||||
class="panel-motion-shell"
|
class="panel-motion-shell"
|
||||||
in:fly={{ x: -180, duration: 340, opacity: 0.08, easing: cubicOut }}
|
in:fly={{ x: -180, duration: 340, opacity: 0.08, easing: cubicOut }}
|
||||||
@@ -321,7 +301,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#if summary.points.length > 0 && summarySide === "right"}
|
{#if summaryCurveVisible && summarySide === "right"}
|
||||||
<div
|
<div
|
||||||
class="panel-motion-shell"
|
class="panel-motion-shell"
|
||||||
in:fly={{ x: 180, duration: 340, opacity: 0.08, easing: cubicOut }}
|
in:fly={{ x: 180, duration: 340, opacity: 0.08, easing: cubicOut }}
|
||||||
@@ -427,75 +407,6 @@
|
|||||||
block-size: 100%;
|
block-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stage-top-overlay {
|
|
||||||
position: absolute;
|
|
||||||
top: clamp(0.55rem, 1.1vw, 0.9rem);
|
|
||||||
left: calc(var(--rail-width) + var(--safe-gap) + var(--rail-edge-inset));
|
|
||||||
right: calc(var(--rail-width) + var(--safe-gap) + var(--rail-edge-inset));
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 0.7rem;
|
|
||||||
z-index: 7;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stage-meta {
|
|
||||||
min-width: 0;
|
|
||||||
max-inline-size: min(22rem, 62%);
|
|
||||||
padding: 0.3rem 0.5rem 0.35rem;
|
|
||||||
border: 1px solid rgb(var(--hud-border-rgb) / 0.2);
|
|
||||||
border-radius: 0.45rem;
|
|
||||||
background: rgb(var(--hud-surface-deep-rgb) / 0.45);
|
|
||||||
backdrop-filter: blur(2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta-label {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 0.56rem;
|
|
||||||
color: rgb(var(--hud-text-dim-rgb) / 0.8);
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin: 0.08rem 0 0;
|
|
||||||
font-size: clamp(0.75rem, 1.1vw, 0.92rem);
|
|
||||||
color: rgb(var(--hud-text-main-rgb) / 0.96);
|
|
||||||
letter-spacing: 0.03em;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 1.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta-hint {
|
|
||||||
margin: 0.09rem 0 0;
|
|
||||||
font-size: 0.62rem;
|
|
||||||
color: rgb(var(--hud-text-dim-rgb) / 0.76);
|
|
||||||
line-height: 1.15;
|
|
||||||
}
|
|
||||||
|
|
||||||
.runtime-status {
|
|
||||||
margin: 0;
|
|
||||||
align-self: center;
|
|
||||||
border: 1px solid rgb(var(--hud-border-rgb) / 0.35);
|
|
||||||
border-radius: 999px;
|
|
||||||
padding: 0.3rem 0.66rem;
|
|
||||||
font-size: 0.66rem;
|
|
||||||
letter-spacing: 0.08em;
|
|
||||||
color: rgb(var(--hud-text-dim-rgb) / 0.9);
|
|
||||||
text-transform: uppercase;
|
|
||||||
white-space: nowrap;
|
|
||||||
background: rgb(var(--hud-surface-deep-rgb) / 0.62);
|
|
||||||
}
|
|
||||||
|
|
||||||
.runtime-status.is-ok {
|
|
||||||
color: rgb(var(--hud-lime-rgb) / 0.94);
|
|
||||||
}
|
|
||||||
|
|
||||||
.runtime-status.is-warn {
|
|
||||||
color: rgb(var(--hud-orange-rgb) / 0.92);
|
|
||||||
}
|
|
||||||
|
|
||||||
.canvas-wrap {
|
.canvas-wrap {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
|||||||
@@ -89,6 +89,10 @@
|
|||||||
colorMapPreset = "emerald";
|
colorMapPreset = "emerald";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSubmit(): void {
|
||||||
|
dispatch("close");
|
||||||
|
}
|
||||||
|
|
||||||
$: selectedColorMap = colorMapOptions.find((option) => option.id === colorMapPreset) ?? colorMapOptions[0];
|
$: selectedColorMap = colorMapOptions.find((option) => option.id === colorMapPreset) ?? colorMapOptions[0];
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
@@ -120,7 +124,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="config-panel" aria-label={title}>
|
<form class="config-panel" aria-label={title} on:submit|preventDefault={handleSubmit}>
|
||||||
<header class="config-head">
|
<header class="config-head">
|
||||||
<div class="config-copy">
|
<div class="config-copy">
|
||||||
<p class="config-label">Stage Config</p>
|
<p class="config-label">Stage Config</p>
|
||||||
@@ -214,7 +218,7 @@
|
|||||||
<p class="live-note">{applyLiveHint}</p>
|
<p class="live-note">{applyLiveHint}</p>
|
||||||
<button type="button" class="reset-btn" on:click={resetDefaults}>{resetLabel}</button>
|
<button type="button" class="reset-btn" on:click={resetDefaults}>{resetLabel}</button>
|
||||||
</footer>
|
</footer>
|
||||||
</section>
|
</form>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.config-panel {
|
.config-panel {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
HudConfigLink,
|
HudConfigLink,
|
||||||
HudNoticeTone,
|
HudNoticeTone,
|
||||||
LocaleCode,
|
LocaleCode,
|
||||||
|
MatrixDisplayMode,
|
||||||
WindowControlAction
|
WindowControlAction
|
||||||
} from "$lib/types/hud";
|
} from "$lib/types/hud";
|
||||||
|
|
||||||
@@ -29,6 +30,10 @@
|
|||||||
export let refreshPortsLabel = "";
|
export let refreshPortsLabel = "";
|
||||||
export let configLinksLabel = "";
|
export let configLinksLabel = "";
|
||||||
export let configLinks: HudConfigLink[] = [];
|
export let configLinks: HudConfigLink[] = [];
|
||||||
|
export let matrixViewLabel = "";
|
||||||
|
export let matrixViewNumericLabel = "";
|
||||||
|
export let matrixViewDotsLabel = "";
|
||||||
|
export let matrixDisplayMode: MatrixDisplayMode = "dots";
|
||||||
export let connectActionLabel = "";
|
export let connectActionLabel = "";
|
||||||
export let disconnectActionLabel = "";
|
export let disconnectActionLabel = "";
|
||||||
export let exportActionLabel = "";
|
export let exportActionLabel = "";
|
||||||
@@ -46,6 +51,7 @@
|
|||||||
windowcontrol: WindowControlAction;
|
windowcontrol: WindowControlAction;
|
||||||
localechange: LocaleCode;
|
localechange: LocaleCode;
|
||||||
configlink: string;
|
configlink: string;
|
||||||
|
matrixdisplaytoggle: boolean;
|
||||||
portchange: string;
|
portchange: string;
|
||||||
serialrefresh: void;
|
serialrefresh: void;
|
||||||
serialconnect: string;
|
serialconnect: string;
|
||||||
@@ -89,6 +95,10 @@
|
|||||||
dispatch("configlink", linkId);
|
dispatch("configlink", linkId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function emitMatrixDisplayToggle(): void {
|
||||||
|
dispatch("matrixdisplaytoggle", matrixDisplayMode !== "dots");
|
||||||
|
}
|
||||||
|
|
||||||
function emitPortChange(event: Event): void {
|
function emitPortChange(event: Event): void {
|
||||||
const target = event.currentTarget as HTMLSelectElement;
|
const target = event.currentTarget as HTMLSelectElement;
|
||||||
dispatch("portchange", target.value);
|
dispatch("portchange", target.value);
|
||||||
@@ -175,6 +185,24 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="matrix-switch-wrap" aria-label={matrixViewLabel}>
|
||||||
|
<span class="matrix-switch-label">{matrixViewLabel}</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="matrix-switch-btn"
|
||||||
|
class:is-active={matrixDisplayMode === "dots"}
|
||||||
|
role="switch"
|
||||||
|
aria-checked={matrixDisplayMode === "dots"}
|
||||||
|
aria-label={matrixViewDotsLabel}
|
||||||
|
on:click={emitMatrixDisplayToggle}
|
||||||
|
>
|
||||||
|
<span class="matrix-switch-track" aria-hidden="true">
|
||||||
|
<span class="matrix-switch-thumb"></span>
|
||||||
|
</span>
|
||||||
|
<span class="matrix-switch-copy">{matrixDisplayMode === "dots" ? matrixViewDotsLabel : matrixViewNumericLabel}</span>
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="state-card" aria-label={connectionLabel}>
|
<section class="state-card" aria-label={connectionLabel}>
|
||||||
<span class="state-dot" class:ok={connectionTone === "ok"} class:warn={connectionTone === "warn"}></span>
|
<span class="state-dot" class:ok={connectionTone === "ok"} class:warn={connectionTone === "warn"}></span>
|
||||||
<span class="state-label">{connectionLabel}</span>
|
<span class="state-label">{connectionLabel}</span>
|
||||||
@@ -432,6 +460,108 @@
|
|||||||
background: var(--panel-surface);
|
background: var(--panel-surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.matrix-switch-wrap {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.4rem;
|
||||||
|
min-block-size: 2rem;
|
||||||
|
border: 1px solid var(--panel-line);
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 0.16rem 0.22rem 0.16rem 0.56rem;
|
||||||
|
background: var(--panel-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
.matrix-switch-label {
|
||||||
|
color: var(--panel-text-dim);
|
||||||
|
font-size: 0.66rem;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.matrix-switch-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.42rem;
|
||||||
|
min-block-size: 1.62rem;
|
||||||
|
border: 1px solid rgb(var(--hud-border-rgb) / 0.26);
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 0.18rem 0.28rem 0.18rem 0.22rem;
|
||||||
|
background: rgb(var(--hud-surface-deep-rgb) / 0.84);
|
||||||
|
color: rgb(var(--hud-text-main-rgb) / 0.92);
|
||||||
|
cursor: pointer;
|
||||||
|
transition:
|
||||||
|
border-color 180ms ease,
|
||||||
|
box-shadow 180ms ease,
|
||||||
|
background-color 180ms ease,
|
||||||
|
color 180ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.matrix-switch-btn:hover {
|
||||||
|
border-color: rgb(var(--hud-cyan-rgb) / 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.matrix-switch-btn.is-active {
|
||||||
|
border-color: rgb(var(--hud-cyan-rgb) / 0.5);
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgb(var(--hud-surface-alt-rgb) / 0.94), rgb(var(--hud-surface-rgb) / 0.9)),
|
||||||
|
radial-gradient(circle at 50% 0, rgb(var(--hud-cyan-rgb) / 0.12), transparent 60%);
|
||||||
|
box-shadow:
|
||||||
|
inset 0 0 0 1px rgb(var(--hud-text-main-rgb) / 0.05),
|
||||||
|
0 0 12px rgb(var(--hud-cyan-rgb) / 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.matrix-switch-track {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
inline-size: 2.2rem;
|
||||||
|
block-size: 1.2rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 0.14rem;
|
||||||
|
background: rgb(var(--hud-surface-rgb) / 0.9);
|
||||||
|
box-shadow: inset 0 0 0 1px rgb(var(--hud-border-rgb) / 0.24);
|
||||||
|
transition:
|
||||||
|
background-color 180ms ease,
|
||||||
|
box-shadow 180ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.matrix-switch-btn.is-active .matrix-switch-track {
|
||||||
|
background: rgb(var(--hud-cyan-rgb) / 0.18);
|
||||||
|
box-shadow: inset 0 0 0 1px rgb(var(--hud-cyan-rgb) / 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.matrix-switch-thumb {
|
||||||
|
inline-size: 0.92rem;
|
||||||
|
block-size: 0.92rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgb(var(--hud-text-main-rgb) / 0.96);
|
||||||
|
box-shadow:
|
||||||
|
0 1px 4px rgb(0 0 0 / 0.26),
|
||||||
|
0 0 10px rgb(var(--hud-text-main-rgb) / 0.12);
|
||||||
|
transform: translateX(0);
|
||||||
|
transition:
|
||||||
|
transform 180ms ease,
|
||||||
|
background-color 180ms ease,
|
||||||
|
box-shadow 180ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.matrix-switch-btn.is-active .matrix-switch-thumb {
|
||||||
|
transform: translateX(0.96rem);
|
||||||
|
background: rgb(var(--hud-cyan-rgb) / 0.96);
|
||||||
|
box-shadow:
|
||||||
|
0 1px 4px rgb(0 0 0 / 0.26),
|
||||||
|
0 0 12px rgb(var(--hud-cyan-rgb) / 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.matrix-switch-copy {
|
||||||
|
font-size: 0.74rem;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
white-space: nowrap;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.state-dot {
|
.state-dot {
|
||||||
inline-size: 0.55rem;
|
inline-size: 0.55rem;
|
||||||
block-size: 0.55rem;
|
block-size: 0.55rem;
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
||||||
import { pressureColorPalettes } from "$lib/config/color-map";
|
import { pressureColorPalettes } from "$lib/config/color-map";
|
||||||
import type { PressureColorMapPreset } from "$lib/types/hud";
|
import type { HudSummary, MatrixDisplayMode, PressureColorMapPreset } from "$lib/types/hud";
|
||||||
|
|
||||||
interface ViewerStats {
|
interface ViewerStats {
|
||||||
total: number;
|
current: number | null;
|
||||||
max: number;
|
max: number | null;
|
||||||
avg: number;
|
min: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MatrixLayout {
|
interface MatrixLayout {
|
||||||
@@ -28,12 +28,14 @@
|
|||||||
export let rangeMin = 0;
|
export let rangeMin = 0;
|
||||||
export let rangeMax = 16000;
|
export let rangeMax = 16000;
|
||||||
export let colorMapPreset: PressureColorMapPreset = "emerald";
|
export let colorMapPreset: PressureColorMapPreset = "emerald";
|
||||||
|
export let matrixDisplayMode: MatrixDisplayMode = "dots";
|
||||||
|
export let summary: HudSummary | null = null;
|
||||||
export let showStatsPanel = true;
|
export let showStatsPanel = true;
|
||||||
|
|
||||||
let viewerEl: HTMLDivElement | undefined;
|
let viewerEl: HTMLDivElement | undefined;
|
||||||
let canvasEl: HTMLCanvasElement | undefined;
|
let canvasEl: HTMLCanvasElement | undefined;
|
||||||
let overlayEl: HTMLCanvasElement | undefined;
|
let overlayEl: HTMLCanvasElement | undefined;
|
||||||
let stats: ViewerStats = { total: 0, max: 0, avg: 0 };
|
let stats: ViewerStats = { current: null, max: null, min: null };
|
||||||
|
|
||||||
const DEFAULT_RANGE_MAX = 16000;
|
const DEFAULT_RANGE_MAX = 16000;
|
||||||
const BASE_MATRIX_SPAN = 24;
|
const BASE_MATRIX_SPAN = 24;
|
||||||
@@ -63,6 +65,7 @@
|
|||||||
const CAMERA_TARGET_Y = MATRIX_OFFSET_Y + 0.2;
|
const CAMERA_TARGET_Y = MATRIX_OFFSET_Y + 0.2;
|
||||||
const CAMERA_TARGET_Z = MATRIX_OFFSET_Z - 0.4;
|
const CAMERA_TARGET_Z = MATRIX_OFFSET_Z - 0.4;
|
||||||
const MATRIX_ROTATION_Y = 0;
|
const MATRIX_ROTATION_Y = 0;
|
||||||
|
const rangeStopPositions = [0, 0.25, 0.5, 0.75, 0.875, 1] as const;
|
||||||
|
|
||||||
const labelVector = new THREE.Vector3();
|
const labelVector = new THREE.Vector3();
|
||||||
$: resolvedColorPalette = pressureColorPalettes[colorMapPreset] ?? pressureColorPalettes.emerald;
|
$: resolvedColorPalette = pressureColorPalettes[colorMapPreset] ?? pressureColorPalettes.emerald;
|
||||||
@@ -75,6 +78,7 @@
|
|||||||
$: labelLowColor = new THREE.Color(resolvedColorPalette.labelLow);
|
$: labelLowColor = new THREE.Color(resolvedColorPalette.labelLow);
|
||||||
$: labelMidColor = new THREE.Color(resolvedColorPalette.labelMid);
|
$: labelMidColor = new THREE.Color(resolvedColorPalette.labelMid);
|
||||||
$: labelHighColor = new THREE.Color(resolvedColorPalette.labelHigh);
|
$: labelHighColor = new THREE.Color(resolvedColorPalette.labelHigh);
|
||||||
|
$: rangeStopColors = resolvedColorPalette.rangeStops.map((stop) => new THREE.Color(stop));
|
||||||
$: sceneClearColor = new THREE.Color(resolvedColorPalette.uiTheme.bg30);
|
$: sceneClearColor = new THREE.Color(resolvedColorPalette.uiTheme.bg30);
|
||||||
$: sceneBoardColor = new THREE.Color(resolvedColorPalette.uiTheme.bg20);
|
$: sceneBoardColor = new THREE.Color(resolvedColorPalette.uiTheme.bg20);
|
||||||
$: sceneGridCenterColor = new THREE.Color(resolvedColorPalette.surfaceMid);
|
$: sceneGridCenterColor = new THREE.Color(resolvedColorPalette.surfaceMid);
|
||||||
@@ -84,7 +88,7 @@
|
|||||||
$: sceneAccentLightColor = rgbTripletToThreeColor(resolvedColorPalette.uiTheme.glowRgb);
|
$: sceneAccentLightColor = rgbTripletToThreeColor(resolvedColorPalette.uiTheme.glowRgb);
|
||||||
$: surfaceThemeAccentColor = rgbTripletToThreeColor(resolvedColorPalette.uiTheme.glowRgb);
|
$: surfaceThemeAccentColor = rgbTripletToThreeColor(resolvedColorPalette.uiTheme.glowRgb);
|
||||||
$: labelThemeAccentColor = rgbTripletToThreeColor(resolvedColorPalette.uiTheme.glowRgb);
|
$: labelThemeAccentColor = rgbTripletToThreeColor(resolvedColorPalette.uiTheme.glowRgb);
|
||||||
$: labelHighlightCss = colorToCss(surfaceHotColor);
|
$: labelHighlightCss = colorToCss(rangeStopColors[5] ?? surfaceHotColor);
|
||||||
$: viewerThemeStyle = [
|
$: viewerThemeStyle = [
|
||||||
`--matrix-bg-10: ${resolvedColorPalette.uiTheme.bg10}`,
|
`--matrix-bg-10: ${resolvedColorPalette.uiTheme.bg10}`,
|
||||||
`--matrix-bg-20: ${resolvedColorPalette.uiTheme.bg20}`,
|
`--matrix-bg-20: ${resolvedColorPalette.uiTheme.bg20}`,
|
||||||
@@ -124,7 +128,16 @@
|
|||||||
$: resolvedRangeMin = resolvedRange.min;
|
$: resolvedRangeMin = resolvedRange.min;
|
||||||
$: resolvedRangeMax = resolvedRange.max;
|
$: resolvedRangeMax = resolvedRange.max;
|
||||||
$: matrixLayout = buildMatrixLayout(resolvedMatrixRows, resolvedMatrixCols);
|
$: matrixLayout = buildMatrixLayout(resolvedMatrixRows, resolvedMatrixCols);
|
||||||
$: statsNote = `${resolvedMatrixRows}x${resolvedMatrixCols} / color range ${resolvedRangeMin}-${resolvedRangeMax} / label raw`;
|
$: statsModeLabel = matrixDisplayMode === "dots" ? "dot pulse" : "numeric pulse";
|
||||||
|
$: statsNote = `${resolvedMatrixRows}x${resolvedMatrixCols} / force range ${resolvedRangeMin}-${resolvedRangeMax} / ${statsModeLabel}`;
|
||||||
|
|
||||||
|
function formatForceStat(value: number | null): string {
|
||||||
|
if (value == null || !Number.isFinite(value)) {
|
||||||
|
return "--";
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.toFixed(1);
|
||||||
|
}
|
||||||
|
|
||||||
function clamp(value: number, min: number, max: number): number {
|
function clamp(value: number, min: number, max: number): number {
|
||||||
return Math.min(max, Math.max(min, value));
|
return Math.min(max, Math.max(min, value));
|
||||||
@@ -143,23 +156,26 @@
|
|||||||
return new THREE.Color(`rgb(${rgbTriplet.replace(/\s+/g, ", ")})`);
|
return new THREE.Color(`rgb(${rgbTriplet.replace(/\s+/g, ", ")})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function surfaceColorMap(valueNormalized: number, target: THREE.Color = new THREE.Color()): THREE.Color {
|
function sampleRangeStopColor(valueNormalized: number, target: THREE.Color = new THREE.Color()): THREE.Color {
|
||||||
const value = clamp(valueNormalized, 0, 1);
|
const value = clamp(valueNormalized, 0, 1);
|
||||||
let mapped: THREE.Color;
|
|
||||||
|
|
||||||
if (value <= 0.45) {
|
for (let index = 0; index < rangeStopPositions.length - 1; index += 1) {
|
||||||
const t = smoothstep(0, 0.45, value);
|
const start = rangeStopPositions[index];
|
||||||
mapped = target.copy(surfaceBaseColor).lerp(surfaceLowColor, t);
|
const end = rangeStopPositions[index + 1];
|
||||||
} else if (value <= 0.78) {
|
if (value <= end) {
|
||||||
const t = smoothstep(0.45, 0.78, value);
|
const localT = smoothstep(start, end, value);
|
||||||
mapped = target.copy(surfaceLowColor).lerp(surfaceMidColor, t);
|
return target.copy(rangeStopColors[index]).lerp(rangeStopColors[index + 1], localT);
|
||||||
} else {
|
}
|
||||||
const t = smoothstep(0.78, 1, value);
|
|
||||||
mapped = target.copy(surfaceMidColor).lerp(surfaceHighColor, t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseAccentStrength = (1 - smoothstep(0.12, 0.52, value)) * 0.34;
|
return target.copy(rangeStopColors[rangeStopColors.length - 1]);
|
||||||
const highlightStrength = smoothstep(0.82, 1, value) * 0.3;
|
}
|
||||||
|
|
||||||
|
function surfaceColorMap(valueNormalized: number, target: THREE.Color = new THREE.Color()): THREE.Color {
|
||||||
|
const value = clamp(valueNormalized, 0, 1);
|
||||||
|
const mapped = sampleRangeStopColor(value, target);
|
||||||
|
const baseAccentStrength = (1 - smoothstep(0.08, 0.28, value)) * 0.16;
|
||||||
|
const highlightStrength = smoothstep(0.88, 1, value) * 0.2;
|
||||||
return mapped.lerp(surfaceThemeAccentColor, baseAccentStrength).lerp(surfaceHotColor, highlightStrength);
|
return mapped.lerp(surfaceThemeAccentColor, baseAccentStrength).lerp(surfaceHotColor, highlightStrength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,22 +187,10 @@
|
|||||||
|
|
||||||
function labelColorMap(valueNormalized: number, target: THREE.Color = new THREE.Color()): THREE.Color {
|
function labelColorMap(valueNormalized: number, target: THREE.Color = new THREE.Color()): THREE.Color {
|
||||||
const value = clamp(valueNormalized, 0, 1);
|
const value = clamp(valueNormalized, 0, 1);
|
||||||
let mapped: THREE.Color;
|
const mapped = sampleRangeStopColor(value, target);
|
||||||
|
const baseAccentStrength = (1 - smoothstep(0.08, 0.24, value)) * 0.18;
|
||||||
if (value <= 0.34) {
|
const highlightStrength = smoothstep(0.88, 1, value) * 0.12;
|
||||||
const t = smoothstep(0, 0.34, value);
|
return mapped.lerp(labelThemeAccentColor, baseAccentStrength).lerp(labelHighColor, highlightStrength);
|
||||||
mapped = target.copy(labelZeroColor).lerp(labelLowColor, t);
|
|
||||||
} else if (value <= 0.76) {
|
|
||||||
const t = smoothstep(0.34, 0.76, value);
|
|
||||||
mapped = target.copy(labelLowColor).lerp(labelMidColor, t);
|
|
||||||
} else {
|
|
||||||
const t = smoothstep(0.76, 1, value);
|
|
||||||
mapped = target.copy(labelMidColor).lerp(labelHighColor, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseAccentStrength = (1 - smoothstep(0.16, 0.58, value)) * 0.46;
|
|
||||||
const highlightStrength = smoothstep(0.8, 1, value) * 0.36;
|
|
||||||
return mapped.lerp(labelThemeAccentColor, baseAccentStrength).lerp(surfaceHotColor, highlightStrength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function shapeHeightValue(valueNormalized: number): number {
|
function shapeHeightValue(valueNormalized: number): number {
|
||||||
@@ -263,6 +267,24 @@
|
|||||||
return `rgb(${Math.round(color.r * 255)} ${Math.round(color.g * 255)} ${Math.round(color.b * 255)})`;
|
return `rgb(${Math.round(color.r * 255)} ${Math.round(color.g * 255)} ${Math.round(color.b * 255)})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function drawProjectedDot(
|
||||||
|
context: CanvasRenderingContext2D,
|
||||||
|
screenX: number,
|
||||||
|
screenY: number,
|
||||||
|
radius: number,
|
||||||
|
fillStyle: string,
|
||||||
|
glowStyle: string,
|
||||||
|
opacity: number
|
||||||
|
): void {
|
||||||
|
context.globalAlpha = opacity;
|
||||||
|
context.shadowBlur = radius * 2.8;
|
||||||
|
context.shadowColor = glowStyle;
|
||||||
|
context.fillStyle = fillStyle;
|
||||||
|
context.beginPath();
|
||||||
|
context.arc(screenX, screenY, radius, 0, Math.PI * 2);
|
||||||
|
context.fill();
|
||||||
|
}
|
||||||
|
|
||||||
$: labelPalette = Array.from({ length: 33 }, (_, index) => {
|
$: labelPalette = Array.from({ length: 33 }, (_, index) => {
|
||||||
const t = index / 32;
|
const t = index / 32;
|
||||||
return colorToCss(labelColorMap(t, new THREE.Color()));
|
return colorToCss(labelColorMap(t, new THREE.Color()));
|
||||||
@@ -431,7 +453,7 @@
|
|||||||
const compactField = new Uint16Array(instanceCount);
|
const compactField = new Uint16Array(instanceCount);
|
||||||
let lastFrameAt = performance.now();
|
let lastFrameAt = performance.now();
|
||||||
|
|
||||||
const drawNumberOverlay = () => {
|
const drawOverlay = () => {
|
||||||
if (!viewerEl || !overlayEl) {
|
if (!viewerEl || !overlayEl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -464,10 +486,42 @@
|
|||||||
|
|
||||||
const normalized = normalizedField[index];
|
const normalized = normalizedField[index];
|
||||||
const displayValue = compactField[index];
|
const displayValue = compactField[index];
|
||||||
|
const bucket = Math.min(32, Math.round(normalized * 32));
|
||||||
|
const isDotsMode = matrixDisplayMode === "dots";
|
||||||
|
|
||||||
|
if (isDotsMode) {
|
||||||
|
const baseDotRadius = clamp(cellSpacing * 0.48, 7.2, 21.6);
|
||||||
|
const dotRadius = clamp(baseDotRadius + smoothstep(0, 1, normalized) * (cellSpacing * 0.86 + 9.6), 7.2, 15);
|
||||||
|
const dotOpacity = displayValue === 0 ? 0.62 : 0.98;
|
||||||
|
|
||||||
|
drawProjectedDot(
|
||||||
|
overlayContext,
|
||||||
|
screenX,
|
||||||
|
screenY,
|
||||||
|
dotRadius,
|
||||||
|
labelPalette[bucket],
|
||||||
|
labelGlowPalette[bucket],
|
||||||
|
dotOpacity
|
||||||
|
);
|
||||||
|
|
||||||
|
if (normalized >= 0.8) {
|
||||||
|
drawProjectedDot(
|
||||||
|
overlayContext,
|
||||||
|
screenX,
|
||||||
|
screenY,
|
||||||
|
dotRadius * 0.46,
|
||||||
|
labelHighlightCss,
|
||||||
|
labelHighlightCss,
|
||||||
|
smoothstep(0.8, 1, normalized) * 0.42
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const displayText = String(displayValue);
|
const displayText = String(displayValue);
|
||||||
const digitCount = displayText.length;
|
const digitCount = displayText.length;
|
||||||
const digitScale = digitCount <= 2 ? 1 : digitCount === 3 ? 0.86 : digitCount === 4 ? 0.74 : 0.64;
|
const digitScale = digitCount <= 2 ? 1 : digitCount === 3 ? 0.86 : digitCount === 4 ? 0.74 : 0.64;
|
||||||
const bucket = Math.min(32, Math.round(normalized * 32));
|
|
||||||
const baseGlyphSize = fontSize + smoothstep(0, 1, normalized) * (2.3 * labelScale + cellSpacing * 0.26);
|
const baseGlyphSize = fontSize + smoothstep(0, 1, normalized) * (2.3 * labelScale + cellSpacing * 0.26);
|
||||||
const glyphSize = clamp(baseGlyphSize * digitScale, 5.2, 26);
|
const glyphSize = clamp(baseGlyphSize * digitScale, 5.2, 26);
|
||||||
const glowSizeFactor = digitCount >= 4 ? 0.76 : digitCount === 3 ? 0.88 : 1;
|
const glowSizeFactor = digitCount >= 4 ? 0.76 : digitCount === 3 ? 0.88 : 1;
|
||||||
@@ -476,7 +530,6 @@
|
|||||||
overlayContext.font = `600 ${glyphSize.toFixed(1)}px "JetBrains Mono", "IBM Plex Mono", "Consolas", monospace`;
|
overlayContext.font = `600 ${glyphSize.toFixed(1)}px "JetBrains Mono", "IBM Plex Mono", "Consolas", monospace`;
|
||||||
overlayContext.shadowBlur = glowBlur;
|
overlayContext.shadowBlur = glowBlur;
|
||||||
overlayContext.shadowColor = labelGlowPalette[bucket];
|
overlayContext.shadowColor = labelGlowPalette[bucket];
|
||||||
|
|
||||||
overlayContext.fillStyle = labelPalette[bucket];
|
overlayContext.fillStyle = labelPalette[bucket];
|
||||||
overlayContext.globalAlpha = displayValue === 0 ? 0.86 : 1;
|
overlayContext.globalAlpha = displayValue === 0 ? 0.86 : 1;
|
||||||
overlayContext.fillText(displayText, screenX, screenY);
|
overlayContext.fillText(displayText, screenX, screenY);
|
||||||
@@ -550,9 +603,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const maxValue = normalizeField(smoothedField, normalizedField, resolvedRangeMin, resolvedRangeMax);
|
const maxValue = normalizeField(smoothedField, normalizedField, resolvedRangeMin, resolvedRangeMax);
|
||||||
let total = 0;
|
|
||||||
let activeCount = 0;
|
|
||||||
|
|
||||||
for (let index = 0; index < instanceCount; index += 1) {
|
for (let index = 0; index < instanceCount; index += 1) {
|
||||||
const normalized = normalizedField[index];
|
const normalized = normalizedField[index];
|
||||||
const heightValue = shapeHeightValue(normalized);
|
const heightValue = shapeHeightValue(normalized);
|
||||||
@@ -560,20 +610,15 @@
|
|||||||
|
|
||||||
heightField[index] = height;
|
heightField[index] = height;
|
||||||
compactField[index] = compactDisplayValue(smoothedField[index], resolvedRangeMin, resolvedRangeMax);
|
compactField[index] = compactDisplayValue(smoothedField[index], resolvedRangeMin, resolvedRangeMax);
|
||||||
|
|
||||||
total += smoothedField[index];
|
|
||||||
if (smoothedField[index] > 30) {
|
|
||||||
activeCount += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.render(scene, camera);
|
renderer.render(scene, camera);
|
||||||
drawNumberOverlay();
|
drawOverlay();
|
||||||
|
|
||||||
stats = {
|
stats = {
|
||||||
total,
|
current: summary?.latest ?? null,
|
||||||
max: maxValue,
|
max: summary?.max ?? null,
|
||||||
avg: activeCount > 0 ? total / activeCount : 0
|
min: summary?.min ?? null
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -612,19 +657,19 @@
|
|||||||
{#if showStatsPanel}
|
{#if showStatsPanel}
|
||||||
<div class="viewer-controls">
|
<div class="viewer-controls">
|
||||||
<section class="stats-panel" aria-label="Pressure Summary">
|
<section class="stats-panel" aria-label="Pressure Summary">
|
||||||
<p class="stats-label">Pressure Matrix</p>
|
<p class="stats-label">Resultant Force</p>
|
||||||
<div class="stats-grid">
|
<div class="stats-grid">
|
||||||
<article class="stats-card stats-card-wide">
|
<article class="stats-card stats-card-wide">
|
||||||
<span class="stats-key">Total Pressure</span>
|
<span class="stats-key">Current RF</span>
|
||||||
<strong class="stats-value">{stats.total.toFixed(0)}</strong>
|
<strong class="stats-value">{formatForceStat(stats.current)}</strong>
|
||||||
</article>
|
</article>
|
||||||
<article class="stats-card">
|
<article class="stats-card">
|
||||||
<span class="stats-key">Max</span>
|
<span class="stats-key">Max RF</span>
|
||||||
<strong class="stats-value">{stats.max.toFixed(0)}</strong>
|
<strong class="stats-value">{formatForceStat(stats.max)}</strong>
|
||||||
</article>
|
</article>
|
||||||
<article class="stats-card">
|
<article class="stats-card">
|
||||||
<span class="stats-key">Avg</span>
|
<span class="stats-key">Min RF</span>
|
||||||
<strong class="stats-value">{stats.avg.toFixed(0)}</strong>
|
<strong class="stats-value">{formatForceStat(stats.min)}</strong>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<p class="stats-note">{statsNote}</p>
|
<p class="stats-note">{statsNote}</p>
|
||||||
|
|||||||
@@ -7,10 +7,13 @@
|
|||||||
export let xValues: number[] | null = null;
|
export let xValues: number[] | null = null;
|
||||||
export let yValues: number[] | null = null;
|
export let yValues: number[] | null = null;
|
||||||
|
|
||||||
const viewportWidth = 100;
|
const viewportWidth = 120;
|
||||||
const viewportHeight = 36;
|
const viewportHeight = 48;
|
||||||
const horizontalInset = 2;
|
const plotInsetLeft = 13;
|
||||||
const verticalInset = 2;
|
const plotInsetRight = 4;
|
||||||
|
const plotInsetTop = 4;
|
||||||
|
const plotInsetBottom = 9;
|
||||||
|
const fixedYBounds = { min: 0, max: 25 };
|
||||||
|
|
||||||
interface CurveSample {
|
interface CurveSample {
|
||||||
x: number;
|
x: number;
|
||||||
@@ -50,12 +53,7 @@
|
|||||||
return String(Math.round(value));
|
return String(Math.round(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Math.abs(value) >= 1000) {
|
return `${Math.round(value)} N`;
|
||||||
const compact = Math.round((value / 1000) * 10) / 10;
|
|
||||||
return Number.isInteger(compact) ? `${compact.toFixed(0)}k` : `${compact.toFixed(1)}k`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.abs(value) >= 100 ? Math.round(value).toString() : value.toFixed(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveDataBounds(values: number[]): { min: number; max: number } {
|
function resolveDataBounds(values: number[]): { min: number; max: number } {
|
||||||
@@ -87,18 +85,18 @@
|
|||||||
|
|
||||||
function mapXToViewport(value: number, bounds: { min: number; max: number }): number {
|
function mapXToViewport(value: number, bounds: { min: number; max: number }): number {
|
||||||
const span = bounds.max - bounds.min;
|
const span = bounds.max - bounds.min;
|
||||||
const chartWidth = viewportWidth - horizontalInset * 2;
|
const chartWidth = viewportWidth - plotInsetLeft - plotInsetRight;
|
||||||
const ratio = span <= 0 ? 0.5 : (value - bounds.min) / span;
|
const ratio = span <= 0 ? 0.5 : (value - bounds.min) / span;
|
||||||
const mappedX = horizontalInset + ratio * chartWidth;
|
const mappedX = plotInsetLeft + ratio * chartWidth;
|
||||||
return Math.round(clamp(mappedX, horizontalInset, viewportWidth - horizontalInset) * 100) / 100;
|
return Math.round(clamp(mappedX, plotInsetLeft, viewportWidth - plotInsetRight) * 100) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapYToViewport(value: number, bounds: { min: number; max: number }): number {
|
function mapYToViewport(value: number, bounds: { min: number; max: number }): number {
|
||||||
const span = bounds.max - bounds.min;
|
const span = bounds.max - bounds.min;
|
||||||
const chartHeight = viewportHeight - verticalInset * 2;
|
const chartHeight = viewportHeight - plotInsetTop - plotInsetBottom;
|
||||||
const ratio = span <= 0 ? 0.5 : (value - bounds.min) / span;
|
const ratio = span <= 0 ? 0.5 : (value - bounds.min) / span;
|
||||||
const mappedY = viewportHeight - verticalInset - ratio * chartHeight;
|
const mappedY = viewportHeight - plotInsetBottom - ratio * chartHeight;
|
||||||
return Math.round(clamp(mappedY, verticalInset, viewportHeight - verticalInset) * 100) / 100;
|
return Math.round(clamp(mappedY, plotInsetTop, viewportHeight - plotInsetBottom) * 100) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildSamples(rawYValues: number[], rawXValues: number[]): CurveSample[] {
|
function buildSamples(rawYValues: number[], rawXValues: number[]): CurveSample[] {
|
||||||
@@ -137,16 +135,13 @@
|
|||||||
|
|
||||||
function buildYAxisTicks(
|
function buildYAxisTicks(
|
||||||
yScaleBounds: { min: number; max: number },
|
yScaleBounds: { min: number; max: number },
|
||||||
yDataBounds: { min: number; max: number }
|
_yDataBounds: { min: number; max: number }
|
||||||
): AxisTick[] {
|
): AxisTick[] {
|
||||||
const hasRange = Math.abs(yDataBounds.max - yDataBounds.min) >= 0.001;
|
const tickValues = [25, 20, 15, 10, 5, 0];
|
||||||
const tickValues = hasRange
|
|
||||||
? [yDataBounds.max, (yDataBounds.max + yDataBounds.min) / 2, yDataBounds.min]
|
|
||||||
: [yScaleBounds.max, (yScaleBounds.max + yScaleBounds.min) / 2, yScaleBounds.min];
|
|
||||||
return tickValues.map((value) => ({
|
return tickValues.map((value) => ({
|
||||||
value,
|
value,
|
||||||
label: formatAxisValue(value, "y"),
|
label: formatAxisValue(value, "y"),
|
||||||
plotX: horizontalInset,
|
plotX: plotInsetLeft - 1.8,
|
||||||
plotY: mapYToViewport(value, yScaleBounds)
|
plotY: mapYToViewport(value, yScaleBounds)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -164,7 +159,7 @@
|
|||||||
value,
|
value,
|
||||||
label: formatAxisValue(value, "x"),
|
label: formatAxisValue(value, "x"),
|
||||||
plotX: mapXToViewport(value, xScaleBounds),
|
plotX: mapXToViewport(value, xScaleBounds),
|
||||||
plotY: viewportHeight - 1.2
|
plotY: viewportHeight - 0.9
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +180,7 @@
|
|||||||
const firstPoint = points[0];
|
const firstPoint = points[0];
|
||||||
const lastPoint = points[points.length - 1];
|
const lastPoint = points[points.length - 1];
|
||||||
|
|
||||||
return `${linePath} L ${lastPoint.x} ${viewportHeight} L ${firstPoint.x} ${viewportHeight} Z`;
|
return `${linePath} L ${lastPoint.x} ${viewportHeight - plotInsetBottom} L ${firstPoint.x} ${viewportHeight - plotInsetBottom} Z`;
|
||||||
}
|
}
|
||||||
|
|
||||||
$: sourceYValues = yValues && yValues.length ? yValues : summary.points;
|
$: sourceYValues = yValues && yValues.length ? yValues : summary.points;
|
||||||
@@ -193,7 +188,7 @@
|
|||||||
$: samples = buildSamples(sourceYValues, sourceXValues);
|
$: samples = buildSamples(sourceYValues, sourceXValues);
|
||||||
$: sampleCount = samples.length;
|
$: sampleCount = samples.length;
|
||||||
$: xScaleBounds = resolveBounds(samples.map((sample) => sample.x));
|
$: xScaleBounds = resolveBounds(samples.map((sample) => sample.x));
|
||||||
$: yScaleBounds = resolveBounds(samples.map((sample) => sample.y));
|
$: yScaleBounds = fixedYBounds;
|
||||||
$: xDataBounds = resolveDataBounds(samples.map((sample) => sample.x));
|
$: xDataBounds = resolveDataBounds(samples.map((sample) => sample.x));
|
||||||
$: yDataBounds = resolveDataBounds(samples.map((sample) => sample.y));
|
$: yDataBounds = resolveDataBounds(samples.map((sample) => sample.y));
|
||||||
$: plotPoints = convertPoints(samples, xScaleBounds, yScaleBounds);
|
$: plotPoints = convertPoints(samples, xScaleBounds, yScaleBounds);
|
||||||
@@ -215,7 +210,7 @@
|
|||||||
>
|
>
|
||||||
<header class="panel-head">
|
<header class="panel-head">
|
||||||
<div class="head-text">
|
<div class="head-text">
|
||||||
<p class="panel-code">TOT</p>
|
<p class="panel-code">RF</p>
|
||||||
<p class="panel-title">{summary.label}</p>
|
<p class="panel-title">{summary.label}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -236,8 +231,8 @@
|
|||||||
</defs>
|
</defs>
|
||||||
|
|
||||||
<g class="grid-lines" aria-hidden="true">
|
<g class="grid-lines" aria-hidden="true">
|
||||||
{#each [6, 12, 18, 24, 30] as y}
|
{#each yAxisTicks as tick (`grid-${tick.value}`)}
|
||||||
<line x1="0" y1={y} x2={viewportWidth} y2={y}></line>
|
<line x1={plotInsetLeft} y1={tick.plotY} x2={viewportWidth - plotInsetRight} y2={tick.plotY}></line>
|
||||||
{/each}
|
{/each}
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
@@ -255,7 +250,7 @@
|
|||||||
|
|
||||||
<g class="axis-labels" aria-hidden="true">
|
<g class="axis-labels" aria-hidden="true">
|
||||||
{#each yAxisTicks as tick, index (`y-${index}`)}
|
{#each yAxisTicks as tick, index (`y-${index}`)}
|
||||||
<text class="axis-label y-axis-label" x={tick.plotX + 0.8} y={tick.plotY - 0.35} text-anchor="start">
|
<text class="axis-label y-axis-label" x={tick.plotX} y={tick.plotY + 1.1} text-anchor="end">
|
||||||
{tick.label}
|
{tick.label}
|
||||||
</text>
|
</text>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -305,14 +300,14 @@
|
|||||||
--enter-ms: 1800ms;
|
--enter-ms: 1800ms;
|
||||||
--fade-ms: 1000ms;
|
--fade-ms: 1000ms;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
inline-size: min(100%, clamp(16.8rem, 23vw, 22rem));
|
inline-size: min(100%, clamp(29rem, 38vw, 37rem));
|
||||||
aspect-ratio: 1.44 / 1;
|
aspect-ratio: 1.42 / 1;
|
||||||
min-block-size: 11.8rem;
|
min-block-size: 20.5rem;
|
||||||
justify-self: start;
|
justify-self: start;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto auto auto;
|
grid-template-rows: auto auto auto;
|
||||||
gap: 0.4rem;
|
gap: 0.68rem;
|
||||||
padding: 0.56rem 0.62rem 0.58rem;
|
padding: 0.88rem 0.96rem 1rem;
|
||||||
border: 1px solid rgb(var(--hud-border-strong-rgb) / 0.42);
|
border: 1px solid rgb(var(--hud-border-strong-rgb) / 0.42);
|
||||||
border-radius: 0.92rem;
|
border-radius: 0.92rem;
|
||||||
background:
|
background:
|
||||||
@@ -345,6 +340,10 @@
|
|||||||
opacity: 0.82;
|
opacity: 0.82;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.summary-panel {
|
||||||
|
margin-block-end: clamp(0.8rem, 1.8vh, 1.4rem);
|
||||||
|
}
|
||||||
|
|
||||||
.panel-head {
|
.panel-head {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -367,7 +366,7 @@
|
|||||||
|
|
||||||
.panel-title {
|
.panel-title {
|
||||||
margin: 0.12rem 0 0;
|
margin: 0.12rem 0 0;
|
||||||
font-size: 0.75rem;
|
font-size: 1.08rem;
|
||||||
color: rgb(var(--hud-text-main-rgb) / 0.96);
|
color: rgb(var(--hud-text-main-rgb) / 0.96);
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
}
|
}
|
||||||
@@ -404,7 +403,7 @@
|
|||||||
|
|
||||||
.chart-stage {
|
.chart-stage {
|
||||||
position: relative;
|
position: relative;
|
||||||
block-size: clamp(6.4rem, 9vw, 8.2rem);
|
block-size: clamp(12rem, 15.5vw, 15rem);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid rgb(var(--hud-border-strong-rgb) / 0.32);
|
border: 1px solid rgb(var(--hud-border-strong-rgb) / 0.32);
|
||||||
border-radius: 0.62rem;
|
border-radius: 0.62rem;
|
||||||
@@ -444,8 +443,8 @@
|
|||||||
|
|
||||||
.axis-label {
|
.axis-label {
|
||||||
fill: rgb(var(--hud-text-main-rgb) / 0.88);
|
fill: rgb(var(--hud-text-main-rgb) / 0.88);
|
||||||
font-size: 2.8px;
|
font-size: 3.2px;
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
letter-spacing: 0.02em;
|
letter-spacing: 0.02em;
|
||||||
text-shadow:
|
text-shadow:
|
||||||
0 1px 0 rgb(0 0 0 / 0.46),
|
0 1px 0 rgb(0 0 0 / 0.46),
|
||||||
@@ -487,7 +486,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.28rem;
|
gap: 0.28rem;
|
||||||
color: rgb(var(--hud-text-main-rgb) / 0.9);
|
color: rgb(var(--hud-text-main-rgb) / 0.9);
|
||||||
font-size: 0.62rem;
|
font-size: 0.76rem;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,28 +519,28 @@
|
|||||||
|
|
||||||
@media (max-width: 1180px) {
|
@media (max-width: 1180px) {
|
||||||
.signal-panel {
|
.signal-panel {
|
||||||
inline-size: min(100%, clamp(14rem, 30vw, 17rem));
|
inline-size: min(100%, clamp(24rem, 36vw, 31rem));
|
||||||
aspect-ratio: 1.5 / 1;
|
aspect-ratio: 1.48 / 1;
|
||||||
min-block-size: 10.1rem;
|
min-block-size: 17rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-height: 900px) {
|
@media (max-height: 900px) {
|
||||||
.signal-panel {
|
.signal-panel {
|
||||||
inline-size: min(100%, clamp(15rem, 22vw, 18.5rem));
|
inline-size: min(100%, clamp(24rem, 33vw, 30rem));
|
||||||
min-block-size: 10.6rem;
|
min-block-size: 16.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-stage {
|
.chart-stage {
|
||||||
block-size: clamp(5.7rem, 7.6vw, 6.9rem);
|
block-size: clamp(9.8rem, 12vw, 11.8rem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-height: 760px) {
|
@media (max-height: 760px) {
|
||||||
.signal-panel {
|
.signal-panel {
|
||||||
inline-size: min(100%, clamp(13.8rem, 20vw, 16.5rem));
|
inline-size: min(100%, clamp(21rem, 29vw, 26rem));
|
||||||
min-block-size: 9.8rem;
|
min-block-size: 14.4rem;
|
||||||
padding: 0.46rem 0.5rem 0.5rem;
|
padding: 0.7rem 0.76rem 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-foot {
|
.panel-foot {
|
||||||
@@ -549,15 +548,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chart-stage {
|
.chart-stage {
|
||||||
block-size: clamp(5rem, 6.6vw, 6rem);
|
block-size: clamp(8.3rem, 9.6vw, 9.8rem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-height: 680px) {
|
@media (max-height: 680px) {
|
||||||
.signal-panel {
|
.signal-panel {
|
||||||
inline-size: min(100%, clamp(12.8rem, 18vw, 15rem));
|
inline-size: min(100%, clamp(18.5rem, 24vw, 22.5rem));
|
||||||
min-block-size: 8.7rem;
|
min-block-size: 12.4rem;
|
||||||
padding: 0.4rem 0.46rem 0.44rem;
|
padding: 0.62rem 0.66rem 0.68rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-head {
|
.panel-head {
|
||||||
@@ -570,7 +569,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chart-stage {
|
.chart-stage {
|
||||||
block-size: clamp(4.4rem, 5.6vw, 5.4rem);
|
block-size: clamp(7rem, 7.8vw, 8rem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,17 +35,17 @@ export interface PressureColorPalette {
|
|||||||
|
|
||||||
export const pressureColorPalettes: Record<PressureColorMapPreset, PressureColorPalette> = {
|
export const pressureColorPalettes: Record<PressureColorMapPreset, PressureColorPalette> = {
|
||||||
emerald: {
|
emerald: {
|
||||||
surfaceBase: "#13201a",
|
surfaceBase: "#397557",
|
||||||
surfaceLow: "#285338",
|
surfaceLow: "#24563a",
|
||||||
surfaceMid: "#3f8a66",
|
surfaceMid: "#2f8d78",
|
||||||
surfaceHigh: "#6dd3ad",
|
surfaceHigh: "#62d9cf",
|
||||||
surfaceHot: "#d9fff0",
|
surfaceHot: "#d9fff0",
|
||||||
labelZero: "#2d8d59",
|
labelZero: "#88e3ac",
|
||||||
labelLow: "#54df8e",
|
labelLow: "#52e6a0",
|
||||||
labelMid: "#98e6ff",
|
labelMid: "#5dcfff",
|
||||||
labelHigh: "#ffab78",
|
labelHigh: "#ff5a4f",
|
||||||
rangeStops: ["#13201a", "#285338", "#3f8a66", "#6dd3ad", "#98e6ff", "#ffab78"],
|
rangeStops: ["#397557", "#36c06d", "#59cfff", "#ffd85a", "#ff8d4d", "#ff5247"],
|
||||||
rangeGlow: ["#54df8e", "#98e6ff", "#ffab78"],
|
rangeGlow: ["#52e6a0", "#59cfff", "#ff5247"],
|
||||||
uiTheme: {
|
uiTheme: {
|
||||||
bg00: "#020403",
|
bg00: "#020403",
|
||||||
bg10: "#07100d",
|
bg10: "#07100d",
|
||||||
|
|||||||
@@ -21,12 +21,12 @@
|
|||||||
--hud-glow-alt-rgb: 133 255 68;
|
--hud-glow-alt-rgb: 133 255 68;
|
||||||
--hud-text-main-rgb: 207 231 255;
|
--hud-text-main-rgb: 207 231 255;
|
||||||
--hud-text-dim-rgb: 134 162 184;
|
--hud-text-dim-rgb: 134 162 184;
|
||||||
--hud-range-0: #13201a;
|
--hud-range-0: #397557;
|
||||||
--hud-range-1: #285338;
|
--hud-range-1: #36c06d;
|
||||||
--hud-range-2: #3f8a66;
|
--hud-range-2: #59cfff;
|
||||||
--hud-range-3: #6dd3ad;
|
--hud-range-3: #ffd85a;
|
||||||
--hud-range-4: #98e6ff;
|
--hud-range-4: #ff8d4d;
|
||||||
--hud-range-5: #ffab78;
|
--hud-range-5: #ff5247;
|
||||||
|
|
||||||
--hud-text-main: #cfe7ff;
|
--hud-text-main: #cfe7ff;
|
||||||
--hud-text-dim: #86a2b8;
|
--hud-text-dim: #86a2b8;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export type HudNoticeTone = "ok" | "warn" | "info";
|
|||||||
|
|
||||||
export type SignalTone = "cyan" | "lime" | "orange" | "violet" | "gold" | "rose";
|
export type SignalTone = "cyan" | "lime" | "orange" | "violet" | "gold" | "rose";
|
||||||
export type PressureColorMapPreset = "emerald" | "arctic" | "ember";
|
export type PressureColorMapPreset = "emerald" | "arctic" | "ember";
|
||||||
|
export type MatrixDisplayMode = "numeric" | "dots";
|
||||||
|
|
||||||
export type SignalPanelSide = "left" | "right";
|
export type SignalPanelSide = "left" | "right";
|
||||||
|
|
||||||
@@ -82,6 +83,9 @@ export interface HudCopy {
|
|||||||
rangeMinLabel: string;
|
rangeMinLabel: string;
|
||||||
rangeMaxLabel: string;
|
rangeMaxLabel: string;
|
||||||
colorMapLabel: string;
|
colorMapLabel: string;
|
||||||
|
matrixViewLabel: string;
|
||||||
|
matrixViewNumericLabel: string;
|
||||||
|
matrixViewDotsLabel: string;
|
||||||
resetConfigLabel: string;
|
resetConfigLabel: string;
|
||||||
applyLiveHint: string;
|
applyLiveHint: string;
|
||||||
runtimeReady: string;
|
runtimeReady: string;
|
||||||
@@ -131,6 +135,7 @@ export interface HudMatrixConfig {
|
|||||||
rangeMin: number;
|
rangeMin: number;
|
||||||
rangeMax: number;
|
rangeMax: number;
|
||||||
colorMapPreset: PressureColorMapPreset;
|
colorMapPreset: PressureColorMapPreset;
|
||||||
|
matrixDisplayMode: MatrixDisplayMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SerialConnectResult {
|
export interface SerialConnectResult {
|
||||||
|
|||||||
@@ -23,12 +23,12 @@
|
|||||||
HudSignalSeries,
|
HudSignalSeries,
|
||||||
HudSummary,
|
HudSummary,
|
||||||
LocaleCode,
|
LocaleCode,
|
||||||
|
MatrixDisplayMode,
|
||||||
SerialConnectResult,
|
SerialConnectResult,
|
||||||
SerialExportResult,
|
SerialExportResult,
|
||||||
SerialRecordStateResult,
|
SerialRecordStateResult,
|
||||||
SerialImportResult,
|
SerialImportResult,
|
||||||
SignalTone,
|
SignalTone,
|
||||||
StageStatusTone,
|
|
||||||
WindowControlAction
|
WindowControlAction
|
||||||
} from "$lib/types/hud";
|
} from "$lib/types/hud";
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
const copyByLocale: Record<LocaleCode, HudCopy> = {
|
const copyByLocale: Record<LocaleCode, HudCopy> = {
|
||||||
"zh-CN": {
|
"zh-CN": {
|
||||||
appName: "JE-Skin",
|
appName: "JE-Skin",
|
||||||
suiteName: "v0.1.0",
|
suiteName: "v0.3.0",
|
||||||
stageTitle: "WebGL2 主渲染区",
|
stageTitle: "WebGL2 主渲染区",
|
||||||
stageHint: "底图与三维操作将在此区域加载",
|
stageHint: "底图与三维操作将在此区域加载",
|
||||||
configPanelTitle: "参数配置",
|
configPanelTitle: "参数配置",
|
||||||
@@ -55,6 +55,9 @@
|
|||||||
rangeMinLabel: "最小值",
|
rangeMinLabel: "最小值",
|
||||||
rangeMaxLabel: "最大值",
|
rangeMaxLabel: "最大值",
|
||||||
colorMapLabel: "映射颜色",
|
colorMapLabel: "映射颜色",
|
||||||
|
matrixViewLabel: "矩阵模式",
|
||||||
|
matrixViewNumericLabel: "数字矩阵",
|
||||||
|
matrixViewDotsLabel: "点矩阵",
|
||||||
resetConfigLabel: "恢复默认",
|
resetConfigLabel: "恢复默认",
|
||||||
applyLiveHint: "实时生效 / 矩阵尺寸变更将重建 viewer",
|
applyLiveHint: "实时生效 / 矩阵尺寸变更将重建 viewer",
|
||||||
runtimeReady: "WEBGL2 READY",
|
runtimeReady: "WEBGL2 READY",
|
||||||
@@ -99,7 +102,7 @@
|
|||||||
},
|
},
|
||||||
"en-US": {
|
"en-US": {
|
||||||
appName: "JE-Skin",
|
appName: "JE-Skin",
|
||||||
suiteName: "v0.1.0",
|
suiteName: "v0.3.0",
|
||||||
stageTitle: "WebGL2 Main Surface",
|
stageTitle: "WebGL2 Main Surface",
|
||||||
stageHint: "Map texture and 3D interactions will render here",
|
stageHint: "Map texture and 3D interactions will render here",
|
||||||
configPanelTitle: "Config Panel",
|
configPanelTitle: "Config Panel",
|
||||||
@@ -111,6 +114,9 @@
|
|||||||
rangeMinLabel: "Min",
|
rangeMinLabel: "Min",
|
||||||
rangeMaxLabel: "Max",
|
rangeMaxLabel: "Max",
|
||||||
colorMapLabel: "Color Map",
|
colorMapLabel: "Color Map",
|
||||||
|
matrixViewLabel: "Matrix Mode",
|
||||||
|
matrixViewNumericLabel: "Numeric",
|
||||||
|
matrixViewDotsLabel: "Dots",
|
||||||
resetConfigLabel: "Reset",
|
resetConfigLabel: "Reset",
|
||||||
applyLiveHint: "Live apply / size changes recreate the viewer",
|
applyLiveHint: "Live apply / size changes recreate the viewer",
|
||||||
runtimeReady: "WEBGL2 READY",
|
runtimeReady: "WEBGL2 READY",
|
||||||
@@ -200,7 +206,6 @@
|
|||||||
let deviceValue = "JE-Skin-F";
|
let deviceValue = "JE-Skin-F";
|
||||||
let sampleRateValue = "100Hz";
|
let sampleRateValue = "100Hz";
|
||||||
let channelsValue = "84";
|
let channelsValue = "84";
|
||||||
let webglStatusTone: StageStatusTone = "warn";
|
|
||||||
let isWindowMaximized = false;
|
let isWindowMaximized = false;
|
||||||
let activeConfigLinkId = "stream-on";
|
let activeConfigLinkId = "stream-on";
|
||||||
let isConfigPanelOpen = false;
|
let isConfigPanelOpen = false;
|
||||||
@@ -214,6 +219,7 @@
|
|||||||
let rangeMin = 0;
|
let rangeMin = 0;
|
||||||
let rangeMax = 16000;
|
let rangeMax = 16000;
|
||||||
let colorMapPreset: PressureColorMapPreset = "emerald";
|
let colorMapPreset: PressureColorMapPreset = "emerald";
|
||||||
|
let matrixDisplayMode: MatrixDisplayMode = "dots";
|
||||||
let replayFrames: ReplayFrame[] = [];
|
let replayFrames: ReplayFrame[] = [];
|
||||||
let replayCurrentIndex = 0;
|
let replayCurrentIndex = 0;
|
||||||
let replayHasDisplayedFrame = false;
|
let replayHasDisplayedFrame = false;
|
||||||
@@ -234,7 +240,6 @@
|
|||||||
|
|
||||||
$: uiCopy = copyByLocale[locale];
|
$: uiCopy = copyByLocale[locale];
|
||||||
$: configLinks = buildConfigLinks(locale, activeConfigLinkId, isConfigPanelOpen, isPrecisionTestOpen);
|
$: configLinks = buildConfigLinks(locale, activeConfigLinkId, isConfigPanelOpen, isPrecisionTestOpen);
|
||||||
$: stageStatusText = webglStatusTone === "ok" ? uiCopy.runtimeReady : uiCopy.runtimeFallback;
|
|
||||||
$: leftSignalPanels = signalPanels.filter((panel) => panel.side === "left");
|
$: leftSignalPanels = signalPanels.filter((panel) => panel.side === "left");
|
||||||
$: rightSignalPanels = signalPanels.filter((panel) => panel.side === "right");
|
$: rightSignalPanels = signalPanels.filter((panel) => panel.side === "right");
|
||||||
$: rangeTicks = buildRangeTicks(rangeMin, rangeMax);
|
$: rangeTicks = buildRangeTicks(rangeMin, rangeMax);
|
||||||
@@ -866,7 +871,7 @@
|
|||||||
|
|
||||||
function buildEmptySummary(): HudSummary {
|
function buildEmptySummary(): HudSummary {
|
||||||
return {
|
return {
|
||||||
label: "TOTAL",
|
label: "Resultant Force",
|
||||||
xValues: [],
|
xValues: [],
|
||||||
points: [],
|
points: [],
|
||||||
latest: null,
|
latest: null,
|
||||||
@@ -875,6 +880,18 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isZeroLikeValue(value: number): boolean {
|
||||||
|
return !Number.isFinite(value) || Math.abs(value) < 0.0001;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldHideSummary(points: number[]): boolean {
|
||||||
|
return points.length === 0 || points.every((value) => isZeroLikeValue(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeSummary(summaryValue: HudSummary): HudSummary {
|
||||||
|
return shouldHideSummary(summaryValue.points) ? buildEmptySummary() : summaryValue;
|
||||||
|
}
|
||||||
|
|
||||||
function buildSummary(points: number[], xValues: number[] = []): HudSummary {
|
function buildSummary(points: number[], xValues: number[] = []): HudSummary {
|
||||||
if (points.length === 0) {
|
if (points.length === 0) {
|
||||||
return buildEmptySummary();
|
return buildEmptySummary();
|
||||||
@@ -886,7 +903,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
label: "TOTAL",
|
label: "Resultant Force",
|
||||||
xValues: resolvedXValues,
|
xValues: resolvedXValues,
|
||||||
points,
|
points,
|
||||||
latest: points[points.length - 1],
|
latest: points[points.length - 1],
|
||||||
@@ -1077,7 +1094,6 @@
|
|||||||
|
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
const context = canvas.getContext("webgl2");
|
const context = canvas.getContext("webgl2");
|
||||||
webglStatusTone = context ? "ok" : "warn";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleLocaleChange(event: CustomEvent<LocaleCode>): void {
|
function handleLocaleChange(event: CustomEvent<LocaleCode>): void {
|
||||||
@@ -1494,6 +1510,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleMatrixDisplayToggle(event: CustomEvent<boolean>): void {
|
||||||
|
matrixDisplayMode = event.detail ? "dots" : "numeric";
|
||||||
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
let disposed = false;
|
let disposed = false;
|
||||||
let unlistenHudStream: UnlistenFn | null = null;
|
let unlistenHudStream: UnlistenFn | null = null;
|
||||||
@@ -1559,6 +1579,10 @@
|
|||||||
channelsValue={channelsValue}
|
channelsValue={channelsValue}
|
||||||
configLinksLabel={uiCopy.configLinksLabel}
|
configLinksLabel={uiCopy.configLinksLabel}
|
||||||
refreshPortsLabel={uiCopy.refreshPortsLabel}
|
refreshPortsLabel={uiCopy.refreshPortsLabel}
|
||||||
|
matrixViewLabel={uiCopy.matrixViewLabel}
|
||||||
|
matrixViewNumericLabel={uiCopy.matrixViewNumericLabel}
|
||||||
|
matrixViewDotsLabel={uiCopy.matrixViewDotsLabel}
|
||||||
|
{matrixDisplayMode}
|
||||||
connectActionLabel={uiCopy.connectActionLabel}
|
connectActionLabel={uiCopy.connectActionLabel}
|
||||||
disconnectActionLabel={uiCopy.disconnectActionLabel}
|
disconnectActionLabel={uiCopy.disconnectActionLabel}
|
||||||
exportActionLabel={uiCopy.exportActionLabel}
|
exportActionLabel={uiCopy.exportActionLabel}
|
||||||
@@ -1576,6 +1600,7 @@
|
|||||||
on:localechange={handleLocaleChange}
|
on:localechange={handleLocaleChange}
|
||||||
on:portchange={handlePortChange}
|
on:portchange={handlePortChange}
|
||||||
on:configlink={handleConfigLink}
|
on:configlink={handleConfigLink}
|
||||||
|
on:matrixdisplaytoggle={handleMatrixDisplayToggle}
|
||||||
on:serialrefresh={handleSerialRefresh}
|
on:serialrefresh={handleSerialRefresh}
|
||||||
on:serialconnect={handleSerialConnect}
|
on:serialconnect={handleSerialConnect}
|
||||||
on:serialexport={handleSerialExportRequest}
|
on:serialexport={handleSerialExportRequest}
|
||||||
@@ -1590,8 +1615,7 @@
|
|||||||
bind:rangeMin
|
bind:rangeMin
|
||||||
bind:rangeMax
|
bind:rangeMax
|
||||||
bind:colorMapPreset
|
bind:colorMapPreset
|
||||||
title={uiCopy.stageTitle}
|
bind:matrixDisplayMode
|
||||||
hint={uiCopy.stageHint}
|
|
||||||
configPanelTitle={uiCopy.configPanelTitle}
|
configPanelTitle={uiCopy.configPanelTitle}
|
||||||
configPanelHint={uiCopy.configPanelHint}
|
configPanelHint={uiCopy.configPanelHint}
|
||||||
matrixSizeLabel={uiCopy.matrixSizeLabel}
|
matrixSizeLabel={uiCopy.matrixSizeLabel}
|
||||||
@@ -1616,8 +1640,6 @@
|
|||||||
{replayFrameInfo}
|
{replayFrameInfo}
|
||||||
resetConfigLabel={uiCopy.resetConfigLabel}
|
resetConfigLabel={uiCopy.resetConfigLabel}
|
||||||
applyLiveHint={uiCopy.applyLiveHint}
|
applyLiveHint={uiCopy.applyLiveHint}
|
||||||
statusText={stageStatusText}
|
|
||||||
statusTone={webglStatusTone}
|
|
||||||
leftPanels={leftSignalPanels}
|
leftPanels={leftSignalPanels}
|
||||||
rightPanels={rightSignalPanels}
|
rightPanels={rightSignalPanels}
|
||||||
{pressureMatrix}
|
{pressureMatrix}
|
||||||
@@ -1786,10 +1808,13 @@
|
|||||||
linear-gradient(
|
linear-gradient(
|
||||||
90deg,
|
90deg,
|
||||||
color-mix(in srgb, var(--hud-range-0) 92%, black) 0%,
|
color-mix(in srgb, var(--hud-range-0) 92%, black) 0%,
|
||||||
color-mix(in srgb, var(--hud-range-1) 94%, black) 18%,
|
color-mix(in srgb, var(--hud-range-1) 96%, black) 12.5%,
|
||||||
color-mix(in srgb, var(--hud-range-2) 96%, black) 40%,
|
color-mix(in srgb, var(--hud-range-1) 92%, black) 25%,
|
||||||
color-mix(in srgb, var(--hud-range-3) 98%, black) 66%,
|
color-mix(in srgb, var(--hud-range-2) 96%, black) 37.5%,
|
||||||
color-mix(in srgb, var(--hud-range-4) 96%, black) 84%,
|
color-mix(in srgb, var(--hud-range-2) 92%, black) 50%,
|
||||||
|
color-mix(in srgb, var(--hud-range-3) 96%, black) 62.5%,
|
||||||
|
color-mix(in srgb, var(--hud-range-3) 92%, black) 75%,
|
||||||
|
color-mix(in srgb, var(--hud-range-4) 96%, black) 87.5%,
|
||||||
color-mix(in srgb, var(--hud-range-5) 94%, black) 100%
|
color-mix(in srgb, var(--hud-range-5) 94%, black) 100%
|
||||||
),
|
),
|
||||||
linear-gradient(180deg, rgb(var(--hud-text-main-rgb) / 0.06), transparent 42%);
|
linear-gradient(180deg, rgb(var(--hud-text-main-rgb) / 0.06), transparent 42%);
|
||||||
|
|||||||
BIN
static/favicon.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |