Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1ca023ee8 | ||
|
|
2b3138d9d0 | ||
|
|
1c678a71fa | ||
|
|
6699a2fc44 | ||
|
|
964377765a | ||
|
|
5cfbb8d98d | ||
|
|
0f95193190 | ||
|
|
15fd5eebdc | ||
|
|
b064acf57c | ||
|
|
4413491370 | ||
|
|
b265454b93 | ||
|
|
99d9851173 | ||
|
|
720cfd7c8a | ||
|
|
2c1222789d | ||
|
|
3620abff12 | ||
|
|
a937a5fd20 | ||
|
|
9d863c3d22 | ||
|
|
99cea559f9 | ||
|
|
18d98d9452 | ||
|
|
4eb991a101 | ||
|
|
1c435a0a79 | ||
|
|
3c8f7ed96e | ||
|
|
3b0b8d72df | ||
|
|
ce93244117 | ||
|
|
8a140c1906 | ||
|
|
d779961a55 | ||
|
|
f59fe9d7c2 | ||
|
|
a71634ae8a | ||
|
|
f1ff58afe7 | ||
|
|
4696804b23 | ||
|
|
88daeb8cf2 | ||
|
|
f8750a4a50 | ||
|
|
2c7a0194f4 | ||
|
|
0ef6b96fe1 | ||
|
|
2d5472372f | ||
|
|
efdf97ecc1 | ||
|
|
46d80ffc3a | ||
|
|
0b15c0ebc9 | ||
|
|
682a6f4538 | ||
|
|
a72174c571 | ||
|
|
fd323e483e | ||
|
|
9f0821cf69 | ||
|
|
69fc9efff7 | ||
|
|
20386cf313 | ||
|
|
c4fd6d9b36 | ||
|
|
e223d86ba2 | ||
|
|
52e5ebefbd | ||
|
|
ca44cd1a7b | ||
|
|
5fe0a6a48d | ||
|
|
da1ef6a17d | ||
|
|
b6c2fb5b7d | ||
|
|
b8b70b7df7 | ||
|
|
bb5d903724 | ||
|
|
1e2348abef | ||
|
|
2493185ab8 | ||
|
|
678f63f4f3 | ||
|
|
0aba0fc467 | ||
|
|
6f550c39ed | ||
|
|
e9d0cef610 | ||
|
|
bb22f1b185 | ||
|
|
7bc5fe1a53 | ||
|
|
51e1788c7e | ||
|
|
7b62297f3e | ||
|
|
890e521a3a | ||
|
|
444184f9ef | ||
|
|
7955af5bc0 | ||
|
|
273a2a8536 | ||
|
|
add0755958 | ||
|
|
de5f7edd16 | ||
|
|
69e0729c61 | ||
|
|
9baaf8434f | ||
|
|
27eefb6a7f | ||
|
|
c6f7e8ca0d | ||
|
|
474f1a904e | ||
|
|
ddaa54eba0 | ||
|
|
b3d31510ee | ||
|
|
bce512cb8d | ||
|
|
9950ecc340 | ||
|
|
e0c4207bd5 | ||
|
|
044a41d2de | ||
|
|
8d243a67f4 | ||
|
|
ee6717f035 | ||
|
|
f5a36666fc | ||
|
|
d78a221607 | ||
|
|
db81dce7ba | ||
|
|
3a8ec8139e | ||
|
|
98c1d4a1e9 | ||
|
|
c00deadaf7 | ||
|
|
7c8aeacea2 | ||
|
|
c3764a429f | ||
|
|
985e5d9449 | ||
|
|
b033fd309e | ||
|
|
76af08a9b0 | ||
|
|
951ffcc254 | ||
|
|
cbd84acf6c | ||
|
|
a1d7eb0bfd | ||
|
|
3741e7ba43 | ||
|
|
fabb0c8233 | ||
|
|
da2304985a | ||
|
|
8c6d29bf83 | ||
|
|
5cffe9e7db | ||
|
|
c51a1cf888 | ||
|
|
522374584c | ||
|
|
5755d9f11f | ||
|
|
3bf993275e | ||
|
|
05ea4feaed | ||
|
|
7af5477f04 | ||
|
|
84f5e19e9d | ||
|
|
1a50162598 | ||
|
|
0eb952a9c5 | ||
|
|
08f0f8859b | ||
|
|
8c63d7b558 | ||
|
|
e351d0fce1 | ||
|
|
ea6da967d2 | ||
|
|
f44f25d596 | ||
|
|
8ecac18978 | ||
|
|
e5f88b88fe | ||
|
|
ebb303cbb8 | ||
|
|
c80f618119 | ||
|
|
3b542f8a85 | ||
|
|
ef01c9e2be | ||
|
|
abeca0f0ed | ||
|
|
5a36be17d2 | ||
|
|
559528155f | ||
|
|
f161abf582 | ||
|
|
a4f80e63a2 | ||
|
|
43f5f99108 | ||
|
|
f8ab204711 | ||
|
|
0df5069831 | ||
|
|
f6a3a3579f | ||
|
|
d25fb8192e | ||
|
|
03a897938f | ||
|
|
15d48d4481 | ||
|
|
c764c8916b | ||
|
|
5efc7e2c2c | ||
|
|
39b4ae9ae1 | ||
|
|
4a472926e1 | ||
|
|
c4f9d95e11 | ||
|
|
bf21c8c7a9 | ||
|
|
629e1b9c6c | ||
|
|
78a1474057 | ||
|
|
751b7ae17b | ||
|
|
c4d7ef8086 | ||
|
|
bd7c506076 | ||
|
|
8e12606c6a | ||
|
|
8b857e41cd | ||
|
|
093e3bbeae | ||
|
|
4128661789 | ||
|
|
b6f3abd35e | ||
|
|
45796e4e3e | ||
|
|
3cd360f9e2 | ||
|
|
d31d9daba2 | ||
|
|
b25729acd6 | ||
|
|
8d2be98ed7 | ||
|
|
43f16e5638 | ||
|
|
6112a185df | ||
|
|
888222277e | ||
|
|
1938f0251f | ||
|
|
b90b592d4f | ||
|
|
e1fbbede61 | ||
|
|
aac4155584 | ||
|
|
5ef001b4fe | ||
|
|
6524712900 | ||
|
|
dd02efe2fe | ||
|
|
7d15e9fb4a | ||
|
|
69106970dd | ||
|
|
686e4bad00 | ||
|
|
b713a23cac | ||
|
|
0c1efda425 | ||
|
|
b1be91478c | ||
|
|
6eb79cad26 | ||
|
|
45fc41ac4c | ||
|
|
901cf16eb3 | ||
|
|
af2d6981a3 | ||
|
|
a04fbc4694 | ||
|
|
dbaa3c7f52 | ||
|
|
6cf0356554 | ||
|
|
b2ad3a65dc | ||
|
|
815384dcc4 | ||
|
|
8cd8742d2b | ||
|
|
dbf4788628 | ||
|
|
cdad032296 | ||
|
|
0decc5c3fa | ||
|
|
d4a3c7f17f | ||
|
|
2c0abcc802 | ||
|
|
f1dbaac452 | ||
|
|
33a9e90896 | ||
|
|
bbbb14169d | ||
|
|
4fbe58f736 | ||
|
|
a64e9e98fb | ||
|
|
130afabae8 | ||
|
|
36e4df95b7 | ||
|
|
b370d4fcd4 | ||
|
|
500cfe4787 | ||
|
|
f7c2c6587e | ||
|
|
30391bfbd2 | ||
|
|
00a42d7cda | ||
|
|
bd6f38e2df | ||
|
|
203bd66daa | ||
|
|
2c3a924231 | ||
|
|
e5422d52e4 | ||
|
|
26e8ca3f39 | ||
|
|
c407e738a3 | ||
|
|
755e9bca05 | ||
|
|
73e15a7d29 | ||
|
|
f38beff441 | ||
|
|
830abd7e18 | ||
|
|
b296ea26a4 | ||
|
|
0b29902d8b | ||
|
|
b18b34e9f5 | ||
|
|
169597a7d2 | ||
|
|
0d1a247bfe | ||
|
|
a4d49f76b9 | ||
|
|
51102b3baf | ||
|
|
977fa26731 | ||
|
|
2841b22cc9 | ||
|
|
3fd3851633 | ||
|
|
d6b940184e | ||
|
|
60adac05b7 | ||
|
|
ec9da648b8 | ||
|
|
0fd1c63563 | ||
|
|
521b29ea21 | ||
|
|
e8e4e5cf67 | ||
|
|
9af1cc6644 | ||
|
|
56fcc49104 | ||
|
|
11c014485e | ||
|
|
86e45980fe | ||
|
|
d613a576ea | ||
|
|
97578ee401 | ||
|
|
e54b4171ca | ||
|
|
338c523217 | ||
|
|
224c9eb671 | ||
|
|
2deb6d2d64 | ||
|
|
82e05d0664 | ||
|
|
a2c662f9f7 | ||
|
|
48c6244d37 | ||
|
|
30404dd9cf | ||
|
|
c4021f9884 | ||
|
|
2227b42841 | ||
|
|
767c36ad12 | ||
|
|
2e9e87c65c | ||
|
|
8d1a67d31b | ||
|
|
c19b846394 | ||
|
|
cf6e955196 | ||
|
|
dddc214a25 | ||
|
|
5da64c6fc5 | ||
|
|
1c088e67c2 | ||
|
|
1231088427 | ||
|
|
4d857a908f | ||
|
|
d6347fe12e | ||
|
|
9b595b8333 | ||
|
|
944b7bea77 | ||
|
|
7f9df37380 | ||
|
|
f574450516 | ||
|
|
3621a211bd | ||
|
|
5eb8ddde12 | ||
|
|
fbecae4e02 | ||
|
|
de099c1f2d | ||
|
|
01460b98b0 | ||
|
|
26f444138e | ||
|
|
00737441c4 | ||
|
|
25d7be3c25 | ||
|
|
29b3968731 | ||
|
|
ed006abd58 | ||
|
|
5419bff2a8 | ||
|
|
7cdf5714e8 | ||
|
|
f1ea275d5d | ||
|
|
5c50fa8588 | ||
|
|
f19938a7b6 | ||
|
|
db5a898372 | ||
|
|
b11422459e | ||
|
|
e5bf0d4892 | ||
|
|
e04f269f1a | ||
|
|
12a61c16e8 | ||
|
|
a70803fe31 | ||
|
|
4b295b1b4d | ||
|
|
615e2d419b | ||
|
|
f85896cccb | ||
|
|
0a0b3411f8 | ||
|
|
08210b02c9 | ||
|
|
27f5540663 | ||
|
|
b742eae7d6 | ||
|
|
d42c5581f3 | ||
|
|
0df48df7b2 | ||
|
|
bd110e0eac | ||
|
|
f3c361efd1 | ||
|
|
a3b6e1d500 | ||
|
|
1d2ad6aa8e | ||
|
|
c929bbc8b3 | ||
|
|
d36f346bba | ||
|
|
2c249ec8cb |
No files matched your search
@@ -10,6 +10,11 @@
|
||||
"name": "ruview",
|
||||
"source": "./plugins/ruview",
|
||||
"description": "End-to-end RuView toolkit: getting started, ESP32 hardware setup, configuration, sensing applications (presence / vitals / pose / sleep / MAT), camera-free + camera-supervised model training, advanced multistatic sensing, CLI / API / WASM, mmWave radar, and witness verification"
|
||||
},
|
||||
{
|
||||
"name": "ruview-live",
|
||||
"source": "./harness/ruview/mod",
|
||||
"description": "Claude Code mod: /ruview opens a live pane with your CSI nodes (ESP32, Realtek) and ESPHome radar (presence, distance, device-reported vitals), refreshed on a timer, plus a one-line status. Read-only; ships inside @ruvnet/ruview. Mods are early access (CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1)."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -135,6 +135,10 @@ async function runProcess(command, args, {
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
// A child that never reads stdin (e.g. `git check-ignore`) may exit and
|
||||
// close the pipe before this write flushes; the resulting EPIPE is not a
|
||||
// failure of the command, whose real outcome the 'close' handler reports.
|
||||
child.stdin.on('error', () => {});
|
||||
child.stdin.end(input);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
name: BFI Research Tools
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'tools/bfi/**'
|
||||
- 'tools/bfi_learning/**'
|
||||
- '.github/workflows/bfi-research.yml'
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'tools/bfi/**'
|
||||
- 'tools/bfi_learning/**'
|
||||
- '.github/workflows/bfi-research.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: bfi-research-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
offline-tests:
|
||||
name: BFI offline tests (Linux, CPU)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
|
||||
with:
|
||||
python-version: '3.13'
|
||||
- name: Install numeric test dependencies
|
||||
run: python -m pip install numpy==2.4.2 scipy==1.17.1
|
||||
- name: Install CPU PyTorch
|
||||
run: python -m pip install torch==2.11.0 --index-url https://download.pytorch.org/whl/cpu
|
||||
- name: Test capture parsing and bounded runners
|
||||
run: python -B -m unittest discover -s tools/bfi -v
|
||||
- name: Test offline learning and data admission
|
||||
run: python -B -m unittest discover -s tools/bfi_learning -v
|
||||
@@ -204,7 +204,10 @@ jobs:
|
||||
node-version: '22'
|
||||
|
||||
- name: Run UI unit tests
|
||||
run: node --test ui/sw.test.mjs ui/services/ws-ticket.test.mjs ui/services/websocket.service.test.mjs v2/crates/wifi-densepose-desktop/ui/build-config.test.mjs
|
||||
run: node --test ui/sw.test.mjs ui/services/ws-ticket.test.mjs ui/services/websocket.service.test.mjs ui/services/sensing.service.test.mjs ui/components/DashboardTab.test.mjs v2/crates/wifi-densepose-desktop/ui/build-config.test.mjs
|
||||
|
||||
- name: Run virtual-view adapter boundary tests
|
||||
run: node --test integrations/virtual-view/adapter.test.mjs
|
||||
|
||||
# Unit and Integration Tests
|
||||
# Python pytest matrix — runs against the archived v1 Python tree.
|
||||
@@ -501,7 +504,7 @@ jobs:
|
||||
notify:
|
||||
name: Notify
|
||||
runs-on: ubuntu-latest
|
||||
needs: [code-quality, test, rust-tests, performance-test, docker-build, docs]
|
||||
needs: [code-quality, test, rust-tests, ui-tests, performance-test, docker-build, docs]
|
||||
if: always()
|
||||
permissions:
|
||||
contents: write # required by softprops/action-gh-release
|
||||
@@ -528,18 +531,22 @@ jobs:
|
||||
text: '❌ CI pipeline failed for ${{ github.ref }}'
|
||||
|
||||
- name: Create GitHub Release
|
||||
if: github.ref == 'refs/heads/main' && needs.docker-build.result == 'success'
|
||||
if: github.ref == 'refs/heads/main' && needs.rust-tests.result == 'success' && needs.ui-tests.result == 'success' && needs.docker-build.result == 'success'
|
||||
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65
|
||||
with:
|
||||
tag_name: v${{ github.run_number }}
|
||||
name: Release v${{ github.run_number }}
|
||||
name: CI snapshot v${{ github.run_number }}
|
||||
# CI snapshots must not replace a curated product release as Latest.
|
||||
make_latest: false
|
||||
body: |
|
||||
Automated release from CI pipeline
|
||||
Source snapshot validated by the CI pipeline. This entry does not contain firmware bundles.
|
||||
|
||||
**Changes:**
|
||||
${{ github.event.head_commit.message }}
|
||||
|
||||
**Docker Image:**
|
||||
`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}`
|
||||
**Source commit:** `${{ github.sha }}`
|
||||
|
||||
Container images publish separately through the [sensing-server release workflow](https://github.com/ruvnet/RuView/actions/workflows/sensing-server-docker.yml).
|
||||
Firmware downloads are attached to the dedicated `vX.Y.Z-esp32` releases.
|
||||
draft: false
|
||||
prerelease: false
|
||||
@@ -16,6 +16,17 @@ on:
|
||||
- '.github/workflows/firmware-ci.yml'
|
||||
|
||||
jobs:
|
||||
provisioning-tests:
|
||||
name: Provisioning tooling tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Verify provisioning and secret handling without hardware
|
||||
run: python -m unittest discover -s firmware/esp32-csi-node/tests -p 'test_provision*.py' -v
|
||||
|
||||
version-guard:
|
||||
name: Verify version.txt matches release tag
|
||||
runs-on: ubuntu-latest
|
||||
@@ -53,7 +64,9 @@ jobs:
|
||||
sdkconfig: sdkconfig.defaults
|
||||
partition_table_name: partitions_display.csv
|
||||
size_warn_kb: 1100
|
||||
size_limit_kb: 1152
|
||||
# Current 8 MB image is 1163 KiB after USB onboarding. The OTA app
|
||||
# partition is 2048 KiB; retain a 1200 KiB hard gate and warning.
|
||||
size_limit_kb: 1200
|
||||
artifact_app: esp32-csi-node.bin
|
||||
artifact_pt: partition-table.bin
|
||||
- variant: 4mb
|
||||
@@ -92,12 +105,11 @@ jobs:
|
||||
idf.py set-target ${{ matrix.target }}
|
||||
idf.py build
|
||||
|
||||
- name: Build and run host-side ADR-110 unit tests
|
||||
- name: Build and run host-side firmware unit tests
|
||||
if: matrix.variant == 'c6-4mb'
|
||||
working-directory: firmware/esp32-csi-node/test
|
||||
run: |
|
||||
make test_adr110
|
||||
./test_adr110
|
||||
make host_tests
|
||||
|
||||
- name: Verify binary size budget
|
||||
working-directory: firmware/esp32-csi-node
|
||||
@@ -118,6 +130,10 @@ jobs:
|
||||
fi
|
||||
echo "Binary size OK: $SIZE <= $MAX"
|
||||
|
||||
- name: Verify built application version before packaging
|
||||
working-directory: firmware/esp32-csi-node
|
||||
run: python test/test_delivery_contract.py --built-app build/esp32-csi-node.bin
|
||||
|
||||
- name: Verify flash image integrity
|
||||
working-directory: firmware/esp32-csi-node
|
||||
run: |
|
||||
@@ -162,10 +178,14 @@ jobs:
|
||||
mkdir -p release-staging
|
||||
cp build/esp32-csi-node.bin release-staging/${{ matrix.artifact_app }}
|
||||
cp build/partition_table/partition-table.bin release-staging/${{ matrix.artifact_pt }}
|
||||
if [ "${{ matrix.variant }}" = "8mb" ]; then
|
||||
cp build/bootloader/bootloader.bin release-staging/bootloader.bin
|
||||
cp build/ota_data_initial.bin release-staging/ota_data_initial.bin
|
||||
fi
|
||||
cp build/bootloader/bootloader.bin release-staging/bootloader.bin
|
||||
cp build/ota_data_initial.bin release-staging/ota_data_initial.bin
|
||||
cp version.txt release-staging/version.txt
|
||||
(cd release-staging && sha256sum \
|
||||
"${{ matrix.artifact_app }}" \
|
||||
"${{ matrix.artifact_pt }}" \
|
||||
bootloader.bin ota_data_initial.bin version.txt \
|
||||
> SHA256SUMS.txt)
|
||||
ls -la release-staging/
|
||||
|
||||
- name: Check QEMU ESP32-S3 support status
|
||||
@@ -180,3 +200,59 @@ jobs:
|
||||
name: esp32-csi-node-firmware-${{ matrix.variant }}
|
||||
path: firmware/esp32-csi-node/release-staging/
|
||||
retention-days: 90
|
||||
|
||||
build-c6-idf6:
|
||||
name: Build XIAO C6 external antenna (ESP-IDF 6.0.2)
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: espressif/idf:v6.0.2
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Build the IDF 6 canary image
|
||||
working-directory: firmware/esp32-csi-node
|
||||
run: |
|
||||
. $IDF_PATH/export.sh
|
||||
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.esp32c6;sdkconfig.defaults.xiao-external" set-target esp32c6
|
||||
idf.py build
|
||||
test "$(stat -c%s build/esp32-csi-node.bin)" -le $((1152 * 1024))
|
||||
strings build/esp32-csi-node.bin | grep -F "external U.FL"
|
||||
|
||||
publish-release-assets:
|
||||
name: Publish firmware release assets
|
||||
if: github.ref_type == 'tag'
|
||||
needs: [version-guard, provisioning-tests, build, build-c6-idf6]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Download the exact-run firmware artifacts
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||
with:
|
||||
pattern: esp32-csi-node-firmware-*
|
||||
path: release-downloads
|
||||
|
||||
- name: Package variants without filename collisions
|
||||
run: |
|
||||
mkdir -p release-assets
|
||||
for directory in release-downloads/esp32-csi-node-firmware-*; do
|
||||
variant="${directory##*/}"
|
||||
tar -C "$directory" -czf "release-assets/${variant}.tar.gz" .
|
||||
done
|
||||
(cd release-assets && sha256sum *.tar.gz > SHA256SUMS.txt)
|
||||
|
||||
- name: Publish the downloadable firmware bundles
|
||||
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65
|
||||
with:
|
||||
name: ESP32 firmware ${{ github.ref_name }}
|
||||
prerelease: true
|
||||
make_latest: false
|
||||
body: |
|
||||
Exact-run ESP32-S3 display 8 MB, ESP32-S3 headless 4 MB, and ESP32-C6 4 MB firmware bundles.
|
||||
Verify each archive against `SHA256SUMS.txt` before flashing.
|
||||
CI builds and host tests verify software behavior, not target hardware.
|
||||
This prerelease has no new physical-board qualification or sensing-accuracy claim.
|
||||
Select the matching board configuration using firmware/esp32-csi-node/README.md.
|
||||
files: release-assets/*
|
||||
@@ -0,0 +1,70 @@
|
||||
name: iPhone LiDAR integration
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/iphone-lidar/**'
|
||||
- 'docs/adr/ADR-340-iphone-lidar-sensor-bridge.md'
|
||||
- '.github/workflows/iphone-lidar.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'integrations/iphone-lidar/**'
|
||||
- 'docs/adr/ADR-340-iphone-lidar-sensor-bridge.md'
|
||||
- '.github/workflows/iphone-lidar.yml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
web:
|
||||
name: Node relay and codec
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: integrations/iphone-lidar/web
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: npm
|
||||
cache-dependency-path: integrations/iphone-lidar/web/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --ignore-scripts
|
||||
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
|
||||
- name: Audit runtime dependencies
|
||||
run: npm audit --omit=optional --audit-level=high
|
||||
|
||||
ios:
|
||||
name: iOS 17 compile
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
|
||||
- name: Compile native sources with strict concurrency
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sdk="$(xcrun --sdk iphoneos --show-sdk-path)"
|
||||
build_dir="$RUNNER_TEMP/ruview-lidar-build"
|
||||
mkdir -p "$build_dir"
|
||||
cd "$build_dir"
|
||||
xcrun swiftc \
|
||||
-parse-as-library \
|
||||
-target arm64-apple-ios17.0 \
|
||||
-sdk "$sdk" \
|
||||
-module-name RuViewLiDAR \
|
||||
-strict-concurrency=complete \
|
||||
-warnings-as-errors \
|
||||
-emit-module \
|
||||
-emit-module-path "$build_dir/RuViewLiDAR.swiftmodule" \
|
||||
-c "$GITHUB_WORKSPACE"/integrations/iphone-lidar/native/RuViewLiDAR/*.swift
|
||||
@@ -40,8 +40,13 @@ jobs:
|
||||
- dir: harness/ruview
|
||||
build: false
|
||||
publishable: true
|
||||
# ADR-283: brain + local hosts + replay assets; still runtime-dependency-free.
|
||||
unpacked_budget: 131072
|
||||
# ADR-283/325: brain + local hosts + replay assets + guarded Spaces OAuth adapter;
|
||||
# still runtime-dependency-free. ADR-369..374 add the SDK, firmware
|
||||
# flashing, training runner/gate, doctor, device access, and SSH
|
||||
# hosts. ADR-375 adds the MCP Apps console widget (~12 KB), the
|
||||
# Streamable HTTP transport and the terminal UI (384 KiB); ADR-378 the
|
||||
# ruview-live showcase views (~37 KB): 448 KiB reviewed ceiling.
|
||||
unpacked_budget: 458752
|
||||
- dir: harness/homecore
|
||||
build: false
|
||||
publishable: true
|
||||
@@ -130,13 +135,19 @@ jobs:
|
||||
npm i --no-fund --no-audit "$TGZ"
|
||||
case "${{ matrix.package.dir }}" in
|
||||
harness/ruview)
|
||||
./node_modules/.bin/ruview --version
|
||||
./node_modules/.bin/ruview doctor
|
||||
./node_modules/.bin/ruview-harness --version
|
||||
./node_modules/.bin/ruview-harness doctor
|
||||
# the honesty gate must fail closed on empty input (ADR-263 F1)
|
||||
if ./node_modules/.bin/ruview claim-check; then
|
||||
if ./node_modules/.bin/ruview-harness claim-check; then
|
||||
echo 'claim-check passed with no input — fail-open regression'; exit 1
|
||||
fi
|
||||
node --input-type=module -e "const m = await import('@ruvnet/ruview'); if (!m.TOOLS) process.exit(1);"
|
||||
# ADR-369: the typed SDK resolves and the evidence gate refuses a baseline-free score
|
||||
node --input-type=module -e "const { createRuView } = await import('@ruvnet/ruview/sdk'); const r = createRuView(); if (r.tools().length < 22) process.exit(1); const g = await r.training.gate({ model_score: 0.93 }); if (g.verdict !== 'FAIL') process.exit(1);"
|
||||
./node_modules/.bin/ruview-harness doctor --json --group runtime,harness,firmware > doctor.json
|
||||
if ./node_modules/.bin/ruview-harness train-gate --model-score 0.93 > /dev/null; then
|
||||
echo 'train-gate passed without a baseline'; exit 1
|
||||
fi
|
||||
;;
|
||||
harness/homecore)
|
||||
./node_modules/.bin/homecore --version
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
name: README visual asset validation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'README.md'
|
||||
- 'assets/readme/**'
|
||||
- 'docs/readme-visual-system.md'
|
||||
- 'scripts/*readme*'
|
||||
- 'scripts/tests/test_readme_visuals_xml.py'
|
||||
- '.github/workflows/readme-visuals.yml'
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'README.md'
|
||||
- 'assets/readme/**'
|
||||
- 'docs/readme-visual-system.md'
|
||||
- 'scripts/*readme*'
|
||||
- 'scripts/tests/test_readme_visuals_xml.py'
|
||||
- '.github/workflows/readme-visuals.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
name: Safe and reproducible README visuals
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Install visual tooling dependency
|
||||
run: python -m pip install -r scripts/requirements-readme-visuals.txt
|
||||
- name: Test XML input boundaries
|
||||
run: python -m unittest discover -s scripts/tests -p test_readme_visuals_xml.py
|
||||
- name: Verify reproducible and accessible assets
|
||||
run: |
|
||||
python scripts/render-readme-visuals.py
|
||||
python scripts/verify-readme-visuals.py
|
||||
git diff --exit-code -- assets/readme
|
||||
test -z "$(git ls-files --others --exclude-standard -- assets/readme)"
|
||||
@@ -0,0 +1,627 @@
|
||||
name: RuForecast Rust CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop, 'feat/*', 'feature/*']
|
||||
paths:
|
||||
- 'v2/crates/ruforecast'
|
||||
- 'v2/Cargo.toml'
|
||||
- 'v2/Cargo.lock'
|
||||
- 'v2/rust-toolchain.toml'
|
||||
- 'scripts/csi-data-policy-check.sh'
|
||||
- 'scripts/run-ruforecast-benchmarks.sh'
|
||||
- 'docs/adr/ADR-348-*.md'
|
||||
- 'docs/adr/ADR-349-*.md'
|
||||
- 'docs/adr/ADR-350-*.md'
|
||||
- 'docs/adr/README.md'
|
||||
- 'docs/benchmarks/ruforecast.md'
|
||||
- 'docs/huggingface/RUVIEW_FORECAST_MODEL_CARD_TEMPLATE.md'
|
||||
- 'docs/security/ruview-forecast-*'
|
||||
- 'docs/validation/ruforecast-requirements-evidence.md'
|
||||
- '.github/workflows/ruforecast-ci.yml'
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
paths:
|
||||
- 'v2/crates/ruforecast'
|
||||
- 'v2/Cargo.toml'
|
||||
- 'v2/Cargo.lock'
|
||||
- 'v2/rust-toolchain.toml'
|
||||
- 'scripts/csi-data-policy-check.sh'
|
||||
- 'scripts/run-ruforecast-benchmarks.sh'
|
||||
- 'docs/adr/ADR-348-*.md'
|
||||
- 'docs/adr/ADR-349-*.md'
|
||||
- 'docs/adr/ADR-350-*.md'
|
||||
- 'docs/adr/README.md'
|
||||
- 'docs/benchmarks/ruforecast.md'
|
||||
- 'docs/huggingface/RUVIEW_FORECAST_MODEL_CARD_TEMPLATE.md'
|
||||
- 'docs/security/ruview-forecast-*'
|
||||
- 'docs/validation/ruforecast-requirements-evidence.md'
|
||||
- '.github/workflows/ruforecast-ci.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ruforecast-${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
CARGO_PROFILE_DEV_DEBUG: '0'
|
||||
CARGO_PROFILE_TEST_DEBUG: '0'
|
||||
CARGO_PROFILE_BENCH_DEBUG: '0'
|
||||
CARGO_PROFILE_RELEASE_DEBUG: '0'
|
||||
|
||||
jobs:
|
||||
contract-rust-189:
|
||||
name: Forecast contract and feature-off boundary (Rust 1.89)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- name: Checkout recursively
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Rust 1.89 with lint components
|
||||
uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4
|
||||
with:
|
||||
toolchain: 1.89.0
|
||||
components: rustfmt,clippy
|
||||
|
||||
- name: Cache Cargo artifacts
|
||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32
|
||||
with:
|
||||
workspaces: v2/crates/ruforecast
|
||||
key: ruforecast-rust-189
|
||||
|
||||
- name: Validate benchmark runner and evidence contract
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
bash -n scripts/run-ruforecast-benchmarks.sh
|
||||
test -x scripts/run-ruforecast-benchmarks.sh
|
||||
test -f docs/benchmarks/ruforecast.md
|
||||
test -f docs/huggingface/RUVIEW_FORECAST_MODEL_CARD_TEMPLATE.md
|
||||
test -f docs/security/ruview-forecast-clean-room.md
|
||||
test -f docs/security/ruview-forecast-threat-model.md
|
||||
test -f docs/validation/ruforecast-requirements-evidence.md
|
||||
|
||||
for adr_number in 348 349 350; do
|
||||
mapfile -t adr_files < <(
|
||||
find docs/adr -maxdepth 1 -type f -name "ADR-${adr_number}-*.md" -print
|
||||
)
|
||||
if [[ "${#adr_files[@]}" -ne 1 ]]; then
|
||||
echo "Expected exactly one ADR-${adr_number} file, found ${#adr_files[@]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -q "^# ADR-${adr_number}:" "${adr_files[0]}"
|
||||
grep -Eq '^[-*] \*\*Status\*\*: (Proposed|Accepted|Superseded|Deprecated)( |$|—)|^## Status' "${adr_files[0]}"
|
||||
done
|
||||
|
||||
grep -q '^## Requirements' docs/adr/ADR-348-*.md
|
||||
grep -q '^## Acceptance gates' docs/adr/ADR-348-*.md
|
||||
grep -q '^## Requirements and acceptance' docs/adr/ADR-349-*.md
|
||||
grep -q '^## Requirements and acceptance' docs/adr/ADR-350-*.md
|
||||
for adr_number in 348 349 350; do
|
||||
grep -q "| \[ADR-${adr_number}\](ADR-${adr_number}-" docs/adr/README.md \
|
||||
|| { echo "ADR-${adr_number} is missing from the ADR index" >&2; exit 1; }
|
||||
done
|
||||
|
||||
for number in $(seq 1 12); do
|
||||
requirement="$(printf 'RF-%03d' "$number")"
|
||||
grep -q "| ${requirement} |" docs/validation/ruforecast-requirements-evidence.md \
|
||||
|| { echo "Missing evidence row for ${requirement}" >&2; exit 1; }
|
||||
done
|
||||
for number in $(seq 1 8); do
|
||||
requirement="$(printf 'FT-%03d' "$number")"
|
||||
grep -q "| ${requirement} |" docs/validation/ruforecast-requirements-evidence.md \
|
||||
|| { echo "Missing evidence row for ${requirement}" >&2; exit 1; }
|
||||
done
|
||||
for number in $(seq 1 9); do
|
||||
requirement="$(printf 'PM-%03d' "$number")"
|
||||
grep -q "| ${requirement} |" docs/validation/ruforecast-requirements-evidence.md \
|
||||
|| { echo "Missing evidence row for ${requirement}" >&2; exit 1; }
|
||||
done
|
||||
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import tomllib
|
||||
|
||||
root = Path("v2/crates/ruforecast/crates")
|
||||
core = tomllib.loads((root / "ruforecast-core/Cargo.toml").read_text())
|
||||
model = tomllib.loads((root / "ruforecast-model/Cargo.toml").read_text())
|
||||
train = tomllib.loads((root / "ruforecast-train/Cargo.toml").read_text())
|
||||
|
||||
assert core.get("features", {}).get("default", []) == []
|
||||
assert model["features"]["default"] == [], "model defaults must stay backend-free"
|
||||
assert train["features"]["default"] == [], "train defaults must stay backend-free"
|
||||
assert {"model", "cpu", "cuda", "wgpu", "ruvector"} <= model["features"].keys()
|
||||
assert {"cpu", "cuda", "training", "cli", "server", "fal-client"} <= train["features"].keys()
|
||||
assert {"model", "dep:burn-ndarray"} <= set(model["features"]["cpu"])
|
||||
assert {"model", "dep:burn-cuda"} <= set(model["features"]["cuda"])
|
||||
assert {"model", "dep:burn-wgpu"} <= set(model["features"]["wgpu"])
|
||||
assert "dep:ruvector-core" in model["features"]["ruvector"]
|
||||
assert {"ruforecast-model/cpu", "training"} <= set(train["features"]["cpu"])
|
||||
assert {"ruforecast-model/cuda", "training"} <= set(train["features"]["cuda"])
|
||||
|
||||
bins = {entry["name"]: entry for entry in train.get("bin", [])}
|
||||
assert bins["ruforecast"]["required-features"] == ["cli"]
|
||||
|
||||
model_benches = {entry["name"]: entry for entry in model.get("bench", [])}
|
||||
train_benches = {entry["name"]: entry for entry in train.get("bench", [])}
|
||||
assert model_benches["forecast_inference"]["harness"] is False
|
||||
assert model_benches["forecast_inference"]["required-features"] == ["cpu"]
|
||||
assert train_benches["data_pipeline"]["harness"] is False
|
||||
assert train_benches["data_pipeline"]["required-features"] == ["cpu"]
|
||||
PY
|
||||
|
||||
- name: Check formatting for forecast packages only
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.89.0 fmt
|
||||
-p ruforecast-core
|
||||
-p ruforecast-model
|
||||
-p ruforecast-train
|
||||
-- --check
|
||||
|
||||
- name: Prove feature-off graph excludes Burn and CubeCL
|
||||
working-directory: v2/crates/ruforecast
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
: > forecast-feature-off-tree.txt
|
||||
for package in ruforecast-core ruforecast-model ruforecast-train; do
|
||||
cargo +1.89.0 tree --locked -e normal,build -p "$package" --no-default-features \
|
||||
>> forecast-feature-off-tree.txt
|
||||
done
|
||||
if grep -Eiq '(^|[[:space:]])(burn|cubecl)(-|[[:space:]])' forecast-feature-off-tree.txt; then
|
||||
echo 'Burn/CubeCL entered the Rust 1.89 feature-off dependency graph.' >&2
|
||||
cat forecast-feature-off-tree.txt >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Check feature-off packages
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.89.0 check --locked
|
||||
-p ruforecast-core
|
||||
-p ruforecast-model
|
||||
-p ruforecast-train
|
||||
--no-default-features --all-targets
|
||||
|
||||
- name: Test model-neutral core
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.89.0 test --locked
|
||||
-p ruforecast-core
|
||||
--no-default-features --lib --tests
|
||||
|
||||
- name: Test model contracts without a model backend
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.89.0 test --locked
|
||||
-p ruforecast-model
|
||||
--no-default-features --lib --tests
|
||||
|
||||
- name: Test RuVector retrieval boundary without a model backend
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.89.0 test --locked
|
||||
-p ruforecast-model
|
||||
--no-default-features --features ruvector --lib --tests
|
||||
|
||||
- name: Clippy RuVector retrieval boundary
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.89.0 clippy --locked
|
||||
-p ruforecast-model
|
||||
--no-default-features --features ruvector --all-targets -- -D warnings
|
||||
|
||||
- name: Clippy forecast packages without backend features
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.89.0 clippy --locked
|
||||
-p ruforecast-core
|
||||
-p ruforecast-model
|
||||
-p ruforecast-train
|
||||
--no-default-features --all-targets -- -D warnings
|
||||
|
||||
- name: Upload feature-off dependency tree
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: ruforecast-feature-off-tree
|
||||
path: v2/crates/ruforecast/forecast-feature-off-tree.txt
|
||||
if-no-files-found: error
|
||||
|
||||
hosted-boundaries-rust-189:
|
||||
name: Forecast hosted boundaries and privacy contract (Rust 1.89)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- name: Checkout recursively
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Rust 1.89 with Clippy
|
||||
uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4
|
||||
with:
|
||||
toolchain: 1.89.0
|
||||
components: clippy
|
||||
|
||||
- name: Cache Cargo artifacts
|
||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32
|
||||
with:
|
||||
workspaces: v2/crates/ruforecast
|
||||
key: ruforecast-hosted-rust-189
|
||||
|
||||
- name: Enforce clean-room source, secret, and hosted-wire boundary
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
|
||||
roots = [
|
||||
Path("v2/crates/ruforecast/crates/ruforecast-core"),
|
||||
Path("v2/crates/ruforecast/crates/ruforecast-model"),
|
||||
Path("v2/crates/ruforecast/crates/ruforecast-train"),
|
||||
]
|
||||
text_suffixes = {".json", ".py", ".rs", ".sh", ".toml", ".yaml", ".yml"}
|
||||
forbidden_source = re.compile(r"(?i)\b(?:times[ _-]?fm|google[ _/-]?research)\b")
|
||||
secret_patterns = {
|
||||
"private key": re.compile(r"-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----"),
|
||||
"AWS access key": re.compile(r"\bAKIA[0-9A-Z]{16}\b"),
|
||||
"JWT": re.compile(r"\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b"),
|
||||
"presigned URL": re.compile(r"(?i)[?&](?:X-Amz-Signature|X-Goog-Signature)="),
|
||||
"literal FAL_KEY": re.compile(r"(?i)\bFAL_KEY\b\s*[:=]\s*['\"][^'$<{\"\n]{8,}['\"]"),
|
||||
}
|
||||
forbidden_blobs = {".ckpt", ".mpk", ".npy", ".npz", ".onnx", ".pt", ".pth", ".safetensors"}
|
||||
|
||||
errors = []
|
||||
for root in roots:
|
||||
for path in root.rglob("*"):
|
||||
if not path.is_file() or "target" in path.parts:
|
||||
continue
|
||||
if path.suffix.lower() in forbidden_blobs:
|
||||
errors.append(f"forbidden checked-in model/data blob: {path}")
|
||||
continue
|
||||
if path.suffix.lower() not in text_suffixes:
|
||||
continue
|
||||
text = path.read_text(encoding="utf-8")
|
||||
if forbidden_source.search(text):
|
||||
errors.append(f"forbidden clean-room source/import reference: {path}")
|
||||
for label, pattern in secret_patterns.items():
|
||||
if pattern.search(text):
|
||||
errors.append(f"possible {label} in {path}")
|
||||
|
||||
fal_source = Path("v2/crates/ruforecast/crates/ruforecast-train/src/fal.rs").read_text()
|
||||
for struct_name in ("HostedOptimizer", "HostedBudget", "HostedSyntheticPayload"):
|
||||
match = re.search(
|
||||
rf"pub struct {struct_name}\s*\{{(?P<body>.*?)^\}}",
|
||||
fal_source,
|
||||
flags=re.MULTILINE | re.DOTALL,
|
||||
)
|
||||
if match is None:
|
||||
errors.append(f"missing hosted wire struct: {struct_name}")
|
||||
continue
|
||||
body = match.group("body")
|
||||
fields = re.findall(r"^\s*pub\s+([A-Za-z0-9_]+)\s*:", body, re.MULTILINE)
|
||||
forbidden_fields = (
|
||||
"account", "data_policy", "dataset", "device", "identity", "path",
|
||||
"person", "room", "session", "site", "split", "subject", "tenant",
|
||||
"workspace",
|
||||
)
|
||||
for field in fields:
|
||||
lowered = field.lower()
|
||||
if any(fragment in lowered for fragment in forbidden_fields):
|
||||
errors.append(f"forbidden hosted field {struct_name}.{field}")
|
||||
if "bytes" in lowered and field not in {
|
||||
"max_artifact_bytes",
|
||||
"max_memory_bytes",
|
||||
}:
|
||||
errors.append(f"unapproved hosted byte field {struct_name}.{field}")
|
||||
if "DataPolicy" in body:
|
||||
errors.append(f"DataPolicy entered hosted wire struct {struct_name}")
|
||||
|
||||
if errors:
|
||||
print("\n".join(errors), file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
PY
|
||||
|
||||
- name: Enforce tracked-data policy
|
||||
run: |
|
||||
set -euo pipefail
|
||||
bash scripts/csi-data-policy-check.sh --self-test
|
||||
bash scripts/csi-data-policy-check.sh --tracked
|
||||
|
||||
- name: Validate minimal fal deployment archive policy
|
||||
run: >-
|
||||
python3
|
||||
v2/crates/ruforecast/crates/ruforecast-train/deploy/fal/deploy.py
|
||||
self-test
|
||||
|
||||
- name: Prove hosted feature graph excludes Burn and CubeCL
|
||||
working-directory: v2/crates/ruforecast
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cargo +1.89.0 tree --locked -e normal,build \
|
||||
-p ruforecast-train \
|
||||
--no-default-features --features cli,server,fal-client \
|
||||
> forecast-hosted-feature-tree.txt
|
||||
if grep -Eiq '(^|[[:space:]])(burn|cubecl)(-|[[:space:]])' \
|
||||
forecast-hosted-feature-tree.txt; then
|
||||
echo 'Burn/CubeCL entered the Rust 1.89 hosted dependency graph.' >&2
|
||||
cat forecast-hosted-feature-tree.txt >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Require named hosted boundary regressions
|
||||
working-directory: v2/crates/ruforecast
|
||||
shell: bash
|
||||
env:
|
||||
FAL_KEY: ''
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cargo +1.89.0 test --locked \
|
||||
-p ruforecast-train \
|
||||
--no-default-features --features cli,server,fal-client \
|
||||
--lib --bins --tests -- --list \
|
||||
| tee hosted-boundary-tests.txt
|
||||
for regression in \
|
||||
fal_app_rejects_path_and_host_confusion \
|
||||
fal_urls_require_exact_origin_path_and_no_query \
|
||||
fal_submit_headers_disable_retry_and_omit_store_io \
|
||||
hosted_payload_dto_has_no_customer_fields \
|
||||
queue_status_discards_provider_error_body \
|
||||
result_url_accepts_exact_response_suffix \
|
||||
artifact_file_url_uses_expected_api_path \
|
||||
fal_key_debug_is_redacted \
|
||||
hosted_payload_rejects_app_field \
|
||||
hosted_reservation_cannot_exceed_source_retention \
|
||||
artifact_handoff_expiry_boundary_is_fail_closed \
|
||||
fal_result_enforces_cumulative_artifact_budget_boundary \
|
||||
fal_download_rejects_over_budget_without_writing \
|
||||
direct_server_train_requires_request_id_header \
|
||||
request_id_rejects_path_injection \
|
||||
unknown_cancel_is_not_success \
|
||||
privacy_external_dataset_payload_is_denied; do
|
||||
grep -q "$regression" hosted-boundary-tests.txt \
|
||||
|| { echo "Missing hosted boundary regression: $regression" >&2; exit 1; }
|
||||
done
|
||||
|
||||
- name: Exercise hosted external-data rejection
|
||||
working-directory: v2/crates/ruforecast
|
||||
env:
|
||||
FAL_KEY: ''
|
||||
run: >-
|
||||
cargo +1.89.0 test --locked
|
||||
-p ruforecast-train
|
||||
--no-default-features --features cli,server,fal-client
|
||||
privacy_external_dataset_payload_is_denied
|
||||
|
||||
- name: Test server and fal client with mock integrations
|
||||
working-directory: v2/crates/ruforecast
|
||||
env:
|
||||
FAL_KEY: ''
|
||||
run: >-
|
||||
cargo +1.89.0 test --locked
|
||||
-p ruforecast-train
|
||||
--no-default-features --features cli,server,fal-client
|
||||
--lib --bins --tests
|
||||
|
||||
- name: Clippy server and fal client boundaries
|
||||
working-directory: v2/crates/ruforecast
|
||||
env:
|
||||
FAL_KEY: ''
|
||||
run: >-
|
||||
cargo +1.89.0 clippy --locked
|
||||
-p ruforecast-train
|
||||
--no-default-features --features cli,server,fal-client
|
||||
--all-targets -- -D warnings
|
||||
|
||||
- name: Clippy standalone CLI feature boundary
|
||||
working-directory: v2/crates/ruforecast
|
||||
env:
|
||||
FAL_KEY: ''
|
||||
run: >-
|
||||
cargo +1.89.0 clippy --locked
|
||||
-p ruforecast-train
|
||||
--no-default-features --features cli
|
||||
--bin ruforecast -- -D warnings
|
||||
|
||||
- name: Upload hosted dependency tree
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: ruforecast-hosted-feature-tree
|
||||
path: v2/crates/ruforecast/forecast-hosted-feature-tree.txt
|
||||
if-no-files-found: error
|
||||
|
||||
burn-cpu-rust-192:
|
||||
name: Forecast Burn CPU tests and bench compile (Rust 1.92)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- name: Checkout recursively
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Rust 1.92 with Clippy
|
||||
uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4
|
||||
with:
|
||||
toolchain: 1.92.0
|
||||
components: clippy
|
||||
|
||||
- name: Cache Cargo artifacts
|
||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32
|
||||
with:
|
||||
workspaces: v2/crates/ruforecast
|
||||
key: ruforecast-rust-192-cpu
|
||||
|
||||
- name: Test model with Burn CPU backend
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.92.0 test --locked
|
||||
-p ruforecast-model
|
||||
--no-default-features --features cpu --lib --tests
|
||||
|
||||
- name: Test trainer and CLI with Burn CPU backend
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.92.0 test --locked
|
||||
-p ruforecast-train
|
||||
--no-default-features --features cpu,cli --lib --bins
|
||||
|
||||
- name: Run one-step local JSONL training smoke
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.92.0 test --locked
|
||||
-p ruforecast-train
|
||||
--no-default-features --features cpu
|
||||
--test local_jsonl_smoke --
|
||||
--exact local_hash_addressed_jsonl_executes_one_real_optimizer_step
|
||||
|
||||
- name: Run idempotent synthetic CLI training smoke
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.92.0 test --locked
|
||||
-p ruforecast-train
|
||||
--no-default-features --features cpu,cli
|
||||
--test cli_smoke --
|
||||
--exact cli_smoke_trains_and_writes_the_complete_candidate_set
|
||||
|
||||
- name: Test combined CPU and hosted feature surface
|
||||
working-directory: v2/crates/ruforecast
|
||||
env:
|
||||
FAL_KEY: ''
|
||||
run: >-
|
||||
cargo +1.92.0 test --locked
|
||||
-p ruforecast-train
|
||||
--no-default-features --features cpu,cli,server,fal-client
|
||||
--lib --bins
|
||||
|
||||
- name: Clippy model with Burn CPU backend
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.92.0 clippy --locked
|
||||
-p ruforecast-model
|
||||
--no-default-features --features cpu --all-targets -- -D warnings
|
||||
|
||||
- name: Clippy trainer and CLI with Burn CPU backend
|
||||
working-directory: v2/crates/ruforecast
|
||||
env:
|
||||
FAL_KEY: ''
|
||||
run: >-
|
||||
cargo +1.92.0 clippy --locked
|
||||
-p ruforecast-train
|
||||
--no-default-features --features cpu,cli,server,fal-client
|
||||
--all-targets -- -D warnings
|
||||
|
||||
- name: Compile forecast inference benchmark
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.92.0 bench --locked
|
||||
-p ruforecast-model
|
||||
--no-default-features --features cpu
|
||||
--bench forecast_inference --no-run
|
||||
|
||||
- name: Compile forecast data-pipeline benchmark
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.92.0 bench --locked
|
||||
-p ruforecast-train
|
||||
--no-default-features --features cpu
|
||||
--bench data_pipeline --no-run
|
||||
|
||||
- name: Run quick inference benchmark for trend visibility
|
||||
continue-on-error: true
|
||||
timeout-minutes: 15
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: |
|
||||
set -o pipefail
|
||||
mkdir -p ../../bench-out/ruforecast
|
||||
cargo +1.92.0 bench --locked \
|
||||
-p ruforecast-model \
|
||||
--no-default-features --features cpu \
|
||||
--bench forecast_inference -- \
|
||||
--warm-up-time 1 --measurement-time 2 --sample-size 10 \
|
||||
| tee ../../bench-out/ruforecast/forecast-inference.txt
|
||||
|
||||
- name: Run quick data-pipeline benchmark for trend visibility
|
||||
continue-on-error: true
|
||||
timeout-minutes: 15
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: |
|
||||
set -o pipefail
|
||||
mkdir -p ../../bench-out/ruforecast
|
||||
cargo +1.92.0 bench --locked \
|
||||
-p ruforecast-train \
|
||||
--no-default-features --features cpu \
|
||||
--bench data_pipeline -- \
|
||||
--warm-up-time 1 --measurement-time 2 --sample-size 10 \
|
||||
| tee ../../bench-out/ruforecast/data-pipeline.txt
|
||||
|
||||
- name: Upload informational benchmark logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: ruforecast-informational-cpu-benchmarks
|
||||
path: bench-out/ruforecast/
|
||||
if-no-files-found: warn
|
||||
|
||||
burn-cuda-compile-rust-192:
|
||||
name: Forecast Burn CUDA/WGPU compile checks only (Rust 1.92)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: Checkout recursively
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Rust 1.92
|
||||
uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4
|
||||
with:
|
||||
toolchain: 1.92.0
|
||||
|
||||
- name: Cache Cargo artifacts
|
||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32
|
||||
with:
|
||||
workspaces: v2/crates/ruforecast
|
||||
key: ruforecast-rust-192-cuda-check
|
||||
|
||||
- name: Check model CUDA feature
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.92.0 check --locked
|
||||
-p ruforecast-model
|
||||
--no-default-features --features cuda --lib
|
||||
|
||||
- name: Check model WGPU feature
|
||||
working-directory: v2/crates/ruforecast
|
||||
run: >-
|
||||
cargo +1.92.0 check --locked
|
||||
-p ruforecast-model
|
||||
--no-default-features --features wgpu --lib
|
||||
|
||||
- name: Check trainer CUDA and hosted-server feature combination
|
||||
working-directory: v2/crates/ruforecast
|
||||
env:
|
||||
FAL_KEY: ''
|
||||
run: >-
|
||||
cargo +1.92.0 check --locked
|
||||
-p ruforecast-train
|
||||
--no-default-features --features cuda,cli,server
|
||||
--lib --bins
|
||||
@@ -0,0 +1,68 @@
|
||||
# ADR-373/374 — device-access end-to-end through the real @ruvnet/ruview CLI.
|
||||
# MR60BHA2 (60 GHz) and RPLIDAR are emulated on pseudo-terminals and read via
|
||||
# real pyserial; an ESP32 node is emulated over UDP; the iPhone LiDAR path
|
||||
# uses the repository's real relay. All results are SYNTHETIC: this proves
|
||||
# the transports and parsers, not hardware behaviour.
|
||||
|
||||
name: ruview device e2e
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'harness/ruview/src/**'
|
||||
- 'harness/ruview/bin/**'
|
||||
- 'harness/ruview/test/e2e/**'
|
||||
- 'integrations/iphone-lidar/web/**'
|
||||
- '.github/workflows/ruview-device-e2e.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'harness/ruview/src/**'
|
||||
- 'harness/ruview/bin/**'
|
||||
- 'harness/ruview/test/e2e/**'
|
||||
- 'integrations/iphone-lidar/web/**'
|
||||
- '.github/workflows/ruview-device-e2e.yml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ruview-device-e2e-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
devices:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install pyserial
|
||||
run: python -m pip install pyserial==3.5
|
||||
|
||||
- name: Install the iPhone LiDAR relay
|
||||
working-directory: integrations/iphone-lidar/web
|
||||
run: npm ci --ignore-scripts
|
||||
|
||||
- name: Install harness
|
||||
working-directory: harness/ruview
|
||||
run: npm ci --ignore-scripts
|
||||
|
||||
# Missing prerequisites fail instead of skipping (RUVIEW_E2E_REQUIRE).
|
||||
# The suite links each emulator pty to /dev/ttyRUVIEWE2E<n> with
|
||||
# `sudo -n`, because the harness refuses /dev/pts/* port names.
|
||||
- name: Device e2e (SYNTHETIC devices)
|
||||
working-directory: harness/ruview
|
||||
env:
|
||||
RUVIEW_E2E_REQUIRE: '1'
|
||||
run: npm run test:e2e:devices
|
||||
@@ -4,6 +4,12 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'harness/ruview/**'
|
||||
- 'scripts/csi-udp-relay.py'
|
||||
- 'scripts/esp32_jsonl_to_rvcsi.py'
|
||||
- 'scripts/overnight-empty-capture.py'
|
||||
- 'scripts/record-csi-udp.py'
|
||||
- 'scripts/collect-training-data.py'
|
||||
- 'scripts/align-ground-truth.js'
|
||||
- '.github/scripts/nightly-sota/**'
|
||||
- '.github/workflows/nightly-sota-agent.yml'
|
||||
- '.github/workflows/ruview-harness-flywheel.yml'
|
||||
@@ -25,8 +31,12 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
name: Verify contributor harness
|
||||
runs-on: ubuntu-latest
|
||||
name: Verify contributor harness (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
defaults:
|
||||
run:
|
||||
working-directory: harness/ruview
|
||||
@@ -39,9 +49,13 @@ jobs:
|
||||
node-version: 22
|
||||
cache: npm
|
||||
cache-dependency-path: harness/ruview/package-lock.json
|
||||
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- run: npm ci --ignore-scripts
|
||||
- run: npm audit --omit=optional
|
||||
- run: npm test
|
||||
- run: npm run test:security
|
||||
- run: npm run brain:verify
|
||||
- run: npm run flywheel:plan
|
||||
- run: npm run flywheel:verify
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
# ADR-368 — @ruvnet/ruview-kernel: build the WASM and napi-rs transports from
|
||||
# source on every OS, run the Rust ABI tests, the package unit/security/e2e
|
||||
# tests with the native addon REQUIRED, the wasm↔napi parity check, artifact
|
||||
# verification, and the cross-package e2e through the @ruvnet/ruview
|
||||
# metaharness. No publish step: publication stays CI-only via the release
|
||||
# workflow and requires explicit maintainer approval (ADR-265).
|
||||
|
||||
name: ruview-kernel npm
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'v2/crates/ruview-kernel/**'
|
||||
- 'v2/crates/ruview-kernel-napi/**'
|
||||
- 'v2/crates/wifi-densepose-vitals/**'
|
||||
- 'harness/ruview-kernel/**'
|
||||
- 'harness/ruview/src/kernel.js'
|
||||
- 'harness/ruview/test/kernel.test.mjs'
|
||||
- '.github/workflows/ruview-kernel-npm.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'v2/crates/ruview-kernel/**'
|
||||
- 'v2/crates/ruview-kernel-napi/**'
|
||||
- 'v2/crates/wifi-densepose-vitals/**'
|
||||
- 'harness/ruview-kernel/**'
|
||||
- 'harness/ruview/src/kernel.js'
|
||||
- 'harness/ruview/test/kernel.test.mjs'
|
||||
- '.github/workflows/ruview-kernel-npm.yml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ruview-kernel-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
kernel:
|
||||
name: kernel (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
# The v2 workspace lists submodule crates as members; cargo must be
|
||||
# able to load every member manifest.
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Rust + wasm32 target
|
||||
uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4
|
||||
with:
|
||||
targets: wasm32-unknown-unknown
|
||||
|
||||
# v2/rust-toolchain pins its own channel; the target must be installed
|
||||
# for that toolchain, not only for the action's default `stable`.
|
||||
- name: Add wasm32 target to the pinned v2 toolchain
|
||||
working-directory: v2
|
||||
run: rustup target add wasm32-unknown-unknown
|
||||
|
||||
- name: Cache cargo
|
||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32
|
||||
with:
|
||||
workspaces: |
|
||||
v2 -> target
|
||||
v2/crates/ruview-kernel-napi -> target
|
||||
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- name: Rust ABI tests
|
||||
run: cargo test --manifest-path v2/Cargo.toml -p ruview-kernel --locked
|
||||
|
||||
- name: Build WASM + napi-rs artifacts from source
|
||||
working-directory: harness/ruview-kernel
|
||||
run: npm run build
|
||||
|
||||
- name: Verify artifacts (checksums, zero WASM imports, ABI)
|
||||
working-directory: harness/ruview-kernel
|
||||
run: node scripts/verify-artifacts.mjs --require-wasm
|
||||
|
||||
- name: Package tests (napi required)
|
||||
working-directory: harness/ruview-kernel
|
||||
env:
|
||||
RUVIEW_KERNEL_REQUIRE_NAPI: '1'
|
||||
run: npm test
|
||||
|
||||
- name: Doctor, self-test, and wasm↔napi parity (SYNTHETIC)
|
||||
working-directory: harness/ruview-kernel
|
||||
run: |
|
||||
node bin/cli.js doctor --strict-napi
|
||||
node bin/cli.js selftest --backend wasm
|
||||
node bin/cli.js selftest --backend napi
|
||||
node bin/cli.js parity
|
||||
|
||||
- name: Pack
|
||||
working-directory: harness/ruview-kernel
|
||||
run: |
|
||||
npm pack --dry-run
|
||||
# Relative destination: Windows runner temp paths contain
|
||||
# backslashes that bash globbing would mangle.
|
||||
mkdir -p dist-pack
|
||||
npm pack --pack-destination dist-pack
|
||||
|
||||
- name: Cross-package e2e through the @ruvnet/ruview metaharness
|
||||
working-directory: harness/ruview
|
||||
run: |
|
||||
npm ci --ignore-scripts
|
||||
npm install --no-save --ignore-scripts ../ruview-kernel/dist-pack/ruvnet-ruview-kernel-*.tgz
|
||||
node --test test/kernel.test.mjs
|
||||
node bin/cli.js kernel --backend auto
|
||||
|
||||
- name: Upload built artifacts
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ruview-kernel-linux-x64
|
||||
path: |
|
||||
harness/ruview-kernel/wasm/ruview_kernel.wasm
|
||||
harness/ruview-kernel/wasm/SHA256SUMS
|
||||
harness/ruview-kernel/native/*.node
|
||||
harness/ruview-kernel/native/SHA256SUMS
|
||||
retention-days: 14
|
||||
@@ -104,8 +104,10 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
case "${{ inputs.package }}" in
|
||||
# ADR-283: brain + local hosts + replay assets; no runtime deps.
|
||||
harness/ruview) export UNPACKED_BUDGET=131072 ;;
|
||||
# ADR-283/325/369-374: brain + hosts + replay + Spaces OAuth + SDK,
|
||||
# flashing, training, doctor, device access, SSH hosts; ADR-375 console
|
||||
# widget, HTTP transport, terminal UI; ADR-378 mod showcase; no runtime deps.
|
||||
harness/ruview) export UNPACKED_BUDGET=458752 ;;
|
||||
# ADR-285: CLI + MCP + reviewed brain + WASM-kernel adapter.
|
||||
harness/homecore) export UNPACKED_BUDGET=180000 ;;
|
||||
# ADR-264 O2: map-free tarball (was 188 kB with maps).
|
||||
@@ -140,12 +142,12 @@ jobs:
|
||||
npm i --no-fund --no-audit "$TGZ"
|
||||
case "${{ inputs.package }}" in
|
||||
harness/ruview)
|
||||
./node_modules/.bin/ruview --version
|
||||
./node_modules/.bin/ruview doctor
|
||||
./node_modules/.bin/ruview guidance --topic homecore --query restore --limit 1 \
|
||||
./node_modules/.bin/ruview-harness --version
|
||||
./node_modules/.bin/ruview-harness doctor
|
||||
./node_modules/.bin/ruview-harness guidance --topic homecore --query restore --limit 1 \
|
||||
| grep -q '"homecore-runtime-restore"'
|
||||
# the honesty gate must fail closed on empty input (ADR-263 F1)
|
||||
if ./node_modules/.bin/ruview claim-check; then
|
||||
if ./node_modules/.bin/ruview-harness claim-check; then
|
||||
echo 'claim-check passed with no input — fail-open regression'; exit 1
|
||||
fi
|
||||
node --input-type=module -e "const m = await import('@ruvnet/ruview'); if (!m.TOOLS) process.exit(1);"
|
||||
|
||||
@@ -14,6 +14,33 @@ env:
|
||||
PYTHON_VERSION: '3.11'
|
||||
|
||||
jobs:
|
||||
# Rust dependency advisories are deterministic for the checked-in lockfile,
|
||||
# so this job gates the PR and retains the exact machine-readable report.
|
||||
rust-audit:
|
||||
name: Rust Dependency Audit
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
|
||||
- name: Install cargo-audit
|
||||
run: cargo install cargo-audit --locked --version 0.22.2
|
||||
|
||||
- name: Audit the checked-in Rust lockfile
|
||||
run: |
|
||||
set -o pipefail
|
||||
cargo audit --file v2/Cargo.lock --json | tee v2/cargo-audit.json
|
||||
|
||||
- name: Upload Rust advisory report
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
if: always()
|
||||
with:
|
||||
name: cargo-audit-report
|
||||
path: v2/cargo-audit.json
|
||||
if-no-files-found: error
|
||||
|
||||
# Static Application Security Testing (SAST)
|
||||
sast:
|
||||
name: Static Application Security Testing
|
||||
|
||||
@@ -28,6 +28,7 @@ on:
|
||||
- 'v2/crates/wifi-densepose-wifiscan/**'
|
||||
- 'v2/crates/wifi-densepose-bfld/**'
|
||||
- 'v2/crates/cog-ha-matter/**'
|
||||
- 'v2/crates/homecore*/**'
|
||||
- 'v2/Cargo.toml'
|
||||
- 'v2/Cargo.lock'
|
||||
- 'ui/**'
|
||||
|
||||
@@ -17,11 +17,16 @@ firmware/esp32-csi-node/sdkconfig.defaults.bak
|
||||
firmware/esp32-hello-world/sdkconfig.old
|
||||
|
||||
# Host-built firmware test binaries (compiled from test/*.c, not source)
|
||||
firmware/esp32-csi-node/test/test_adr110
|
||||
firmware/esp32-csi-node/test/test_vitals
|
||||
firmware/esp32-csi-node/test/fuzz_serialize
|
||||
firmware/esp32-csi-node/test/fuzz_edge
|
||||
firmware/esp32-csi-node/test/fuzz_nvs
|
||||
# Compiled host-test and fuzz binaries. The Makefile writes them beside their
|
||||
# sources, so they land in a tracked directory. Ignore them by SHAPE rather
|
||||
# than by name: every source here carries an extension and no binary does.
|
||||
#
|
||||
# This replaced a hand-maintained list of five targets, which had gone stale --
|
||||
# test_csi_sanitize, test_mmwave_detect and test_thermal were all built by
|
||||
# `make host_tests`, ignored by nothing, and got committed by accident.
|
||||
firmware/esp32-csi-node/test/test_*
|
||||
firmware/esp32-csi-node/test/fuzz_*
|
||||
!firmware/esp32-csi-node/test/*.*
|
||||
firmware/esp32-csi-node/test/*.exe
|
||||
firmware/esp32-csi-node/test/*.obj
|
||||
|
||||
@@ -311,3 +316,12 @@ v2/crates/wifi-densepose-sensing-server/data/
|
||||
# ADR-324: wasm-bindgen output for ruview-offaxis is generated locally
|
||||
# (see the crate README); never commit generated artifacts.
|
||||
v2/crates/ruview-offaxis/pkg/
|
||||
|
||||
# fal.ai visual-teacher LoRA training data/weights -- regenerable, never
|
||||
# commit training images or model weights (ADR-353)
|
||||
scripts/fal-visual-teacher/training-data/
|
||||
scripts/fal-visual-teacher/training-data.zip
|
||||
scripts/fal-visual-teacher/output/
|
||||
|
||||
# Trained adaptive classifier (auto-created at runtime; #2135)
|
||||
/v2/data/adaptive_model.json
|
||||
@@ -33,3 +33,7 @@
|
||||
path = vendor/metaharness
|
||||
url = https://github.com/ruvnet/metaharness
|
||||
branch = main
|
||||
[submodule "v2/crates/ruforecast"]
|
||||
path = v2/crates/ruforecast
|
||||
url = https://github.com/ruvnet/RuForecast.git
|
||||
branch = main
|
||||
@@ -47,17 +47,18 @@ from the current tree when needed.
|
||||
|
||||
## RuView contributor harness
|
||||
|
||||
`@ruvnet/ruview@0.3.1` is the runtime-dependency-free contributor interface
|
||||
`@ruvnet/ruview@0.5.0` is the runtime-dependency-free contributor interface
|
||||
defined by ADR-283.
|
||||
|
||||
```bash
|
||||
npx @ruvnet/ruview@0.3.1 doctor
|
||||
npx @ruvnet/ruview@0.3.1 guidance --topic homecore --query "restore and plugins"
|
||||
npx @ruvnet/ruview@0.3.1 agent run \
|
||||
npx @ruvnet/ruview@0.5.0 doctor
|
||||
npx @ruvnet/ruview@0.5.0 guidance --topic homecore --query "restore and plugins"
|
||||
npx @ruvnet/ruview@0.5.0 agent run \
|
||||
--host codex --repo . --prompt "Find the nearest tests and cite files"
|
||||
npx @ruvnet/ruview@0.3.1 brain search --query "community memory"
|
||||
npx @ruvnet/ruview@0.3.1 brain verify --repo .
|
||||
npx @ruvnet/ruview@0.3.1 mcp start
|
||||
npx @ruvnet/ruview@0.5.0 brain search --query "community memory"
|
||||
npx @ruvnet/ruview@0.5.0 brain verify --repo .
|
||||
npx @ruvnet/ruview@0.5.0 spaces
|
||||
npx @ruvnet/ruview@0.5.0 mcp start
|
||||
```
|
||||
|
||||
Start unfamiliar repository work with `ruview_guidance`. It returns reviewed
|
||||
|
||||
@@ -7,8 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Community batch (PRs #2100-#2157 by aepod, reviewed and integrated)
|
||||
|
||||
Integrated as one set: conflicts resolved, review findings fixed, validated on the integrated branch. Hardware figures cited by the PRs are the author's own live runs on ESP32-S3 nodes and were not independently reproduced here.
|
||||
|
||||
- **Security and honest status.** Refuse a routable HTTP bind when API auth is off (#2134). `--privacy-mode` now strips biometrics from REST, WebSocket and recordings, not only MQTT (#2125; the stripped-key list is an exact-match allowlist, so a new biometric field must be added to it). `/api/v1/status` waits for a real frame and unknown `--source` values are rejected (#2126; breaking for `--source macos|linux|windows`). A stale `/sensing/latest` reports `{"status":"stale"}` after 10 s (#2119). Measured stream fps and real WebSocket client counts (#2127). Absent nodes no longer count as one person (#2132). ESP32 frames with zero antennas or subcarriers are dropped (#2118). Dead nodes are evicted on a timer (#2120). Recordings and models stay under `--data-dir` (#2129). Boolean env flags accept 1/0/yes/no/on/off (#2108). Docker UDP ingest posture is explicit (#2107).
|
||||
- **CSI pipeline.** The grid gate locks on the majority frame shape and `/health` reports a stalled pipeline (#2157; a partial fix, mixed 192/306 frame shapes still drop frames, so it does not close #1894). Phase is combined across nodes only when they declare a shared reference (#2156). Point-cloud and hardware parsers use the ADR-018 layout and accept more than 256 subcarriers (#2155; the bandwidth rule for counts above 64 is CLAIMED, inferred from the datasheet). Per-node adaptive training from real recordings (#2101, #2103); a run that fell back to the live buffer now reports `degraded: true`. Gaussian decay no longer compounds across calls (#2140).
|
||||
- **MediaTek (ADR-266/267).** Legacy and unknown PPDU types in MTC1 (#2112), per-device ingest capped at 64 devices (#2113), a labelled amplitude heuristic and activity index (#2114; CLAIMED, not an occupancy estimate), an MT7981 bridge (#2115), and the OpenWrt WN586X3 patch set and guide (#2116; the vendored CSI patch is BSD-3-Clause-Clear, see `NOTICE`).
|
||||
- **MQTT / Home Assistant.** Semantic states wired into the publisher, entities announced only when sourced, persisted client id (#2117). Existing Home Assistant installs keep retained discovery configs for the six removed entities until they are cleared manually.
|
||||
- **Provisioning and firmware.** Wi-Fi password kept owner-only and out of argv and `--state` (#2153); state keyed by board MAC (#2152); `--dry-run` and a failed `--reset` leave state intact (#2111); OTA images confirmed by a bounded health check, which means only "reached the network and sent CSI" (#2100, ADR-379).
|
||||
- **Ground truth and spatial.** Radar window adapter and auto-labeller with a session-disjoint split and a median count baseline; radar labels carry `evidence: CLAIMED` (#2143, #2144). Node self-survey, check-only (#2145, ADR-381). The `spatial.evidence.v1` export defaults to the CODE proof grade and MEASURED requires a reproducer (#2141, ADR-382). Loopback UDP tee (#2102, ADR-380).
|
||||
- **Tooling.** `prove.sh` reports INCOMPLETE instead of PASS when a gate is skipped (#2130); ADR-018 capture scripts (#2131); API token on the ground-truth script (#2104); the UI asks for the API token instead of retrying forever (#2128); macOS redacted-link handling (#2105).
|
||||
- **Not included:** #2106 (MacWifi.app, draft) and #2142 (MR60 probe change, needs a captured MR60BHA2 boot log). `v2/data/adaptive_model.json` (41.5% training accuracy) is no longer tracked (#2135).
|
||||
|
||||
### Added
|
||||
|
||||
- **`@ruvnet/ruview` 0.9.1: live sensing views inside Claude Code (ADR-377, ADR-378).** The package now ships `ruview-live`, a Claude Code mod. Type `/ruview` and a pane opens next to the conversation showing what your sensors see right now, refreshed automatically. It has three views, switched with keys `1` `2` `3` or with `/ruview overview|waterfall|radar`:
|
||||
- **Overview**: the CSI nodes streaming to your machine (rate, packet loss, signal strength) and an optional 60 GHz radar kit (presence, distance, heart and breathing rates).
|
||||
- **CSI waterfall**: the Wi-Fi signal itself, the strength of every subcarrier over time, drawn in colour and scrolling as frames arrive. The new `ruview esp32 --spectrum` option supplies the data.
|
||||
- **Radar**: a top-down range fan with an animated ping out to the measured distance, plus heart, breathing and distance charts.
|
||||
|
||||
Every reading is labelled honestly: MEASURED or SYNTHETIC from the packets themselves; radar vitals as "device-reported, not validated"; range-only radar as "distance, not direction". The pane only reads; it never flashes or configures a device.
|
||||
|
||||
Verified on real hardware: an ESP32-C6 streaming CSI and a Seeed MR60BHA2 radar kit (MEASURED; reproducer `npx @ruvnet/ruview esp32 --seconds 4 --spectrum --json`). The package's size ceiling rises from 384 KiB to 448 KiB; it still has no runtime dependencies.
|
||||
- **`wifi-densepose-sar` — coherent wideband RF tomography research crate (ADR-287).** New standalone leaf crate (the `nvsim` pattern; zero coupling to `wifi-densepose-hardware` or any real ingestion path) implementing the synthetic-aperture-radar reconstruction primitive a handheld through-wall RF imaging device would need — motivated by comparison against Applied Electrodynamics' "WaveSight" launch, and explicitly scoped below ADR-278's RISE/DiffRadar/GeRaF reproduction gates. Ships: (1) a stepped-frequency, multi-position complex forward measurement simulator (`y_{m,k} = Σ σ_j/R² · exp(-i·4π·f·R/c) + noise`, deterministic ChaCha20 seeding); (2) delay-and-sum backprojection reconstruction onto a 3D voxel grid, rayon-parallelized over voxels; (3) threshold + local-maximum point-cloud extraction; (4) closed-form range/cross-range resolution and antenna-pose coherence-budget formulas (`ΔR=c/2B`, `δ_CR≈λR/2L`, `Δp≤λ/8`) checked against the reconstruction's *actual* behavior in `tests/physics_validation.rs` rather than merely documented — forward-simulating two targets at controlled separations and proving they resolve or merge exactly where the formulas predict, and that reconstructed focus at a known target degrades as injected antenna-pose error grows. Every number is SYNTHETIC/L0 (ADR-282) — no real wideband RF hardware backs this crate; see the crate README and `docs/tutorials/coherent-rf-tomography-backprojection.md` for the full honesty boundary and a worked walkthrough. `focus_at_point` exploits the evenly-spaced-by-construction frequency sweep (an arithmetic progression in per-term phase) to evaluate each pose's phasor once and advance it by a fixed complex-multiply step per frequency instead of one `sin`/`cos` pair per frequency — **MEASURED ~4.4-4.5x faster** (criterion regression detection, p < 0.001) than the first-shipped direct-computation version, proven equivalent (not just faster) to an independently reimplemented reference across four sweep sizes and on-/off-target points. 25 tests (22 unit + 3 integration), 0 failed, clippy-clean; MEASURED backprojection throughput ~1.7-2.3M voxels/sec (criterion, 21 poses × 32 freq steps).
|
||||
- **HOMECORE platform runtime completion — secure native/Wasmtime plugins, authenticated HAP IP, expanded Home Assistant APIs, durable restoration/migration, and voice protocols.** `homecore-server` now owns deterministic compiled-in native plugin registration plus explicitly configured, path-bounded, Ed25519 publisher-verified Wasm packages executed through Wasmtime with setup/state-change/teardown lifecycle; arbitrary native dynamic libraries remain intentionally unsupported. The optional HAP server implements persisted accessory identity and controller records, SRP-6a Pair-Setup M1–M6, X25519/Ed25519 Pair-Verify M1–M4, HKDF-SHA512/ChaCha20-Poly1305 record framing, authenticated/admin endpoint gates, replay/tamper closure, live entity synchronization, and paired-state `_hap._tcp` mDNS updates (45 focused tests; external Apple certification is not claimed). Startup restores device/entity registries and deterministic latest recorder states before plugins, and migration now atomically preserves forward-compatible device/config-entry fields. The HA-compatible surface adds events, templates, config checks, components, registries, history/logbook with SQL-enforced global response bounds, calendar/camera provider routes, and modern WebSocket negotiation while retaining a machine-readable limitations matrix for integration-specific behavior. Assist adds bounded PCM16, async STT/TTS contracts, an end-to-end speech pipeline, and an authenticated satellite session protocol; real deployments still provide the speech engines.
|
||||
- **`ruview-unified` increment 3 — Gaussian update-loop completion, separable delay-Doppler, and property-tested boundary hardening.** (1) `GaussianMap::merge_overlapping` (ADR-275 step 5: mutual-Mahalanobis + semantic-compatibility dedup catching drift the insert-time gate misses) and lifetime-aware decay (`τ_eff = τ·(1+ln(1+lifetime/τ))` — confirmed structures outlive transients at equal nominal τ). (2) `delay_doppler_map` reimplemented separably (`O(B²S+S²B)`), proven equivalent to the direct reference to <1e-10 and **measured 8.3× faster** (520 µs vs 4.34 ms at 56×8). (3) `tests/security_boundaries.rs` — 8 `proptest` properties over the boundary surfaces (arbitrary values incl. NaN/±inf via `f64::from_bits`) that found and fixed three input-controlled defects: a BLE-CS phase-unwrap infinite loop on non-finite phases and an ~1e299-iteration loop on finite-huge phases (now O(1) modular unwrap + plausibility bound), and a subnormal Gaussian scale overflowing `1/σ²` to NaN density (now physical σ/occupancy bounds). (4) New criterion benches for all increment-2 hot paths (`to_canonical` 38 µs, `ble_cs_range` 481 ns, AoI planner 647 ns/200 regions, coherent fusion 1.5 µs/32 members, factorized pose 521 ns). ruview-unified now 98 tests (87 lib + 3 acceptance + 8 security), 0 failed, clippy-clean.
|
||||
|
||||
@@ -45,7 +45,7 @@ retrieved memories, generated proposals, and old test counts are not.
|
||||
Do not hardcode crate, ADR, or test counts in instructions; derive them when a
|
||||
task needs them.
|
||||
|
||||
## Contributor metaharness (`@ruvnet/ruview@0.3.1`)
|
||||
## Contributor metaharness (`@ruvnet/ruview@0.4.0`)
|
||||
|
||||
ADR-283 defines the current community metaharness. It adds secure local
|
||||
Claude/Codex execution, a reviewed shared brain, default-deny MCP mutation
|
||||
@@ -54,21 +54,24 @@ free of runtime dependencies.
|
||||
|
||||
```bash
|
||||
# Diagnose the installed harness
|
||||
npx @ruvnet/ruview@0.3.1 doctor
|
||||
npx @ruvnet/ruview@0.4.0 doctor
|
||||
|
||||
# Get a source-cited capability map before unfamiliar work
|
||||
npx @ruvnet/ruview@0.3.1 guidance --topic homecore --query "restore and plugins"
|
||||
npx @ruvnet/ruview@0.4.0 guidance --topic homecore --query "restore and plugins"
|
||||
|
||||
# Explore this trusted checkout through Claude Code (stdin, plan/safe mode)
|
||||
npx @ruvnet/ruview@0.3.1 agent run \
|
||||
npx @ruvnet/ruview@0.4.0 agent run \
|
||||
--host claude-code --repo . --prompt "Map the relevant subsystem and cite files"
|
||||
|
||||
# Search reviewed, source-cited repository knowledge
|
||||
npx @ruvnet/ruview@0.3.1 brain search --query "community memory"
|
||||
npx @ruvnet/ruview@0.3.1 brain verify --repo .
|
||||
npx @ruvnet/ruview@0.4.0 brain search --query "community memory"
|
||||
npx @ruvnet/ruview@0.4.0 brain verify --repo .
|
||||
|
||||
# Read the OAuth-bound Cognitum Spaces projection
|
||||
npx @ruvnet/ruview@0.4.0 spaces
|
||||
|
||||
# Run the dependency-free RuView MCP server
|
||||
npx @ruvnet/ruview@0.3.1 mcp start
|
||||
npx @ruvnet/ruview@0.4.0 mcp start
|
||||
```
|
||||
|
||||
`ruview_guidance` returns reviewed capability maturity, repository citations,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
RuView third-party notices
|
||||
|
||||
This repository is licensed MIT OR Apache-2.0 (see LICENSE). The items below
|
||||
are vendored third-party material that keeps its own licence and is not
|
||||
covered by that dual licence.
|
||||
|
||||
firmware/openwrt-wn586x3/patches/1001-mtk-mt76-mt7915-csi-implement-csi-support-REBASED.patch
|
||||
What: MediaTek's mt76 mt7915 CSI patch, rebased onto openwrt/mt76
|
||||
eb567bc7 (the revision pinned by OpenWrt 24.10.8).
|
||||
Author: Bo Jiao <Bo.Jiao@mediatek.com> (original author line kept in the
|
||||
patch header); copyright MediaTek Inc.
|
||||
Origin: mediatek/mtk-openwrt-feeds @ a15454c888f4f4144c50e33b5feef4f247c5f78b
|
||||
Licence: BSD-3-Clause-Clear (SPDX identifier,
|
||||
https://spdx.org/licenses/BSD-3-Clause-Clear.html). The patch
|
||||
carries the SPDX tags and MediaTek copyright lines in its added
|
||||
files; the licence text is not reproduced here.
|
||||
Scope: A vendored patch applied to an OpenWrt/mt76 build. It is not part
|
||||
of the Rust crates, is not compiled by the Cargo workspace, and is
|
||||
not linked into any RuView binary.
|
||||
|
||||
See firmware/openwrt-wn586x3/README.md for the other patches in that
|
||||
directory and the licence each one keeps.
|
||||
@@ -2,20 +2,32 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://cognitum.one/seed">
|
||||
<img src="assets/ruview-seed.png" alt="RuView - WiFi DensePose" width="100%">
|
||||
<img src="assets/ruview-hero-h3-v3.gif" alt="RuView - WiFi DensePose — animated visualization of real-time pose estimation, breathing, and heart-rate sensing through WiFi" width="100%">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
[](docs/user-guide.md)
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center" width="33%"><a href="docs/user-guide.md"><img src="assets/readme/nav-start-spatial-v4.svg" width="180" alt="Start here" /></a><br/><a href="docs/user-guide.md">Start here</a></td>
|
||||
<td align="center" width="33%"><a href="firmware/esp32-csi-node/README.md"><img src="assets/readme/nav-hardware-spatial-v4.svg" width="180" alt="Hardware" /></a><br/><a href="firmware/esp32-csi-node/README.md">Hardware</a></td>
|
||||
<td align="center" width="33%"><a href="https://huggingface.co/ruvnet/wifi-densepose-pretrained"><img src="assets/readme/nav-models-spatial-v4.svg" width="180" alt="Models" /></a><br/><a href="https://huggingface.co/ruvnet/wifi-densepose-pretrained">Models</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" width="33%"><a href="harness/ruview/README.md"><img src="assets/readme/nav-agents-spatial-v4.svg" width="180" alt="AI toolkit" /></a><br/><a href="harness/ruview/README.md">AI toolkit</a></td>
|
||||
<td align="center" width="33%"><a href="docs/integrations/home-assistant.md"><img src="assets/readme/nav-home-spatial-v4.svg" width="180" alt="Smart home" /></a><br/><a href="docs/integrations/home-assistant.md">Smart home</a></td>
|
||||
<td align="center" width="33%"><a href="https://cognitum.one/seed"><img src="assets/readme/nav-seed-spatial-v4.svg" width="180" alt="Cognitum Seed" /></a><br/><a href="https://cognitum.one/seed">Cognitum Seed</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://cognitum.one/marketplace">
|
||||
<img src="assets/musica-promo.png" alt="Cognitum Musica" width="100%">
|
||||
</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/ruvnet/RuCelium">
|
||||
<img src="assets/rucelium-hero.png" alt="RuCelium — environmental intelligence" width="100%">
|
||||
<a href="https://ruos.cognitum.one">
|
||||
<img src="assets/ruos-animated.svg" alt="RuView — WiFi becomes spatial awareness, with Ruflo coordination and a ruOS sensing workspace" width="100%">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
||||
## **See through walls with WiFi** ##
|
||||
|
||||
**Turn ordinary WiFi into a spatial intelligence / sensing system.** Detect people, measure breathing and heart rate, track movement, and monitor rooms — through walls, in the dark, with no cameras or wearables. Just physics.
|
||||
@@ -30,6 +42,8 @@ Works natively with the four major smart-home ecosystems: **[Home Assistant](doc
|
||||
|
||||
Every WiFi router already fills your space with radio waves. When people move, breathe, or even sit still, they disturb those waves in measurable ways. RuView captures these disturbances using Channel State Information (CSI) from low-cost ESP32 sensors and turns them into actionable data: who's there, what they're doing, and whether they're okay.
|
||||
|
||||
[](docs/user-guide.md)
|
||||
|
||||
**What it senses:**
|
||||
- **Presence and occupancy** — detect people through walls, count them, track entries and exits
|
||||
- **Vital signs** — breathing rate and heart rate, contactless, while sleeping or sitting
|
||||
@@ -46,31 +60,75 @@ Every WiFi router already fills your space with radio waves. When people move, b
|
||||
- **Governed evidence** — attach privacy policy, uncertainty, provenance, and witness records to sensing events
|
||||
- **RuView MetaHarness** — use an AI operator to onboard, calibrate, train, verify, and check sensing claims
|
||||
|
||||
<!-- ruview-capability-cards -->
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%"><a href="docs/user-guide.md"><img src="assets/readme/feature-presence-spatial-v4.svg" width="580" alt="Presence and motion: open documentation and current limitations" /></a><br/><a href="docs/user-guide.md">Presence and motion</a></td>
|
||||
<td width="50%"><a href="v2/crates/wifi-densepose-signal/README.md"><img src="assets/readme/feature-vitals-spatial-v4.svg" width="580" alt="Breathing and vital signals: open documentation and current limitations" /></a><br/><a href="v2/crates/wifi-densepose-signal/README.md">Breathing and vital signals</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%"><a href="docs/benchmarks/pose-estimation-cog.md"><img src="assets/readme/feature-pose-spatial-v6.svg" width="580" alt="Pose research and limitations: open documentation and current limitations" /></a><br/><a href="docs/benchmarks/pose-estimation-cog.md">Pose research and limitations</a></td>
|
||||
<td width="50%"><a href="firmware/esp32-csi-node/README.md"><img src="assets/readme/feature-edge-spatial-v4.svg" width="580" alt="Edge sensor mesh: open documentation and current limitations" /></a><br/><a href="firmware/esp32-csi-node/README.md">Edge sensor mesh</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%"><a href="docs/integrations/home-assistant.md"><img src="assets/readme/feature-automation-spatial-v4.svg" width="580" alt="Local automation: open documentation and current limitations" /></a><br/><a href="docs/integrations/home-assistant.md">Local automation</a></td>
|
||||
<td width="50%"><a href="harness/ruview/README.md"><img src="assets/readme/feature-agents-spatial-v4.svg" width="580" alt="Guided AI operator: open documentation and current limitations" /></a><br/><a href="harness/ruview/README.md">Guided AI operator</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<details>
|
||||
<summary><strong>RuView MetaHarness</strong> — guided operation for humans and AI agents</summary>
|
||||
|
||||
The RuView-specific metaharness we created is published as [`@ruvnet/ruview`](harness/ruview/README.md). It provides source-cited guidance, guarded Claude Code/Codex agents, deterministic verification, and an honesty check for accuracy claims.
|
||||
The RuView-specific metaharness we created is published as [`@ruvnet/ruview`](harness/ruview/README.md). It provides:
|
||||
- source-cited guidance;
|
||||
- device access for CSI nodes, radar and LiDAR;
|
||||
- firmware flashing with boot evidence;
|
||||
- one MCP server, usable over stdio or HTTP for ChatGPT, with a live console widget;
|
||||
- a Claude Code mod;
|
||||
- guarded Claude Code/Codex agents;
|
||||
- deterministic verification;
|
||||
- an honesty check for accuracy claims.
|
||||
|
||||
Companion packages: [`homecore`](harness/homecore/README.md) (Homecore developer metaharness) and [`@ruvnet/ruview-kernel`](harness/ruview-kernel/README.md) (the vitals pipeline as WASM).
|
||||
|
||||
```bash
|
||||
# Check the local setup and get source-cited guidance
|
||||
npx @ruvnet/ruview@0.3.1 doctor
|
||||
npx @ruvnet/ruview@0.3.1 guidance --topic sensing --query "model loading"
|
||||
npx @ruvnet/ruview@0.9.1 doctor
|
||||
npx @ruvnet/ruview@0.9.1 guidance --topic sensing --query "model loading"
|
||||
|
||||
# Hardware: what is plugged in, live CSI from your nodes, a 60 GHz radar kit
|
||||
npx @ruvnet/ruview@0.9.1 devices
|
||||
npx @ruvnet/ruview@0.9.1 esp32 --watch # ESP32 + Realtek RAC1 nodes, live view
|
||||
npx @ruvnet/ruview@0.9.1 esp32 --seconds 45 --analyze # live CSI through the vitals kernel
|
||||
npx @ruvnet/ruview@0.9.1 mmwave --source esphome --host <kit-ip>
|
||||
|
||||
# Agents: MCP over stdio, or over HTTP for ChatGPT (token-protected, read tools only)
|
||||
npx @ruvnet/ruview@0.9.1 mcp start
|
||||
RUVIEW_MCP_GRANTS=device-access npx @ruvnet/ruview@0.9.1 mcp start --http
|
||||
|
||||
# Claude Code: a live sensing pane (/ruview), shipped in the package
|
||||
npx @ruvnet/ruview@0.9.1 mod
|
||||
|
||||
# Run a read-only RuView agent through Codex
|
||||
npx @ruvnet/ruview@0.3.1 agent run --host codex --repo . \
|
||||
npx @ruvnet/ruview@0.9.1 agent run --host codex --repo . \
|
||||
--prompt "Find the nearest tests and cite the source files"
|
||||
|
||||
# Search or verify the reviewed contributor brain
|
||||
npx @ruvnet/ruview@0.3.1 brain search --query "calibration"
|
||||
npx @ruvnet/ruview@0.3.1 brain verify --repo .
|
||||
|
||||
# Check claims, replay the deterministic proof, or expose the MCP server
|
||||
npx @ruvnet/ruview@0.3.1 claim-check --file REPORT.md
|
||||
npx @ruvnet/ruview@0.3.1 verify
|
||||
npx @ruvnet/ruview@0.3.1 mcp start
|
||||
# Check claims, replay the deterministic proof, search the reviewed brain
|
||||
npx @ruvnet/ruview@0.9.1 claim-check --file REPORT.md
|
||||
npx @ruvnet/ruview@0.9.1 verify
|
||||
npx @ruvnet/ruview@0.9.1 brain search --query "calibration"
|
||||
```
|
||||
|
||||
Agent runs are read-only by default. Workspace writes require both `--allow-write` and `--confirm`; retrieved brain content is evidence, not authority.
|
||||
**Safety:**
|
||||
- Agent runs are read-only by default. Workspace writes require both `--allow-write` and `--confirm`.
|
||||
- Hardware reads need the `device-access` grant.
|
||||
- Flashing and calibration never run over the HTTP transport.
|
||||
- Device-reported vitals are labelled as unvalidated.
|
||||
- Retrieved brain content is evidence, not authority.
|
||||
|
||||
A single `npx ruview` package bundling all of this is ready (ADR-376). It is waiting on npm to release the unscoped name.
|
||||
|
||||
Full walkthrough: [user guide → RuView npm toolkit](docs/user-guide.md#ruview-npm-toolkit-ruvnetruview).
|
||||
|
||||
</details>
|
||||
|
||||
@@ -108,8 +166,8 @@ RuView turns ordinary WiFi into a contactless sensor. A $9 ESP32 board reads the
|
||||
> | 🧱 **Through-wall sensing** | Fresnel-zone geometry + multipath modeling | Up to ~5 m, signal-dependent |
|
||||
> | 🧠 **Edge intelligence** | **105-cog catalog** ([ADR-102](docs/adr/ADR-102-edge-module-registry.md)) live from `app-registry.json` — health, security, building, retail, industrial, research, AI, swarm, signal, network, and developer modules. Optional Cognitum Seed adds persistent vector store + kNN + witness chain | $140 total BOM |
|
||||
> | 🎯 **Camera-free pre-training** | Self-supervised contrastive encoder, 12.2M training steps on 60K frames, shipped on Hugging Face | 84 s/epoch retrain on M4 Pro |
|
||||
> | 📷 **Camera-supervised fine-tune** | MediaPipe + ESP32 CSI paired training, end-to-end Candle pipeline on RTX 5080 ([ADR-079](docs/adr/ADR-079-camera-supervised-pose-finetune.md)) | 2.1 s for 400 epochs (~5 ms/epoch) |
|
||||
> | 📡 **Multi-frequency mesh** | Channel hopping across 6 bands, TDM slot scheduling ([ADR-029](docs/adr/ADR-029-multifrequency-mesh.md)) | 3× sensing bandwidth |
|
||||
> | 📷 **Camera-supervised fine-tune** | MediaPipe + ESP32 CSI paired training, end-to-end Candle pipeline on RTX 5080 ([ADR-079](docs/adr/ADR-079-camera-ground-truth-training.md)) | 2.1 s for 400 epochs (~5 ms/epoch) |
|
||||
> | 📡 **Multi-frequency mesh** | Channel hopping across 6 bands, TDM slot scheduling ([ADR-029](docs/adr/ADR-029-ruvsense-multistatic-sensing-mode.md)) | 3× sensing bandwidth |
|
||||
> | 🌐 **3D point cloud fusion** | Camera depth (MiDaS) + WiFi CSI + mmWave radar → unified spatial model | 22 ms pipeline · 19K+ points/frame |
|
||||
>
|
||||
> Browse the full 105-module catalog (with practical descriptions, sizes, and difficulty) below in [🧩 Edge Module Catalog](#-edge-module-catalog), or visit [seed.cognitum.one/store](https://seed.cognitum.one/store).
|
||||
@@ -122,8 +180,11 @@ RuView turns ordinary WiFi into a contactless sensor. A $9 ESP32 board reads the
|
||||
```bash
|
||||
# Option 1: Docker (simulated data, no hardware needed)
|
||||
docker pull ruvnet/wifi-densepose:latest
|
||||
docker run -p 3000:3000 ruvnet/wifi-densepose:latest
|
||||
export RUVIEW_API_TOKEN=$(openssl rand -hex 32) # required; the container exits 64 without it
|
||||
docker run -p 127.0.0.1:3000:3000 -e RUVIEW_API_TOKEN ruvnet/wifi-densepose:latest
|
||||
# Open http://localhost:3000
|
||||
# ESP32 nodes in Docker also need a UDP source guard (RUVIEW_UDP_ALLOW);
|
||||
# see docs/user-guide.md "Receiving ESP32 frames in Docker".
|
||||
|
||||
# Option 2a: Live sensing with ESP32-S3 hardware ($9)
|
||||
# Flash firmware, provision WiFi, and start sensing:
|
||||
@@ -235,6 +296,8 @@ The separate **17-keypoint pose-estimation model** is now published at [`ruvnet/
|
||||
|
||||
### Results & proof
|
||||
|
||||
[](docs/benchmarks/pose-estimation-cog.md)
|
||||
|
||||
See the measured benchmarks, witness records, and one-command reproducibility check.
|
||||
|
||||
<details>
|
||||
@@ -244,8 +307,8 @@ See the measured benchmarks, witness records, and one-command reproducibility ch
|
||||
|------|-------|---------|
|
||||
| **MM-Fi pose model (SOTA)** | [`ruvnet/wifi-densepose-mmfi-pose`](https://huggingface.co/ruvnet/wifi-densepose-mmfi-pose) | 82.69% torso-PCK@20 (single) · 83.59% (ensemble+TTA) · 75K-param micro variant 74.30% |
|
||||
| **AetherArena benchmark Space** | [`ruvnet/aether-arena`](https://huggingface.co/spaces/ruvnet/aether-arena) | self-correcting, auditable MM-Fi leaderboard |
|
||||
| **Full MM-Fi study (honest picture)** | [`docs/benchmarks/mmfi-wifi-sensing-study.md`](docs/benchmarks/mmfi-wifi-sensing-study.md) | pose + action; zero-shot cross-subject ~64%, +~30 s in-room calibration → 72.2% |
|
||||
| **Efficiency frontier** | [`docs/benchmarks/wifi-pose-efficiency-frontier.md`](docs/benchmarks/wifi-pose-efficiency-frontier.md) | SOTA-beating WiFi pose in a 20 KB int4 edge model |
|
||||
| **Full MM-Fi study (honest picture)** | [`docs/benchmarks/mmfi-wifi-sensing-study.md`](docs/benchmarks/mmfi-wifi-sensing-study.md) | pose + action; zero-shot cross-subject ~64%, labeled in-room calibration → 72.2% |
|
||||
| **Efficiency frontier** | [`docs/benchmarks/wifi-pose-efficiency-frontier.md`](docs/benchmarks/wifi-pose-efficiency-frontier.md) | SOTA-beating MM-Fi pose in a ~37 KB int4 model; live ESP32 compatibility not established |
|
||||
| **Pretrained encoder** | [`ruvnet/wifi-densepose-pretrained`](https://huggingface.co/ruvnet/wifi-densepose-pretrained) | 82.3% held-out temporal-triplet, 8 KB int4 |
|
||||
| **Reproducible proof (Trust Kill Switch)** | [`archive/v1/data/proof/verify.py`](archive/v1/data/proof/verify.py) + [`expected_features.sha256`](archive/v1/data/proof/expected_features.sha256) | one-command deterministic pipeline replay (SHA-256 of output vs published hash) |
|
||||
| **Benchmark-proof ADR** | [ADR-168](docs/adr/ADR-168-benchmark-proof.md) | how the numbers are produced and verified |
|
||||
@@ -289,6 +352,8 @@ number. The path to a first *reproducible* on-device baseline (PCK@20 ≥ 35%) i
|
||||
|
||||
## 🧩 Edge Module Catalog
|
||||
|
||||
[](firmware/esp32-csi-node/README.md)
|
||||
|
||||
Add signed modules for health, security, buildings, industry, research, AI, and more.
|
||||
|
||||
<details>
|
||||
@@ -463,6 +528,8 @@ Browse and install modules at [seed.cognitum.one/store](https://seed.cognitum.on
|
||||
|
||||
## 🔬 How It Works
|
||||
|
||||
[](docs/user-guide.md)
|
||||
|
||||
WiFi routers flood every room with radio waves. When a person moves — or even breathes — those waves scatter differently. WiFi DensePose reads that scattering pattern and reconstructs what happened:
|
||||
|
||||
```
|
||||
@@ -487,12 +554,20 @@ Neural Network: processed signals → 17 body keypoints + vital signs + room mod
|
||||
Output: real-time pose, breathing, heart rate, room fingerprint, drift alerts
|
||||
```
|
||||
|
||||
No training cameras required — the [Self-Learning system (ADR-024)](docs/adr/ADR-024-contrastive-csi-embedding-model.md) bootstraps from raw WiFi data alone. [MERIDIAN (ADR-027)](docs/adr/ADR-027-cross-environment-domain-generalization.md) ensures the model works in any room, not just the one it trained in.
|
||||
The [Self-Learning system (ADR-024)](docs/adr/ADR-024-contrastive-csi-embedding-model.md) provides
|
||||
camera-free representation-learning components. Cross-room pose remains a separate, data-gated
|
||||
problem: [MERIDIAN (ADR-027)](docs/adr/ADR-027-cross-environment-domain-generalization.md) is
|
||||
**Proposed**, while the measured calibration reference requires labeled CSI/keypoint pairs and
|
||||
model-specific adapters. See the [model compatibility boundary](docs/user-guide.md#model-and-capture-compatibility).
|
||||
|
||||
---
|
||||
|
||||
## 🏢 Use Cases & Applications
|
||||
|
||||
> **Safety boundary:** these are research and prototype applications, not medical devices,
|
||||
> emergency systems, or safety-certified controls. Vital-sign and pose outputs require independent
|
||||
> validation on the exact hardware, room, subjects, and failure conditions before operational use.
|
||||
|
||||
WiFi sensing works anywhere WiFi exists. No new hardware in most cases — just software on existing access points or a $8 ESP32 add-on. Because there are no cameras, deployments avoid privacy regulations (GDPR video, HIPAA imaging) by design.
|
||||
|
||||
**Scaling:** Each AP distinguishes ~3-5 people (56 subcarriers). Multi-AP multiplies linearly — a 4-AP retail mesh covers ~15-20 occupants. No hard software limit; the practical ceiling is signal physics.
|
||||
@@ -527,7 +602,7 @@ WiFi sensing works anywhere WiFi exists. No new hardware in most cases — just
|
||||
| Use Case | What It Does | Hardware | Key Metric | Edge Module |
|
||||
|----------|-------------|----------|------------|-------------|
|
||||
| **Smart home automation** | Room-level presence triggers (lights, HVAC, music) that work through walls — no dead zones, no motion-sensor timeouts | 2-3 ESP32-S3 nodes ($24) | Through-wall range ~5m | [HVAC Presence](docs/edge-modules/building.md), [Lighting Zones](docs/edge-modules/building.md) |
|
||||
| **Fitness & sports** | Rep counting, posture correction, breathing cadence during exercise — no wearable, no camera in locker rooms | 3+ ESP32-S3 mesh | Pose: 17 keypoints | [Breathing Sync](docs/edge-modules/exotic.md), [Gait Analysis](docs/edge-modules/medical.md) |
|
||||
| **Fitness & sports research** | Explore motion and breathing cadence without a wearable or camera; reliable posture correction requires a validated compatible pose model | 3+ ESP32-S3 mesh + edge host | Prototype; no live S3 pose accuracy claim | [Breathing Sync](docs/edge-modules/exotic.md), [Gait Analysis](docs/edge-modules/medical.md) |
|
||||
| **Childcare & schools** | Naptime breathing monitoring, playground headcount, restricted-area alerts — privacy-safe for minors | 2-4 ESP32-S3 per zone | Breathing: ±1 BPM | [Sleep Apnea](docs/edge-modules/medical.md), [Perimeter Breach](docs/edge-modules/security.md) |
|
||||
| **Event venues & concerts** | Crowd density mapping, crush-risk detection via breathing compression, emergency evacuation flow tracking | Multi-AP mesh (4-8 APs) | Density per m² | [Customer Flow](docs/edge-modules/retail.md), [Panic Motion](docs/edge-modules/security.md) |
|
||||
| **Stadiums & arenas** | Section-level occupancy for dynamic pricing, concession staffing, emergency egress flow modeling | Enterprise AP grid | 15-20 per AP mesh | [Dwell Heatmap](docs/edge-modules/retail.md), [Queue Length](docs/edge-modules/retail.md) |
|
||||
@@ -579,6 +654,8 @@ These scenarios exploit WiFi's ability to penetrate solid materials — concrete
|
||||
|
||||
## 🧠 Self-Learning WiFi AI
|
||||
|
||||
[](docs/user-guide.md)
|
||||
|
||||
Learn compact room fingerprints from raw CSI and adapt the model to each environment.
|
||||
|
||||
<details>
|
||||
@@ -694,7 +771,13 @@ claude --plugin-dir ./plugins/ruview
|
||||
|
||||
Verify the plugin structure: `bash plugins/ruview/scripts/smoke.sh`. Full details: [`plugins/ruview/README.md`](plugins/ruview/README.md).
|
||||
|
||||
For the portable RuView MetaHarness, use `npx @ruvnet/ruview@0.3.1`; the quick commands and fuller explanation are in the collapsed MetaHarness section near the top of this README and in [`harness/ruview/`](harness/ruview/README.md).
|
||||
**Live sensing pane (Claude Code mod):** the same marketplace also lists `ruview-live`, a Claude Code mod.
|
||||
- Install it with `/plugin install ruview-live@ruview`, or run `npx @ruvnet/ruview@0.9.1 mod` for its path inside the npm package.
|
||||
- `/ruview` opens a pane beside the transcript with your CSI nodes and radar, refreshed on a timer, plus a one-line status.
|
||||
- It is read-only.
|
||||
- Mods are early access; if `/ruview` is missing, start Claude Code with `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1`. See [ADR-377](docs/adr/ADR-377-ruview-live-claude-code-mod.md).
|
||||
|
||||
For the portable RuView MetaHarness, use `npx @ruvnet/ruview@0.9.1`. The quick commands and a fuller explanation are in the collapsed MetaHarness section near the top of this README, in [`harness/ruview/`](harness/ruview/README.md), and in the [user guide](docs/user-guide.md#ruview-npm-toolkit-ruvnetruview).
|
||||
|
||||
</details>
|
||||
|
||||
@@ -702,6 +785,8 @@ For the portable RuView MetaHarness, use `npx @ruvnet/ruview@0.3.1`; the quick c
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
[](docs/user-guide.md)
|
||||
|
||||
Start with the user, build, and calibration guides; expand for the full reference map.
|
||||
|
||||
<details>
|
||||
@@ -719,6 +804,8 @@ Start with the user, build, and calibration guides; expand for the full referenc
|
||||
| [Semantic Primitives — Precision/Recall](docs/integrations/semantic-primitives-metrics.md) | Per-primitive F1 on the held-out paired-capture set: someone-sleeping, possible-distress, room-active, elderly-inactivity-anomaly, meeting, bathroom, fall-risk, bed-exit, no-movement, multi-room. |
|
||||
| [Claude Code / Codex Plugin](plugins/ruview/README.md) | The `ruview` plugin + marketplace — skills, `/ruview-*` commands, agents, and the Codex prompt mirror |
|
||||
| [Portable harness — `npx @ruvnet/ruview`](harness/ruview/README.md) | MetaHarness-minted, host-portable RuView operator harness — `ruview.*` MCP tools + the MEASURED-vs-CLAIMED honesty guardrail enforced in code ([ADR-182](docs/adr/ADR-182-npx-ruview-harness-via-metaharness.md)). A lighter, multi-host companion to the in-repo plugin. |
|
||||
| [CSI Frame Selection — Measured](docs/csi-frame-selection-measured.md) | Which rate gate actually buys cross-node pairing, measured on a nine-node ESP32-C6 fleet as a 2x2 factorial in three Latin-square blocks. Selecting frames by 802.11 `rx_seq` roughly doubled pairing (+31.7 pp) while mesh-time alignment bought +0.5 pp, inside noise. Includes the trade it makes, a prediction that turned out wrong, the limits of the measurement, and `run_arms.py` so the comparison can be re-run rather than taken on trust. |
|
||||
| [ESP32-C6 Firmware Runbook](firmware/esp32-csi-node/RUNBOOK.md) | What to run, in what order, and what to check: the three-file build that keeps OTA rollback compiled in, a five-key pre-flash gate, which flash regions OTA can and cannot reach, a single-board diagnostic flash with a revert path, and the tunables whose right value depends on your house rather than on the chip. |
|
||||
| [Architecture Decisions](docs/adr/README.md) | 205 ADRs — why each technical choice was made, organized by domain (hardware, signal processing, ML, platform, infrastructure) |
|
||||
| [Domain Models](docs/ddd/README.md) | 8 DDD models (RuvSense, Signal Processing, Training Pipeline, Hardware Platform, Sensing Server, WiFi-Mat, CHCI, rvCSI) — bounded contexts, aggregates, domain events, and ubiquitous language |
|
||||
| [rvCSI — edge RF sensing runtime](https://github.com/ruvnet/rvcsi) | Rust-first / TypeScript-accessible / hardware-abstracted CSI runtime: multi-source ingestion (incl. real nexmon_csi `.pcap` from a **Raspberry Pi 5** / Pi 4 / Pi 3B+ — CYW43455 / BCM43455c0) → validation → DSP → typed events → RuVector RF memory ([ADR-095](docs/adr/ADR-095-rvcsi-edge-rf-sensing-platform.md), [ADR-096](docs/adr/ADR-096-rvcsi-ffi-crate-layout.md), [domain model](docs/ddd/rvcsi-domain-model.md)). Now its own repo — [`ruvnet/rvcsi`](https://github.com/ruvnet/rvcsi) — vendored here under `vendor/rvcsi`; 9 `rvcsi-*` crates on crates.io, `@ruv/rvcsi` on npm, plus a Claude Code plugin. |
|
||||
@@ -741,6 +828,8 @@ Start with the user, build, and calibration guides; expand for the full referenc
|
||||
>
|
||||
> Contributions and bug reports welcome at [Issues](https://github.com/ruvnet/RuView/issues).
|
||||
|
||||
[](https://cognitum.one)
|
||||
|
||||
## 📄 License
|
||||
|
||||
MIT License — see [LICENSE](LICENSE) for details.
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
# RuView Calibration Service (reference implementation)
|
||||
|
||||
Turn a **shared WiFi-CSI pose base model** into a room-specific one with a **30-second labeled
|
||||
calibration** and a **~11 KB per-room LoRA adapter**. This is the deployable resolution of the
|
||||
cross-subject / cross-environment generalization problem (full study: [ADR-150 §3.3–3.6](../../docs/adr/ADR-150-rf-foundation-encoder.md)).
|
||||
Fit a room-specific **~11 KB LoRA adapter** for a shared WiFi-CSI pose base from a short **labeled
|
||||
capture**. This is a measured MM-Fi reference path for cross-subject / cross-environment adaptation
|
||||
(full study: [ADR-150 §3.3–3.6](../../docs/adr/ADR-150-rf-foundation-encoder.md)); it is not proof of
|
||||
plug-and-play adaptation from a live ESP32 stream.
|
||||
|
||||
> **Not the proposed MERIDIAN fast path.** Both producers below require paired CSI and keypoint
|
||||
> labels, and their tensor shapes and adapter files are model-specific. ADR-027's automatic,
|
||||
> unlabeled 10-second MERIDIAN calibration remains **Proposed** and is not implemented as an
|
||||
> end-to-end deployment command.
|
||||
|
||||
## Why
|
||||
|
||||
@@ -66,8 +72,8 @@ Adapters are **model-specific**. There are two calibration producers here:
|
||||
| `cog_calibrate.py` | cog **conv+MLP** (`pose_v1.safetensors`, 56×20) | `[N,56,20]` | `.safetensors` (`fc1.a`/`fc1.b`/`fc2.a`/`fc2.b`) | Rust `cog-pose-estimation run --adapter` |
|
||||
|
||||
```bash
|
||||
# Produce a cog-format per-room adapter for the deployed Rust pose engine:
|
||||
python cog_calibrate.py --base pose_v1.safetensors --data calib.npz --out room.safetensors
|
||||
# Produce a cog-format per-room adapter from X:[N,56,20], Y:[N,17,2]:
|
||||
python cog_calibrate.py --base pose_v1.safetensors --data cog-calib.npz --out room.safetensors
|
||||
# then in the cog runtime:
|
||||
cog-pose-estimation run --config <cfg> --adapter room.safetensors
|
||||
```
|
||||
|
||||
@@ -10,6 +10,39 @@ func main() {
|
||||
exit(1)
|
||||
}
|
||||
|
||||
// One connected-link RSSI sample for the Rust adapter. Keep the legacy
|
||||
// no-argument 10 Hz stream below unchanged for Python callers.
|
||||
if CommandLine.arguments.contains("--scan-once") {
|
||||
guard interface.powerOn(),
|
||||
let channel = interface.wlanChannel(),
|
||||
interface.rssiValue() < 0 else {
|
||||
fputs("WiFi is not connected\n", stderr)
|
||||
exit(1)
|
||||
}
|
||||
let sample: [String: Any] = [
|
||||
// Always the connected link. macOS redacts ssid/bssid without
|
||||
// Location Services; rssi/noise/channel stay real, so mark the
|
||||
// sample as the connected link for the Rust adapter.
|
||||
"connected": true,
|
||||
"ssid": interface.ssid() ?? "",
|
||||
"bssid": interface.bssid() ?? "00:00:00:00:00:00",
|
||||
"channel": channel.channelNumber,
|
||||
"rssi": interface.rssiValue(),
|
||||
"noise": interface.noiseMeasurement(),
|
||||
"timestamp": Date().timeIntervalSince1970,
|
||||
"tx_rate": interface.transmitRate()
|
||||
]
|
||||
do {
|
||||
let data = try JSONSerialization.data(withJSONObject: sample, options: [.sortedKeys])
|
||||
FileHandle.standardOutput.write(data)
|
||||
FileHandle.standardOutput.write(Data([0x0a]))
|
||||
} catch {
|
||||
fputs("Could not encode WiFi sample: \(error)\n", stderr)
|
||||
exit(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Flush stdout automatically to prevent buffering issues with Python subprocess
|
||||
setbuf(stdout, nil)
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"endpoint": "fal-ai/flux-lora",
|
||||
"lora_url": "https://v3b.fal.media/files/b/0aa8c60d/OjaBs6Gi8pMhZqMo79iym_pytorch_lora_weights.safetensors",
|
||||
"prompt": "ruviewstyle room visualization, a living room with a glowing cyan pose skeleton overlay, wifi signal arcs radiating across the space, a vitals readout panel, dark tech aesthetic, synthetic sensor visualization",
|
||||
"scale": 1.0,
|
||||
"source_image_url": "https://v3b.fal.media/files/b/0aa8cf67/JH1qyC3GCKQ9ojkrAUXe9.png"
|
||||
}
|
||||
|
After Width: | Height: | Size: 585 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="304" viewBox="0 0 1200 304" role="img" aria-labelledby="title desc"><title id="title">Explore Cognitum One</title><desc id="desc">Ambient Intelligence at the edge of the physical world. Open cognitum.one.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="303" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="44" y="42" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">COGNITUM ONE</text><text x="44" y="99" font-size="42" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Ambient Intelligence.</text><text x="44" y="147" font-size="25" fill="#78cfff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >At the edge of the physical world.</text><text x="44" y="190" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Explore the platform behind the ecosystem.</text><rect x="44" y="224" width="256" height="46" rx="11" fill="url(#accent)"/><text x="65" y="254" font-size="18" fill="#071124" text-anchor="start" font-weight="500" >Explore Cognitum</text><path d="M263 247H284M277 240L284 247L277 254" fill="none" stroke="#071124" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="947" cy="151" r="173" fill="url(#halo)"/><g transform="translate(945 173) scale(1.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><g transform="translate(945 145) scale(1.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M0 -38L31 -20V18L0 38L-31 18V-20ZM-31 -20L0 -1L31 -20M0 -1V38" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M-15 1L-5 11L17 -12" fill="none" stroke="#438fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="trace"/></g></g><ellipse cx="945" cy="150" rx="140" ry="30" transform="rotate(-25 945 150)" fill="none" stroke="#437cb2" stroke-dasharray="5 18" class="flow"/><ellipse cx="945" cy="150" rx="160" ry="43" transform="rotate(-25 945 150)" fill="none" stroke="#437cb2" stroke-dasharray="5 18" class="flow"/><ellipse cx="945" cy="150" rx="180" ry="56" transform="rotate(-25 945 150)" fill="none" stroke="#437cb2" stroke-dasharray="5 18" class="flow"/></svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="304" viewBox="0 0 1200 304" role="img" aria-labelledby="title desc"><title id="title">Explore Cognitum One</title><desc id="desc">Ambient Intelligence at the edge of the physical world. Open cognitum.one.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{stroke-dasharray:3 14;animation:flow 8s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
.layer{animation:layer 6s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
@keyframes layer{50%{transform:translateY(-5px)}}
|
||||
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="303" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="44" y="42" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">COGNITUM ONE</text><text x="44" y="99" font-size="42" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Ambient Intelligence.</text><text x="44" y="147" font-size="25" fill="#78cfff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >At the edge of the physical world.</text><text x="44" y="190" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Explore the platform behind the ecosystem.</text><rect x="44" y="224" width="256" height="46" rx="11" fill="url(#accent)"/><text x="65" y="254" font-size="18" fill="#071124" text-anchor="start" font-weight="500" >Explore Cognitum</text><path d="M263 247H284M277 240L284 247L277 254" fill="none" stroke="#071124" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="947" cy="151" r="173" fill="url(#halo)"/><g transform="translate(945 173) scale(1.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><g transform="translate(945 145) scale(1.65)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><g class="layer" style="animation-delay:-0.0s"><path d="M-38 -23L0 -42L38 -23L0 -4Z" fill="#102749" stroke="#78cfff"/><path d="M-38 -23V-16L0 3L38 -16V-23M0 -4V3" fill="#09172c" stroke="#315685"/></g><g class="layer" style="animation-delay:-0.7s"><path d="M-38 -10L0 -29L38 -10L0 9Z" fill="#102749" stroke="#438fff"/><path d="M-38 -10V-3L0 16L38 -3V-10M0 9V16" fill="#09172c" stroke="#315685"/></g><g class="layer" style="animation-delay:-1.4s"><path d="M-38 3L0 -16L38 3L0 22Z" fill="#102749" stroke="#438fff"/><path d="M-38 3V10L0 29L38 10V3M0 22V29" fill="#09172c" stroke="#315685"/></g><path d="M-12 -31L0 -37L12 -31L0 -25Z" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M-26 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M0 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M26 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/></g></g><ellipse cx="945" cy="150" rx="140" ry="30" transform="rotate(-25 945 150)" fill="none" stroke="#437cb2" stroke-dasharray="5 18" class="flow"/><ellipse cx="945" cy="150" rx="160" ry="43" transform="rotate(-25 945 150)" fill="none" stroke="#437cb2" stroke-dasharray="5 18" class="flow"/><ellipse cx="945" cy="150" rx="180" ry="56" transform="rotate(-25 945 150)" fill="none" stroke="#437cb2" stroke-dasharray="5 18" class="flow"/><path d="M24 1H1176" stroke="url(#accent)" opacity=".55"/><path d="M24 303H1176" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="304" viewBox="0 0 1200 304" role="img" aria-labelledby="title desc"><title id="title">Explore Cognitum One</title><desc id="desc">Ambient Intelligence at the edge of the physical world. Open cognitum.one.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="303" rx="18" fill="url(#wash)" stroke="#245360"/><text x="44" y="42" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">COGNITUM ONE</text><text x="44" y="99" font-size="42" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Ambient Intelligence.</text><text x="44" y="147" font-size="25" fill="#72eee0" text-anchor="start" font-weight="650" letter-spacing="-0.6" >At the edge of the physical world.</text><text x="44" y="190" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >Explore the platform behind the ecosystem.</text><rect x="44" y="224" width="256" height="46" rx="11" fill="url(#accent)"/><text x="65" y="254" font-size="18" fill="#041117" text-anchor="start" font-weight="500" >Explore Cognitum</text><path d="M263 247H284M277 240L284 247L277 254" fill="none" stroke="#041117" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="947" cy="151" r="173" fill="url(#halo)"/><g transform="translate(945 173) scale(1.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><g transform="translate(945 145) scale(1.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M0 -38L31 -20V18L0 38L-31 18V-20ZM-31 -20L0 -1L31 -20M0 -1V38" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M-15 1L-5 11L17 -12" fill="none" stroke="#70b6ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="trace"/></g></g><ellipse cx="945" cy="150" rx="140" ry="30" transform="rotate(-25 945 150)" fill="none" stroke="#3c8897" stroke-dasharray="5 18" class="flow"/><ellipse cx="945" cy="150" rx="160" ry="43" transform="rotate(-25 945 150)" fill="none" stroke="#3c8897" stroke-dasharray="5 18" class="flow"/><ellipse cx="945" cy="150" rx="180" ry="56" transform="rotate(-25 945 150)" fill="none" stroke="#3c8897" stroke-dasharray="5 18" class="flow"/></svg>
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">A guided AI operator</title><desc id="desc">Source-cited setup and verification. CLI, MCP and agent workflows. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 06</text><text x="30" y="94" font-size="29" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >A guided AI operator</text><text x="30" y="136" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Source-cited setup and verification.</text><text x="30" y="164" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >CLI, MCP and agent workflows.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 161) scale(0.53)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><g transform="translate(474 155) scale(0.68)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M0 0L0 -33" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="0" cy="-33" r="7" stroke="#78cfff" fill="none" class="breathe"/><path d="M0 0L-35 23" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="-35" cy="23" r="7" stroke="#78cfff" fill="none" class="breathe"/><path d="M0 0L35 23" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="35" cy="23" r="7" stroke="#78cfff" fill="none" class="breathe"/><circle cx="0" cy="0" r="15" stroke="#78cfff" fill="none" /><path d="M-6 0L-1 5L8 -6" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">TOOLKIT GUIDE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 5.2 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">A guided AI operator</title><desc id="desc">Source-cited setup and verification. CLI, MCP and agent workflows. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 06</text><text x="30" y="89" font-size="25" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >A guided AI operator</text><text x="30" y="126" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Source-cited setup and verification.</text><text x="30" y="151" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >CLI, MCP and agent workflows.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 144) scale(1.12)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><path d="M0 0L0 -36" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M0 -43l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><path d="M0 0L-38 -10" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M-38 -17l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><path d="M0 0L-23 31" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M-23 24l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><path d="M0 0L30 28" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M30 21l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><path d="M0 0L39 -17" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M39 -24l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><circle cx="0" cy="0" r="15" stroke="#b8f36c" fill="none" /><path d="M-6 0L-1 5L8 -6" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">TOOLKIT GUIDE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H556" stroke="url(#accent)" opacity=".55"/><path d="M24 275H556" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">A guided AI operator</title><desc id="desc">Source-cited setup and verification. CLI, MCP and agent workflows. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#245360"/><text x="30" y="39" font-size="11" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">RUVIEW / 06</text><text x="30" y="94" font-size="29" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >A guided AI operator</text><text x="30" y="136" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >Source-cited setup and verification.</text><text x="30" y="164" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >CLI, MCP and agent workflows.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 161) scale(0.53)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><g transform="translate(474 155) scale(0.68)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M0 0L0 -33" fill="none" stroke="#70b6ff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="0" cy="-33" r="7" stroke="#72eee0" fill="none" class="breathe"/><path d="M0 0L-35 23" fill="none" stroke="#70b6ff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="-35" cy="23" r="7" stroke="#72eee0" fill="none" class="breathe"/><path d="M0 0L35 23" fill="none" stroke="#70b6ff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="35" cy="23" r="7" stroke="#72eee0" fill="none" class="breathe"/><circle cx="0" cy="0" r="15" stroke="#72eee0" fill="none" /><path d="M-6 0L-1 5L8 -6" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></g></g><path d="M30 204H550" fill="none" stroke="#245360" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#72eee0" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">TOOLKIT GUIDE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Local automation</title><desc id="desc">Connect rooms to your smart home. Home Assistant, MQTT and Matter. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 05</text><text x="30" y="94" font-size="29" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Local automation</text><text x="30" y="136" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Connect rooms to your smart home.</text><text x="30" y="164" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Home Assistant, MQTT and Matter.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 161) scale(0.53)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><g transform="translate(474 155) scale(0.68)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-37 -3L0 -34L37 -3M-28 -10V32H28V-10M-9 32V8H9V32" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="-9" r="5" stroke="#438fff" fill="none" class="breathe"/></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">INTEGRATION GUIDE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Local automation</title><desc id="desc">Connect rooms to your smart home. Home Assistant, MQTT and Matter. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 05</text><text x="30" y="89" font-size="25" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Local automation</text><text x="30" y="126" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Connect rooms to your smart home.</text><text x="30" y="151" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Home Assistant, MQTT and Matter.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 144) scale(1.12)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><path d="M-43 12L0 -10L43 12L0 35Z" fill="#102749" stroke="#438fff"/><path d="M-32 17V-16L0 -35L32 -16V17M-32 -16L0 3L32 -16M0 3V34" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M-22 20L-10 13L12 25M-10 13V-5" fill="none" stroke="#b8f36c" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="-22" cy="20" r="4" stroke="#ffb45e" fill="#102749" class="breathe"/><circle cx="-10" cy="-5" r="4" stroke="#ffb45e" fill="#102749" class="breathe"/><circle cx="12" cy="25" r="4" stroke="#ffb45e" fill="#102749" class="breathe"/></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">INTEGRATION GUIDE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H556" stroke="url(#accent)" opacity=".55"/><path d="M24 275H556" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Local automation</title><desc id="desc">Connect rooms to your smart home. Home Assistant, MQTT and Matter. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#245360"/><text x="30" y="39" font-size="11" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">RUVIEW / 05</text><text x="30" y="94" font-size="29" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Local automation</text><text x="30" y="136" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >Connect rooms to your smart home.</text><text x="30" y="164" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >Home Assistant, MQTT and Matter.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 161) scale(0.53)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><g transform="translate(474 155) scale(0.68)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-37 -3L0 -34L37 -3M-28 -10V32H28V-10M-9 32V8H9V32" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="-9" r="5" stroke="#70b6ff" fill="none" class="breathe"/></g></g><path d="M30 204H550" fill="none" stroke="#245360" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#72eee0" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">INTEGRATION GUIDE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Edge sensor mesh</title><desc id="desc">Provision, capture and calibrate. Explore ESP32 firmware and runbooks. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 04</text><text x="30" y="94" font-size="29" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Edge sensor mesh</text><text x="30" y="136" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Provision, capture and calibrate.</text><text x="30" y="164" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Explore ESP32 firmware and runbooks.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 161) scale(0.53)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><g transform="translate(474 155) scale(0.68)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><rect x="-25" y="-25" width="50" height="50" rx="7" fill="#0c2242" stroke="#78cfff"/><rect x="-13" y="-13" width="26" height="26" rx="3" fill="none" stroke="#438fff"/><path d="M-16 -36V-25M-16 25V36M-36 -16H-25M25 -16H36" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M0 -36V-25M0 25V36M-36 0H-25M25 0H36" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M16 -36V-25M16 25V36M-36 16H-25M25 16H36" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="0" r="4" stroke="#78cfff" fill="#78cfff" class="breathe"/></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">HARDWARE GUIDE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Edge sensor mesh</title><desc id="desc">Provision, capture and calibrate. Explore ESP32 firmware and runbooks. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.layer{animation:layer 6s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
@keyframes layer{50%{transform:translateY(-5px)}}
|
||||
|
||||
|
||||
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 04</text><text x="30" y="89" font-size="25" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Edge sensor mesh</text><text x="30" y="126" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Provision, capture and calibrate.</text><text x="30" y="151" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Explore ESP32 firmware and runbooks.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 144) scale(1.12)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><g class="layer" style="animation-delay:-0.0s"><path d="M-38 -23L0 -42L38 -23L0 -4Z" fill="#102749" stroke="#78cfff"/><path d="M-38 -23V-16L0 3L38 -16V-23M0 -4V3" fill="#09172c" stroke="#315685"/></g><g class="layer" style="animation-delay:-0.7s"><path d="M-38 -10L0 -29L38 -10L0 9Z" fill="#102749" stroke="#438fff"/><path d="M-38 -10V-3L0 16L38 -3V-10M0 9V16" fill="#09172c" stroke="#315685"/></g><g class="layer" style="animation-delay:-1.4s"><path d="M-38 3L0 -16L38 3L0 22Z" fill="#102749" stroke="#438fff"/><path d="M-38 3V10L0 29L38 10V3M0 22V29" fill="#09172c" stroke="#315685"/></g><path d="M-12 -31L0 -37L12 -31L0 -25Z" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M-26 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M0 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M26 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">HARDWARE GUIDE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H556" stroke="url(#accent)" opacity=".55"/><path d="M24 275H556" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Edge sensor mesh</title><desc id="desc">Provision, capture and calibrate. Explore ESP32 firmware and runbooks. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#245360"/><text x="30" y="39" font-size="11" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">RUVIEW / 04</text><text x="30" y="94" font-size="29" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Edge sensor mesh</text><text x="30" y="136" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >Provision, capture and calibrate.</text><text x="30" y="164" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >Explore ESP32 firmware and runbooks.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 161) scale(0.53)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><g transform="translate(474 155) scale(0.68)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><rect x="-25" y="-25" width="50" height="50" rx="7" fill="#0a2630" stroke="#72eee0"/><rect x="-13" y="-13" width="26" height="26" rx="3" fill="none" stroke="#70b6ff"/><path d="M-16 -36V-25M-16 25V36M-36 -16H-25M25 -16H36" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M0 -36V-25M0 25V36M-36 0H-25M25 0H36" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M16 -36V-25M16 25V36M-36 16H-25M25 16H36" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="0" r="4" stroke="#72eee0" fill="#72eee0" class="breathe"/></g></g><path d="M30 204H550" fill="none" stroke="#245360" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#72eee0" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">HARDWARE GUIDE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Pose research</title><desc id="desc">Train and compare body keypoints. Live accuracy differs from benchmarks. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 03</text><text x="30" y="94" font-size="29" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Pose research</text><text x="30" y="136" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Train and compare body keypoints.</text><text x="30" y="164" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Live accuracy differs from benchmarks.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 161) scale(0.53)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><g transform="translate(474 155) scale(0.68)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><circle cx="0" cy="-28" r="8" stroke="#b8f36c" fill="none" /><path d="M0 -20V12M-24 -6L0 -14L24 -6M0 12L-18 38M0 12L18 38" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="-14" r="2.3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="0" cy="12" r="2.3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="-24" cy="-6" r="2.3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="24" cy="-6" r="2.3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="-18" cy="38" r="3" stroke="#ffb45e" fill="#071124" class="breathe"/><circle cx="18" cy="38" r="3" stroke="#ffb45e" fill="#071124" class="breathe"/></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">READ THE EVIDENCE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Pose research</title><desc id="desc">Train and compare body keypoints. Live accuracy differs from benchmarks. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
|
||||
.limb{animation:limb 3s ease-in-out infinite;transform-origin:0 -18px}
|
||||
.stride{animation:limb 3s ease-in-out infinite reverse;transform-origin:5px 16px}
|
||||
|
||||
|
||||
|
||||
@keyframes limb{0%,100%{transform:rotate(-9deg)}50%{transform:rotate(9deg)}}
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 03</text><text x="30" y="89" font-size="25" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Pose research</text><text x="30" y="126" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Train and compare body keypoints.</text><text x="30" y="151" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Live accuracy differs from benchmarks.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 144) scale(1.12)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><circle cx="0" cy="-32" r="7" stroke="#b8f36c" fill="none" /><path d="M0 -25L-3 -2L5 16" fill="none" stroke="#b8f36c" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" /><g class="limb"><path d="M-1 -18L-19 -5L-31 -14M-1 -18L18 -11L28 -25" fill="none" stroke="#b8f36c" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" /></g><g class="stride"><path d="M5 16L-12 28L-22 47M5 16L24 28L33 44" fill="none" stroke="#b8f36c" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" /></g><circle cx="-1" cy="-18" r="2.8" stroke="#ffb45e" fill="#ffb45e"/><circle cx="-3" cy="-2" r="2.8" stroke="#ffb45e" fill="#ffb45e"/><circle cx="5" cy="16" r="2.8" stroke="#ffb45e" fill="#ffb45e"/><circle cx="-19" cy="-5" r="2.8" stroke="#ffb45e" fill="#ffb45e"/><circle cx="18" cy="-11" r="2.8" stroke="#ffb45e" fill="#ffb45e"/><path d="M-42 -42V-50H-30M30 -50H42V-42M42 45V53H30M-30 53H-42V45" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">READ THE EVIDENCE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H556" stroke="url(#accent)" opacity=".55"/><path d="M24 275H556" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Pose research</title><desc id="desc">Train and compare body keypoints. Live accuracy differs from benchmarks. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
|
||||
.limb{animation:limb 3s ease-in-out infinite;transform-origin:0 -18px}
|
||||
.stride{animation:limb 3s ease-in-out infinite reverse;transform-origin:5px 16px}
|
||||
|
||||
|
||||
|
||||
@keyframes limb{0%,100%{transform:rotate(-3deg)}50%{transform:rotate(3deg)}}
|
||||
|
||||
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 03</text><text x="30" y="89" font-size="25" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Pose research</text><text x="30" y="126" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Train and compare body keypoints.</text><text x="30" y="151" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Live accuracy differs from benchmarks.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 144) scale(1.12)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><defs><linearGradient id="humanSurface" x1="0" y1="0" x2="1" y2=".3"><stop stop-color="#153d48"/><stop offset=".42" stop-color="#338469"/><stop offset=".7" stop-color="#83c766"/><stop offset="1" stop-color="#163c4a"/></linearGradient><linearGradient id="humanRear"><stop stop-color="#0f2d40"/><stop offset="1" stop-color="#397a68"/></linearGradient></defs><g stroke="#88d783" stroke-width=".65" stroke-linejoin="round"><g class="limb"><path d="M-9 -25C-15 -25 -18 -19 -21 -13L-29 -5C-32 -3 -33 1 -30 3L-25 2L-14 -7C-9 -12 -6 -19 -6 -23Z" fill="url(#humanRear)"/></g><g class="stride"><path d="M-6 5C-13 10 -15 18 -17 26L-25 43L-29 47C-30 49 -28 51 -24 51L-17 50L-16 46L-8 30C-4 23 2 15 3 10Z" fill="url(#humanRear)"/><path d="M3 5C10 7 14 17 19 23C24 28 23 35 24 41L29 45C32 47 32 49 28 50L20 49C17 48 17 46 17 42L14 32C8 28 2 23 -3 16L-4 10Z" fill="url(#humanSurface)"/></g><g class="limb"><path d="M7 -26C14 -25 17 -20 20 -13L24 -17L29 -24C30 -27 33 -29 35 -26L35 -22L30 -16L24 -8C22 -5 18 -5 16 -8L8 -17Z" fill="url(#humanSurface)"/></g><path d="M-4 -32L4 -33L6 -28C11 -27 14 -24 13 -19L9 -5L10 7C10 13 2 15 -5 12L-10 7L-8 -5L-12 -20C-13 -25 -8 -28 -5 -28Z" fill="url(#humanSurface)"/><path d="M-6 -42C-6 -48 2 -51 7 -47C10 -45 10 -41 9 -39L11 -36L8 -35L7 -31L3 -29L-3 -32L-5 -37Z" fill="url(#humanSurface)"/></g><path d="M-9 -23Q-2 -18 10 -23M-7 -15Q0 -11 9 -16M-6 -8Q1 -5 8 -9M-7 1Q1 5 9 1M0 -26L2 9M-4 -40Q0 -42 7 -40M2 -32L6 -34" fill="none" stroke="#b8f36c" stroke-width="0.55" stroke-linecap="round" stroke-linejoin="round" opacity=".65"/><path d="M-5 -45Q1 -49 6 -46M-10 -22L-6 -8M9 17L17 28M-12 20L-20 42" fill="none" stroke="#78cfff" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round" opacity=".8"/><circle cx="-9" cy="-24" r="3.5" stroke="#ffb45e" fill="none" stroke-opacity=".25"/><circle cx="-9" cy="-24" r="1.5" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="10" cy="-23" r="3.5" stroke="#ffb45e" fill="none" stroke-opacity=".25"/><circle cx="10" cy="-23" r="1.5" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="1" cy="-12" r="3.5" stroke="#ffb45e" fill="none" stroke-opacity=".25"/><circle cx="1" cy="-12" r="1.5" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="2" cy="9" r="3.5" stroke="#ffb45e" fill="none" stroke-opacity=".25"/><circle cx="2" cy="9" r="1.5" stroke="#ffb45e" fill="#ffb45e" class="spark"/><path d="M-42 -42V-53H-30M30 -53H42V-42M42 45V55H30M-30 55H-42V45" fill="none" stroke="#438fff" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">READ THE EVIDENCE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H556" stroke="url(#accent)" opacity=".55"/><path d="M24 275H556" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
@@ -0,0 +1,47 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Pose research</title><desc id="desc">Train and compare body keypoints. Live accuracy differs from benchmarks. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.humanTurn{transform-box:fill-box;transform-origin:center 85%;animation:humanTurn 8s ease-in-out infinite}
|
||||
.humanBody{animation:humanBody 1.6s ease-in-out infinite}
|
||||
.armFar{transform-origin:-9px -24px;animation:armSwing 1.6s ease-in-out infinite}
|
||||
.armNear{transform-origin:10px -23px;animation:armSwing 1.6s ease-in-out infinite;animation-delay:-.8s}
|
||||
.legFar{transform-origin:-3px 9px;animation:legSwing 1.6s ease-in-out infinite;animation-delay:-.8s}
|
||||
.legNear{transform-origin:2px 9px;animation:legSwing 1.6s ease-in-out infinite}
|
||||
.humanLight{animation:humanLight 8s ease-in-out infinite}
|
||||
.gaitShadow{transform-box:fill-box;transform-origin:center;animation:gaitShadow 1.6s ease-in-out infinite}
|
||||
@keyframes humanTurn{0%,100%{transform:perspective(450px) rotateY(-24deg) rotateZ(-2deg)}50%{transform:perspective(450px) rotateY(24deg) rotateZ(2deg)}}
|
||||
@keyframes humanBody{0%,50%,100%{transform:translateY(0)}25%,75%{transform:translateY(-2px)}}
|
||||
@keyframes armSwing{0%,100%{transform:rotate(-17deg)}50%{transform:rotate(17deg)}}
|
||||
@keyframes legSwing{0%,100%{transform:rotate(-12deg)}50%{transform:rotate(12deg)}}
|
||||
@keyframes humanLight{0%,100%{opacity:.1}50%{opacity:.45}}
|
||||
@keyframes gaitShadow{0%,50%,100%{transform:scaleX(1);opacity:.7}25%,75%{transform:scaleX(.85);opacity:.45}}
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 03</text><text x="30" y="89" font-size="25" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Pose research</text><text x="30" y="126" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Train and compare body keypoints.</text><text x="30" y="151" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Live accuracy differs from benchmarks.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 144) scale(1.12)"><ellipse cy="53" rx="37" ry="7" fill="#020816" class="gaitShadow"/><g class="humanBody"><defs><linearGradient id="humanSurface" x1="0" y1="0" x2="1" y2=".3"><stop stop-color="#153d48"/><stop offset=".42" stop-color="#338469"/><stop offset=".7" stop-color="#83c766"/><stop offset="1" stop-color="#163c4a"/></linearGradient><linearGradient id="humanRear"><stop stop-color="#0f2d40"/><stop offset="1" stop-color="#397a68"/></linearGradient></defs><g class="humanTurn"><g stroke="#88d783" stroke-width=".65" stroke-linejoin="round"><g class="armFar"><path d="M-9 -25C-15 -25 -18 -19 -21 -13L-29 -5C-32 -3 -33 1 -30 3L-25 2L-14 -7C-9 -12 -6 -19 -6 -23Z" fill="url(#humanRear)"/></g><g class="legFar"><path d="M-6 5C-13 10 -15 18 -17 26L-25 43L-29 47C-30 49 -28 51 -24 51L-17 50L-16 46L-8 30C-4 23 2 15 3 10Z" fill="url(#humanRear)"/><circle cx="-15" cy="26" r="1.8" fill="#ffb45e"/></g><g class="legNear"><path d="M3 5C10 7 14 17 19 23C24 28 23 35 24 41L29 45C32 47 32 49 28 50L20 49C17 48 17 46 17 42L14 32C8 28 2 23 -3 16L-4 10Z" fill="url(#humanSurface)"/><circle cx="19" cy="28" r="1.8" fill="#ffb45e"/></g><g class="armNear"><path d="M7 -26C14 -25 17 -20 20 -13L24 -17L29 -24C30 -27 33 -29 35 -26L35 -22L30 -16L24 -8C22 -5 18 -5 16 -8L8 -17Z" fill="url(#humanSurface)"/></g><path d="M-4 -32L4 -33L6 -28C11 -27 14 -24 13 -19L9 -5L10 7C10 13 2 15 -5 12L-10 7L-8 -5L-12 -20C-13 -25 -8 -28 -5 -28Z" fill="url(#humanSurface)"/><path d="M-6 -42C-6 -48 2 -51 7 -47C10 -45 10 -41 9 -39L11 -36L8 -35L7 -31L3 -29L-3 -32L-5 -37Z" fill="url(#humanSurface)"/></g><path d="M-9 -23Q-2 -18 10 -23M-7 -15Q0 -11 9 -16M-6 -8Q1 -5 8 -9M-7 1Q1 5 9 1M0 -26L2 9M-4 -40Q0 -42 7 -40M2 -32L6 -34" fill="none" stroke="#b8f36c" stroke-width="0.55" stroke-linecap="round" stroke-linejoin="round" opacity=".65"/><path d="M-5 -45Q1 -49 6 -46M-10 -22L-6 -8" fill="none" stroke="#78cfff" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round" opacity=".8"/><path d="M-8 -25Q-2 -21 1 -10L3 9Q-5 8 -6 3L-5 -8Z" fill="#a7ebff" class="humanLight" opacity=".2"/><circle cx="-9" cy="-24" r="3.5" stroke="#ffb45e" fill="none" stroke-opacity=".25"/><circle cx="-9" cy="-24" r="1.5" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="10" cy="-23" r="3.5" stroke="#ffb45e" fill="none" stroke-opacity=".25"/><circle cx="10" cy="-23" r="1.5" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="1" cy="-12" r="3.5" stroke="#ffb45e" fill="none" stroke-opacity=".25"/><circle cx="1" cy="-12" r="1.5" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="2" cy="9" r="3.5" stroke="#ffb45e" fill="none" stroke-opacity=".25"/><circle cx="2" cy="9" r="1.5" stroke="#ffb45e" fill="#ffb45e" class="spark"/></g><path d="M-42 -42V-53H-30M30 -53H42V-42M42 45V55H30M-30 55H-42V45" fill="none" stroke="#438fff" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">READ THE EVIDENCE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H556" stroke="url(#accent)" opacity=".55"/><path d="M24 275H556" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 6.6 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Pose research</title><desc id="desc">Train and compare body keypoints. Live accuracy differs from benchmarks. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#245360"/><text x="30" y="39" font-size="11" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">RUVIEW / 03</text><text x="30" y="94" font-size="29" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Pose research</text><text x="30" y="136" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >Train and compare body keypoints.</text><text x="30" y="164" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >Live accuracy differs from benchmarks.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 161) scale(0.53)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><g transform="translate(474 155) scale(0.68)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><circle cx="0" cy="-28" r="8" stroke="#72eee0" fill="none" /><path d="M0 -20V12M-24 -6L0 -14L24 -6M0 12L-18 38M0 12L18 38" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="-14" r="3" stroke="#70b6ff" fill="#041117" class="breathe"/><circle cx="0" cy="12" r="3" stroke="#70b6ff" fill="#041117" class="breathe"/><circle cx="-24" cy="-6" r="3" stroke="#70b6ff" fill="#041117" class="breathe"/><circle cx="24" cy="-6" r="3" stroke="#70b6ff" fill="#041117" class="breathe"/><circle cx="-18" cy="38" r="3" stroke="#70b6ff" fill="#041117" class="breathe"/><circle cx="18" cy="38" r="3" stroke="#70b6ff" fill="#041117" class="breathe"/></g></g><path d="M30 204H550" fill="none" stroke="#245360" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#72eee0" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">READ THE EVIDENCE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Presence & motion</title><desc id="desc">Explore changes in room occupancy. Inspect motion features from CSI. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 01</text><text x="30" y="94" font-size="29" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Presence & motion</text><text x="30" y="136" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Explore changes in room occupancy.</text><text x="30" y="164" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Inspect motion features from CSI.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 161) scale(0.53)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><g transform="translate(474 155) scale(0.68)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><circle cx="0" cy="-28" r="8" stroke="#b8f36c" fill="none" /><path d="M0 -20V12M-24 -6L0 -14L24 -6M0 12L-18 38M0 12L18 38" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="-14" r="2.3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="0" cy="12" r="2.3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="-24" cy="-6" r="2.3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="24" cy="-6" r="2.3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><ellipse cx="0" cy="14" rx="40" ry="13" fill="none" stroke="#438fff" stroke-dasharray="3 8" class="flow"/></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">SENSING GUIDE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Presence & motion</title><desc id="desc">Explore changes in room occupancy. Inspect motion features from CSI. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
.sweep{animation:sweep 5s ease-in-out infinite;transform-origin:0 0}
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes sweep{0%,100%{transform:rotate(-20deg)}50%{transform:rotate(155deg)}}
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 01</text><text x="30" y="89" font-size="25" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Presence & motion</text><text x="30" y="126" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Explore changes in room occupancy.</text><text x="30" y="151" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Inspect motion features from CSI.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 144) scale(1.12)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><ellipse rx="18" ry="8.64" fill="none" stroke="#78cfff" opacity=".4"/><ellipse rx="32" ry="15.36" fill="none" stroke="#78cfff" opacity=".4"/><ellipse rx="46" ry="22.08" fill="none" stroke="#78cfff" opacity=".4"/><path d="M-46 0H46M0 -23V23" fill="none" stroke="#438fff" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round" /><g class="sweep"><path d="M0 0L40 -18" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="34" cy="-15" r="3" stroke="#b8f36c" fill="#b8f36c"/></g><circle cx="-20" cy="8" r="3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="12" cy="13" r="3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="23" cy="-8" r="3" stroke="#ffb45e" fill="#ffb45e" class="spark"/></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">SENSING GUIDE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H556" stroke="url(#accent)" opacity=".55"/><path d="M24 275H556" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Presence & motion</title><desc id="desc">Explore changes in room occupancy. Inspect motion features from CSI. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#245360"/><text x="30" y="39" font-size="11" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">RUVIEW / 01</text><text x="30" y="94" font-size="29" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Presence & motion</text><text x="30" y="136" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >Explore changes in room occupancy.</text><text x="30" y="164" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >Inspect motion features from CSI.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 161) scale(0.53)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><g transform="translate(474 155) scale(0.68)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><circle cx="0" cy="-28" r="8" stroke="#72eee0" fill="none" /><path d="M0 -20V12M-24 -6L0 -14L24 -6M0 12L-18 38M0 12L18 38" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><ellipse cx="0" cy="14" rx="40" ry="13" fill="none" stroke="#70b6ff" stroke-dasharray="3 8" class="flow"/></g></g><path d="M30 204H550" fill="none" stroke="#245360" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#72eee0" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">SENSING GUIDE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Breathing & vital signals</title><desc id="desc">Inspect phase-derived signal trends. Validate estimates on your hardware. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 02</text><text x="30" y="94" font-size="29" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Breathing & vital signals</text><text x="30" y="136" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Inspect phase-derived signal trends.</text><text x="30" y="164" font-size="16" fill="#b0c2db" text-anchor="start" font-weight="500" >Validate estimates on your hardware.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 161) scale(0.53)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><g transform="translate(474 155) scale(0.68)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-42 6H-27L-18 -10L-9 25L3 -25L14 10L24 -3L31 6H43" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="trace"/><path d="M-42 31H43" fill="none" stroke="#233f63" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">SIGNAL PIPELINE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Breathing & vital signals</title><desc id="desc">Inspect phase-derived signal trends. Validate estimates on your hardware. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.cursor{animation:cursor 5s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
@keyframes cursor{0%,100%{transform:translateX(-35px);opacity:.3}50%{transform:translateX(35px);opacity:1}}
|
||||
|
||||
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="30" y="39" font-size="11" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / 02</text><text x="30" y="89" font-size="25" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Breathing & vital signals</text><text x="30" y="126" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Inspect phase-derived signal trends.</text><text x="30" y="151" font-size="14" fill="#b0c2db" text-anchor="start" font-weight="500" >Validate estimates on your hardware.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 144) scale(1.12)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><path d="M-49 -14C-34 -14 -30 -35 -17 -35S0 7 14 7S34 -14 49 -14" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="trace" style="animation-delay:-0s" opacity="1.0"/><path d="M-49 -2C-34 -2 -30 -23 -17 -23S0 19 14 19S34 -2 49 -2" fill="none" stroke="#b8f36c" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="trace" style="animation-delay:-1s" opacity="0.8"/><path d="M-49 10C-34 10 -30 -11 -17 -11S0 31 14 31S34 10 49 10" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="trace" style="animation-delay:-2s" opacity="0.6"/><g class="cursor"><path d="M0 -42V40" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="-8" r="3" stroke="#ffb45e" fill="#ffb45e"/></g></g></g><path d="M30 204H550" fill="none" stroke="#2d4e77" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#78cfff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">SIGNAL PIPELINE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H556" stroke="url(#accent)" opacity=".55"/><path d="M24 275H556" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="580" height="276" viewBox="0 0 580 276" role="img" aria-labelledby="title desc"><title id="title">Breathing & vital signals</title><desc id="desc">Inspect phase-derived signal trends. Validate estimates on your hardware. Conceptual animation; follow the linked source for capability limits.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="579" height="275" rx="18" fill="url(#wash)" stroke="#245360"/><text x="30" y="39" font-size="11" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">RUVIEW / 02</text><text x="30" y="94" font-size="29" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Breathing & vital signals</text><text x="30" y="136" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >Inspect phase-derived signal trends.</text><text x="30" y="164" font-size="16" fill="#9abac5" text-anchor="start" font-weight="500" >Validate estimates on your hardware.</text><circle cx="465" cy="170" r="110" fill="url(#halo)"/><g transform="translate(480 161) scale(0.53)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><g transform="translate(474 155) scale(0.68)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-42 6H-27L-18 -10L-9 25L3 -25L14 10L24 -3L31 6H43" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="trace"/><path d="M-42 31H43" fill="none" stroke="#214451" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /></g></g><path d="M30 204H550" fill="none" stroke="#245360" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M30 204H550" fill="none" stroke="#72eee0" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow" opacity=".5"/><text x="30" y="245" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">SIGNAL PIPELINE</text><path d="M510 239H540M532 231L540 239L532 247" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">Choose your next step</title><desc id="desc">Animated section heading. GUIDES / HARDWARE / INTEGRATIONS</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(76 75) scale(0.75)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M0 0L0 -33" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="0" cy="-33" r="7" stroke="#78cfff" fill="none" class="breathe"/><path d="M0 0L-35 23" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="-35" cy="23" r="7" stroke="#78cfff" fill="none" class="breathe"/><path d="M0 0L35 23" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="35" cy="23" r="7" stroke="#78cfff" fill="none" class="breathe"/><circle cx="0" cy="0" r="15" stroke="#78cfff" fill="none" /><path d="M-6 0L-1 5L8 -6" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="140" y="63" font-size="34" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Choose your next step</text><text x="142" y="99" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">GUIDES / HARDWARE / INTEGRATIONS</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">Choose your next step</title><desc id="desc">Animated section heading. GUIDES / HARDWARE / INTEGRATIONS</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{stroke-dasharray:3 14;animation:flow 8s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(76 75) scale(0.75)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><path d="M0 0L0 -36" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M0 -43l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><path d="M0 0L-38 -10" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M-38 -17l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><path d="M0 0L-23 31" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M-23 24l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><path d="M0 0L30 28" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M30 21l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><path d="M0 0L39 -17" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M39 -24l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><circle cx="0" cy="0" r="15" stroke="#b8f36c" fill="none" /><path d="M-6 0L-1 5L8 -6" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="140" y="63" font-size="34" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Choose your next step</text><text x="142" y="99" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">GUIDES / HARDWARE / INTEGRATIONS</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H1176" stroke="url(#accent)" opacity=".55"/><path d="M24 147H1176" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">Choose your next step</title><desc id="desc">Animated section heading. GUIDES / HARDWARE / INTEGRATIONS</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#245360"/><g transform="translate(76 75) scale(0.75)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M0 0L0 -33" fill="none" stroke="#70b6ff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="0" cy="-33" r="7" stroke="#72eee0" fill="none" class="breathe"/><path d="M0 0L-35 23" fill="none" stroke="#70b6ff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="-35" cy="23" r="7" stroke="#72eee0" fill="none" class="breathe"/><path d="M0 0L35 23" fill="none" stroke="#70b6ff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="35" cy="23" r="7" stroke="#72eee0" fill="none" class="breathe"/><circle cx="0" cy="0" r="15" stroke="#72eee0" fill="none" /><path d="M-6 0L-1 5L8 -6" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="140" y="63" font-size="34" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Choose your next step</text><text x="142" y="99" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">GUIDES / HARDWARE / INTEGRATIONS</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">Intelligence at the edge</title><desc id="desc">Animated section heading. SENSORS / FIRMWARE / MODULES</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(76 75) scale(0.75)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><rect x="-25" y="-25" width="50" height="50" rx="7" fill="#0c2242" stroke="#78cfff"/><rect x="-13" y="-13" width="26" height="26" rx="3" fill="none" stroke="#438fff"/><path d="M-16 -36V-25M-16 25V36M-36 -16H-25M25 -16H36" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M0 -36V-25M0 25V36M-36 0H-25M25 0H36" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M16 -36V-25M16 25V36M-36 16H-25M25 16H36" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="0" r="4" stroke="#78cfff" fill="#78cfff" class="breathe"/></g></g><text x="140" y="63" font-size="34" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Intelligence at the edge</text><text x="142" y="99" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">SENSORS / FIRMWARE / MODULES</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">Intelligence at the edge</title><desc id="desc">Animated section heading. SENSORS / FIRMWARE / MODULES</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{stroke-dasharray:3 14;animation:flow 8s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
.layer{animation:layer 6s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
@keyframes layer{50%{transform:translateY(-5px)}}
|
||||
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(76 75) scale(0.75)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><g class="layer" style="animation-delay:-0.0s"><path d="M-38 -23L0 -42L38 -23L0 -4Z" fill="#102749" stroke="#78cfff"/><path d="M-38 -23V-16L0 3L38 -16V-23M0 -4V3" fill="#09172c" stroke="#315685"/></g><g class="layer" style="animation-delay:-0.7s"><path d="M-38 -10L0 -29L38 -10L0 9Z" fill="#102749" stroke="#438fff"/><path d="M-38 -10V-3L0 16L38 -3V-10M0 9V16" fill="#09172c" stroke="#315685"/></g><g class="layer" style="animation-delay:-1.4s"><path d="M-38 3L0 -16L38 3L0 22Z" fill="#102749" stroke="#438fff"/><path d="M-38 3V10L0 29L38 10V3M0 22V29" fill="#09172c" stroke="#315685"/></g><path d="M-12 -31L0 -37L12 -31L0 -25Z" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M-26 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M0 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M26 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/></g></g><text x="140" y="63" font-size="34" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Intelligence at the edge</text><text x="142" y="99" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">SENSORS / FIRMWARE / MODULES</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H1176" stroke="url(#accent)" opacity=".55"/><path d="M24 147H1176" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">Intelligence at the edge</title><desc id="desc">Animated section heading. SENSORS / FIRMWARE / MODULES</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#245360"/><g transform="translate(76 75) scale(0.75)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><rect x="-25" y="-25" width="50" height="50" rx="7" fill="#0a2630" stroke="#72eee0"/><rect x="-13" y="-13" width="26" height="26" rx="3" fill="none" stroke="#70b6ff"/><path d="M-16 -36V-25M-16 25V36M-36 -16H-25M25 -16H36" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M0 -36V-25M0 25V36M-36 0H-25M25 0H36" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M16 -36V-25M16 25V36M-36 16H-25M25 16H36" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="0" r="4" stroke="#72eee0" fill="#72eee0" class="breathe"/></g></g><text x="140" y="63" font-size="34" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Intelligence at the edge</text><text x="142" y="99" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">SENSORS / FIRMWARE / MODULES</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">Evidence before accuracy claims</title><desc id="desc">Animated section heading. BENCHMARKS / REPRODUCERS / LIMITS</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(76 75) scale(0.75)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M0 -38L31 -20V18L0 38L-31 18V-20ZM-31 -20L0 -1L31 -20M0 -1V38" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M-15 1L-5 11L17 -12" fill="none" stroke="#438fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="trace"/></g></g><text x="140" y="63" font-size="34" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Evidence before accuracy claims</text><text x="142" y="99" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">BENCHMARKS / REPRODUCERS / LIMITS</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">Evidence before accuracy claims</title><desc id="desc">Animated section heading. BENCHMARKS / REPRODUCERS / LIMITS</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{stroke-dasharray:3 14;animation:flow 8s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
.layer{animation:layer 6s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
@keyframes layer{50%{transform:translateY(-5px)}}
|
||||
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(76 75) scale(0.75)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><g class="layer" style="animation-delay:-0.0s"><path d="M-38 -23L0 -42L38 -23L0 -4Z" fill="#102749" stroke="#78cfff"/><path d="M-38 -23V-16L0 3L38 -16V-23M0 -4V3" fill="#09172c" stroke="#315685"/></g><g class="layer" style="animation-delay:-0.7s"><path d="M-38 -10L0 -29L38 -10L0 9Z" fill="#102749" stroke="#438fff"/><path d="M-38 -10V-3L0 16L38 -3V-10M0 9V16" fill="#09172c" stroke="#315685"/></g><g class="layer" style="animation-delay:-1.4s"><path d="M-38 3L0 -16L38 3L0 22Z" fill="#102749" stroke="#438fff"/><path d="M-38 3V10L0 29L38 10V3M0 22V29" fill="#09172c" stroke="#315685"/></g><path d="M-12 -31L0 -37L12 -31L0 -25Z" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M-26 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M0 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M26 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/></g></g><text x="140" y="63" font-size="34" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Evidence before accuracy claims</text><text x="142" y="99" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">BENCHMARKS / REPRODUCERS / LIMITS</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H1176" stroke="url(#accent)" opacity=".55"/><path d="M24 147H1176" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">Evidence before accuracy claims</title><desc id="desc">Animated section heading. BENCHMARKS / REPRODUCERS / LIMITS</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#245360"/><g transform="translate(76 75) scale(0.75)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M0 -38L31 -20V18L0 38L-31 18V-20ZM-31 -20L0 -1L31 -20M0 -1V38" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M-15 1L-5 11L17 -12" fill="none" stroke="#70b6ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="trace"/></g></g><text x="140" y="63" font-size="34" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Evidence before accuracy claims</text><text x="142" y="99" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">BENCHMARKS / REPRODUCERS / LIMITS</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">Explore the capabilities</title><desc id="desc">Animated section heading. SENSING / MODELS / AUTOMATION</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(76 75) scale(0.75)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><circle cx="0" cy="-28" r="8" stroke="#b8f36c" fill="none" /><path d="M0 -20V12M-24 -6L0 -14L24 -6M0 12L-18 38M0 12L18 38" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="-14" r="2.3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="0" cy="12" r="2.3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="-24" cy="-6" r="2.3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="24" cy="-6" r="2.3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><ellipse cx="0" cy="14" rx="40" ry="13" fill="none" stroke="#438fff" stroke-dasharray="3 8" class="flow"/></g></g><text x="140" y="63" font-size="34" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Explore the capabilities</text><text x="142" y="99" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">SENSING / MODELS / AUTOMATION</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">Explore the capabilities</title><desc id="desc">Animated section heading. SENSING / MODELS / AUTOMATION</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{stroke-dasharray:3 14;animation:flow 8s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
|
||||
.sweep{animation:sweep 5s ease-in-out infinite;transform-origin:0 0}
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes sweep{0%,100%{transform:rotate(-20deg)}50%{transform:rotate(155deg)}}
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(76 75) scale(0.75)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><ellipse rx="18" ry="8.64" fill="none" stroke="#78cfff" opacity=".4"/><ellipse rx="32" ry="15.36" fill="none" stroke="#78cfff" opacity=".4"/><ellipse rx="46" ry="22.08" fill="none" stroke="#78cfff" opacity=".4"/><path d="M-46 0H46M0 -23V23" fill="none" stroke="#438fff" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round" /><g class="sweep"><path d="M0 0L40 -18" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="34" cy="-15" r="3" stroke="#b8f36c" fill="#b8f36c"/></g><circle cx="-20" cy="8" r="3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="12" cy="13" r="3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="23" cy="-8" r="3" stroke="#ffb45e" fill="#ffb45e" class="spark"/></g></g><text x="140" y="63" font-size="34" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Explore the capabilities</text><text x="142" y="99" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">SENSING / MODELS / AUTOMATION</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H1176" stroke="url(#accent)" opacity=".55"/><path d="M24 147H1176" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">Explore the capabilities</title><desc id="desc">Animated section heading. SENSING / MODELS / AUTOMATION</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#245360"/><g transform="translate(76 75) scale(0.75)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><circle cx="0" cy="-28" r="8" stroke="#72eee0" fill="none" /><path d="M0 -20V12M-24 -6L0 -14L24 -6M0 12L-18 38M0 12L18 38" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><ellipse cx="0" cy="14" rx="40" ry="13" fill="none" stroke="#70b6ff" stroke-dasharray="3 8" class="flow"/></g></g><text x="140" y="63" font-size="34" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Explore the capabilities</text><text x="142" y="99" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">SENSING / MODELS / AUTOMATION</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">From recordings to models</title><desc id="desc">Animated section heading. CAPTURE / TRAIN / EVALUATE</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(76 75) scale(0.75)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-42 6H-27L-18 -10L-9 25L3 -25L14 10L24 -3L31 6H43" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="trace"/><path d="M-42 31H43" fill="none" stroke="#233f63" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="140" y="63" font-size="34" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >From recordings to models</text><text x="142" y="99" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">CAPTURE / TRAIN / EVALUATE</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">From recordings to models</title><desc id="desc">Animated section heading. CAPTURE / TRAIN / EVALUATE</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
|
||||
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{stroke-dasharray:3 14;animation:flow 8s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.cursor{animation:cursor 5s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
@keyframes cursor{0%,100%{transform:translateX(-35px);opacity:.3}50%{transform:translateX(35px);opacity:1}}
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(76 75) scale(0.75)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><path d="M-49 -14C-34 -14 -30 -35 -17 -35S0 7 14 7S34 -14 49 -14" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="trace" style="animation-delay:-0s" opacity="1.0"/><path d="M-49 -2C-34 -2 -30 -23 -17 -23S0 19 14 19S34 -2 49 -2" fill="none" stroke="#b8f36c" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="trace" style="animation-delay:-1s" opacity="0.8"/><path d="M-49 10C-34 10 -30 -11 -17 -11S0 31 14 31S34 10 49 10" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="trace" style="animation-delay:-2s" opacity="0.6"/><g class="cursor"><path d="M0 -42V40" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="-8" r="3" stroke="#ffb45e" fill="#ffb45e"/></g></g></g><text x="140" y="63" font-size="34" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >From recordings to models</text><text x="142" y="99" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">CAPTURE / TRAIN / EVALUATE</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M24 1H1176" stroke="url(#accent)" opacity=".55"/><path d="M24 147H1176" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="148" viewBox="0 0 1200 148" role="img" aria-labelledby="title desc"><title id="title">From recordings to models</title><desc id="desc">Animated section heading. CAPTURE / TRAIN / EVALUATE</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="147" rx="18" fill="url(#wash)" stroke="#245360"/><g transform="translate(76 75) scale(0.75)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-42 6H-27L-18 -10L-9 25L3 -25L14 10L24 -3L31 6H43" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="trace"/><path d="M-42 31H43" fill="none" stroke="#214451" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="140" y="63" font-size="34" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >From recordings to models</text><text x="142" y="99" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">CAPTURE / TRAIN / EVALUATE</text><g transform="translate(1012 84) scale(0.55)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><path d="M1140 70H1160M1152 62L1160 70L1152 78" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="450" viewBox="0 0 1200 450" role="img" aria-labelledby="title desc"><title id="title">RuView: spaces become signals</title><desc id="desc">Animated conceptual RF field and room geometry. Explore the RuView user guide. This illustration is not a sensor measurement.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="449" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="48" y="44" font-size="13" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / COGNITUM ECOSYSTEM</text><text x="48" y="121" font-size="76" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >RuView</text><text x="48" y="184" font-size="38" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Spaces become signals.</text><text x="48" y="234" font-size="32" fill="#78cfff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Signals become understanding.</text><text x="50" y="279" font-size="18" fill="#b0c2db" text-anchor="start" font-weight="500" >Explore RF sensing, edge inference and local automation.</text><rect x="48" y="326" width="270" height="52" rx="12" fill="url(#accent)"/><text x="72" y="359" font-size="20" fill="#071124" text-anchor="start" font-weight="500" >Explore the guide</text><path d="M272 352H292M285 345L292 352L285 359" fill="none" stroke="#071124" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><text x="49" y="419" font-size="11" fill="#b0c2db" text-anchor="start" font-weight="500" class="mono">RF SENSING / EDGE MODELS / LOCAL ACTION</text><circle cx="950" cy="235" r="235" fill="url(#halo)"/><path d="M750 282L610 443" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M790 282L690 443" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M830 282L770 443" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M870 282L850 443" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M910 282L930 443" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M950 282L1010 443" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M990 282L1090 443" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M1030 282L1170 443" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M1070 282L1250 443" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M680 306H1168" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M680 336H1168" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M680 372H1168" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M680 418H1168" fill="none" stroke="#162f50" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M803 157L1008 106L1137 177L930 236ZM803 157V314L930 391L1137 324V177M930 236V391M1008 106V268L803 314M1008 268L1137 324" fill="none" stroke="#5490c5" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></g><g transform="translate(0 80)"><g class="scan"><path d="M803 157L1008 106L1137 177L930 236Z" fill="#78cfff" fill-opacity=".1" stroke="#78cfff" stroke-opacity=".6"/></g></g><g transform="translate(974 282)"><g class="orbit"><ellipse rx="135" ry="36" fill="none" stroke="#438fff" stroke-dasharray="3 11" opacity=".4"/><circle cx="135" cy="0" r="4" fill="#9ee7ff"/></g></g><g transform="translate(974 312)"><ellipse rx="140" ry="44" fill="none" stroke="#438fff" class="wave" style="animation-delay:-0.0s"/></g><g transform="translate(974 312)"><ellipse rx="140" ry="44" fill="none" stroke="#438fff" class="wave" style="animation-delay:-1.3s"/></g><g transform="translate(974 312)"><ellipse rx="140" ry="44" fill="none" stroke="#438fff" class="wave" style="animation-delay:-2.6s"/></g><circle cx="849" cy="198" r="1.7" stroke="#438fff" fill="#438fff" class="spark" style="animation-delay:-0.0s"/><circle cx="893" cy="198" r="1.7" stroke="#438fff" fill="#438fff" class="spark" style="animation-delay:-0.5s"/><circle cx="937" cy="198" r="1.7" stroke="#438fff" fill="#438fff" class="spark" style="animation-delay:-1.0s"/><circle cx="981" cy="198" r="1.7" stroke="#438fff" fill="#438fff" class="spark" style="animation-delay:-1.5s"/><circle cx="1025" cy="198" r="1.7" stroke="#438fff" fill="#438fff" class="spark" style="animation-delay:-2.0s"/><circle cx="1069" cy="198" r="1.7" stroke="#438fff" fill="#438fff" class="spark" style="animation-delay:-2.5s"/><circle cx="849" cy="233" r="1.7" stroke="#438fff" fill="#438fff" class="spark" style="animation-delay:-3.0s"/><circle cx="893" cy="233" r="1.7" stroke="#438fff" fill="#438fff" class="spark" style="animation-delay:-0.0s"/><circle cx="937" cy="233" r="1.7" stroke="#438fff" fill="#438fff" class="spark" style="animation-delay:-0.5s"/><circle cx="981" cy="233" r="1.7" stroke="#43Line truncated
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="450" viewBox="0 0 1200 450" role="img" aria-labelledby="title desc"><title id="title">RuView: invisible signals, visible possibility</title><desc id="desc">Animated conceptual RF room with an articulated pose, moving scan plane and propagating waves. Illustration only, not a sensor measurement.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
|
||||
|
||||
.limb{animation:limb 3s ease-in-out infinite;transform-origin:0 -18px}
|
||||
.stride{animation:limb 3s ease-in-out infinite reverse;transform-origin:5px 16px}
|
||||
.layer{animation:layer 6s ease-in-out infinite}
|
||||
|
||||
|
||||
@keyframes limb{0%,100%{transform:rotate(-9deg)}50%{transform:rotate(9deg)}}
|
||||
@keyframes layer{50%{transform:translateY(-5px)}}
|
||||
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="449" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="48" y="45" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / SPATIAL INTELLIGENCE</text><text x="44" y="140" font-size="59" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Invisible signals.</text><text x="44" y="204" font-size="55" fill="#b8f36c" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Visible possibility.</text><text x="48" y="256" font-size="18" fill="#b0c2db" text-anchor="start" font-weight="500" >Explore the space between sensing and understanding.</text><text x="48" y="284" font-size="18" fill="#b0c2db" text-anchor="start" font-weight="500" >WiFi sensing. Edge models. Local automation.</text><rect x="48" y="327" width="240" height="49" rx="24" fill="url(#accent)"/><text x="72" y="358" font-size="18" fill="#071124" text-anchor="start" font-weight="500" >Enter the field</text><path d="M246 351H266M259 344L266 351L259 358" fill="none" stroke="#071124" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><text x="49" y="418" font-size="10" fill="#b0c2db" text-anchor="start" font-weight="500" class="mono">RF SENSING / OPEN RESEARCH / EDGE COMPUTE</text><circle cx="955" cy="230" r="234" fill="url(#halo)"/><path d="M785 270L648 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M809 270L739 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M833 270L830 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M857 270L921 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M881 270L1012 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M905 270L1103 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M929 270L1194 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M768 286H1110" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M741 317H1126" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M714 348H1142" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M687 379H1158" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M660 410H1174" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M780 295L963 211L1148 303L960 400Z" fill="#0d2342" fill-opacity=".65" stroke="#315685"/><path d="M780 295V153L963 70L1148 162V303M780 153L960 244L1148 162M960 244V400" fill="none" stroke="#438fff" opacity=".55"/><path d="M963 70V211L1148 303V162Z" fill="#438fff" fill-opacity=".05"/><g class="scan"><path d="M780 286L963 202L1148 294L960 390Z" fill="#78cfff" fill-opacity=".08" stroke="#78cfff" stroke-opacity=".6"/></g><g transform="translate(957 320)"><ellipse rx="90" ry="30" fill="none" stroke="#78cfff" class="wave" style="animation-delay:-0.0s"/></g><g transform="translate(957 320)"><ellipse rx="116" ry="38" fill="none" stroke="#78cfff" class="wave" style="animation-delay:-1.3s"/></g><g transform="translate(957 320)"><ellipse rx="142" ry="46" fill="none" stroke="#78cfff" class="wave" style="animation-delay:-2.6s"/></g><g transform="translate(959 236) scale(1.8)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><circle cx="0" cy="-32" r="7" stroke="#b8f36c" fill="none" /><path d="M0 -25L-3 -2L5 16" fill="none" stroke="#b8f36c" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" /><g class="limb"><path d="M-1 -18L-19 -5L-31 -14M-1 -18L18 -11L28 -25" fill="none" stroke="#b8f36c" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" /></g><g class="stride"><path d="M5 16L-12 28L-22 47M5 16L24 28L33 44" fill="none" stroke="#b8f36c" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" /></g><circle cx="-1" cy="-18" r="2.8" stroke="#ffb45e" fill="#ffb45e"/><circle cx="-3" cy="-2" r="2.8" stroke="#ffb45e" fill="#ffb45e"/><circle cx="5" cy="16" r="2.8" stroke="#ffb45e" fill="#ffb45e"/><circle cx="-19" cy="-5" r="2.8" stroke="#ffb45e" fill="#ffb45e"/><circle cx="18" cy="-11" r="2.8" stroke="#ffb45e" fill="#ffb45e"/><path d="M-42 -42V-50H-30M30 -50H42V-42M42 45V53H30M-30 53H-42V45" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /></g></g><g transform="translate(771 324) scale(0.72)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><g class="layer" style="animation-delay:-0.0s"><path d="M-38 -23L0 -42L38 -2Line truncated
|
||||
|
After Width: | Height: | Size: 9.0 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="450" viewBox="0 0 1200 450" role="img" aria-labelledby="title desc"><title id="title">RuView: invisible signals, visible possibility</title><desc id="desc">Animated conceptual RF room with an anatomical human silhouette, moving scan plane and propagating waves. Illustration only, not a sensor measurement.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
|
||||
|
||||
.limb{animation:limb 3s ease-in-out infinite;transform-origin:0 -18px}
|
||||
.stride{animation:limb 3s ease-in-out infinite reverse;transform-origin:5px 16px}
|
||||
.layer{animation:layer 6s ease-in-out infinite}
|
||||
|
||||
|
||||
@keyframes limb{0%,100%{transform:rotate(-3deg)}50%{transform:rotate(3deg)}}
|
||||
@keyframes layer{50%{transform:translateY(-5px)}}
|
||||
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="449" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="48" y="45" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / SPATIAL INTELLIGENCE</text><text x="44" y="140" font-size="59" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Invisible signals.</text><text x="44" y="204" font-size="55" fill="#b8f36c" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Visible possibility.</text><text x="48" y="256" font-size="18" fill="#b0c2db" text-anchor="start" font-weight="500" >Explore the space between sensing and understanding.</text><text x="48" y="284" font-size="18" fill="#b0c2db" text-anchor="start" font-weight="500" >WiFi sensing. Edge models. Local automation.</text><rect x="48" y="327" width="240" height="49" rx="24" fill="url(#accent)"/><text x="72" y="358" font-size="18" fill="#071124" text-anchor="start" font-weight="500" >Enter the field</text><path d="M246 351H266M259 344L266 351L259 358" fill="none" stroke="#071124" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><text x="49" y="418" font-size="10" fill="#b0c2db" text-anchor="start" font-weight="500" class="mono">RF SENSING / OPEN RESEARCH / EDGE COMPUTE</text><circle cx="955" cy="230" r="234" fill="url(#halo)"/><path d="M785 270L648 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M809 270L739 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M833 270L830 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M857 270L921 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M881 270L1012 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M905 270L1103 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M929 270L1194 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M768 286H1110" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M741 317H1126" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M714 348H1142" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M687 379H1158" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M660 410H1174" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M780 295L963 211L1148 303L960 400Z" fill="#0d2342" fill-opacity=".65" stroke="#315685"/><path d="M780 295V153L963 70L1148 162V303M780 153L960 244L1148 162M960 244V400" fill="none" stroke="#438fff" opacity=".55"/><path d="M963 70V211L1148 303V162Z" fill="#438fff" fill-opacity=".05"/><g class="scan"><path d="M780 286L963 202L1148 294L960 390Z" fill="#78cfff" fill-opacity=".08" stroke="#78cfff" stroke-opacity=".6"/></g><g transform="translate(957 320)"><ellipse rx="90" ry="30" fill="none" stroke="#78cfff" class="wave" style="animation-delay:-0.0s"/></g><g transform="translate(957 320)"><ellipse rx="116" ry="38" fill="none" stroke="#78cfff" class="wave" style="animation-delay:-1.3s"/></g><g transform="translate(957 320)"><ellipse rx="142" ry="46" fill="none" stroke="#78cfff" class="wave" style="animation-delay:-2.6s"/></g><g transform="translate(959 236) scale(1.8)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><defs><linearGradient id="humanSurface" x1="0" y1="0" x2="1" y2=".3"><stop stop-color="#153d48"/><stop offset=".42" stop-color="#338469"/><stop offset=".7" stop-color="#83c766"/><stop offset="1" stop-color="#163c4a"/></linearGradient><linearGradient id="humanRear"><stop stop-color="#0f2d40"/><stop offset="1" stop-color="#397a68"/></linearGradient></defs><g stroke="#88d783" stroke-width=".65" stroke-linejoin="round"><g class="limb"><path d="M-9 -25C-15 -25 -18 -19 -21 -13L-29 -5C-32 -3 -33 1 -30 3L-25 2L-14 -7C-9 -12 -6 -19 -6 -23Z" fill="url(#humanRear)"/></g><g class="stride"><path d="M-6 5C-13 10 -15 18 -17 26L-25 43L-29 47C-30 49 -28 51 -24 51L-17 50L-16 46L-8 30C-4 23 2 15 3 10Z" fill="url(#humanRear)"/><path d="M3 5C10 7 14 17 19 23C24 28 23 35 24 41L29 45C32 47 32 49 28 50L20 49C17 48 17 46 17 42L14 32C8 28 2 23 -3 16L-4 10Z" fill="url(#humanSurface)"/></g><g class="limb"><path d="M7 -26C14 -25 17 -20 20 -13L24 -17L29 -24C30 -27 33 -29 35 -26L35 -22L30 -16L24 -8C22 -5 18 -5 16 -8L8 -17Z" fill="url(#humanSurface)"/></g><path d="M-4 -32L4 -33L6 -28C11 -27 14 -24 13 -19L9 -5L10 7C10 13 2 15 -5 12L-10 7L-8 -5L-12 -20C-13 -25 -8 -28 -5 -28Z" fill="url(#humanSurface)"/><path d="M-6 -42C-6 -48 2 -51 7 -47C10Line truncated
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,47 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="450" viewBox="0 0 1200 450" role="img" aria-labelledby="title desc"><title id="title">RuView: invisible signals, visible possibility</title><desc id="desc">Animated conceptual RF room with an anatomical human silhouette, moving scan plane and propagating waves. Illustration only, not a sensor measurement.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
.layer{animation:layer 6s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
@keyframes layer{50%{transform:translateY(-5px)}}
|
||||
|
||||
|
||||
|
||||
.humanTurn{transform-box:fill-box;transform-origin:center 85%;animation:humanTurn 8s ease-in-out infinite}
|
||||
.humanBody{animation:humanBody 1.6s ease-in-out infinite}
|
||||
.armFar{transform-origin:-9px -24px;animation:armSwing 1.6s ease-in-out infinite}
|
||||
.armNear{transform-origin:10px -23px;animation:armSwing 1.6s ease-in-out infinite;animation-delay:-.8s}
|
||||
.legFar{transform-origin:-3px 9px;animation:legSwing 1.6s ease-in-out infinite;animation-delay:-.8s}
|
||||
.legNear{transform-origin:2px 9px;animation:legSwing 1.6s ease-in-out infinite}
|
||||
.humanLight{animation:humanLight 8s ease-in-out infinite}
|
||||
.gaitShadow{transform-box:fill-box;transform-origin:center;animation:gaitShadow 1.6s ease-in-out infinite}
|
||||
@keyframes humanTurn{0%,100%{transform:perspective(450px) rotateY(-24deg) rotateZ(-2deg)}50%{transform:perspective(450px) rotateY(24deg) rotateZ(2deg)}}
|
||||
@keyframes humanBody{0%,50%,100%{transform:translateY(0)}25%,75%{transform:translateY(-2px)}}
|
||||
@keyframes armSwing{0%,100%{transform:rotate(-17deg)}50%{transform:rotate(17deg)}}
|
||||
@keyframes legSwing{0%,100%{transform:rotate(-12deg)}50%{transform:rotate(12deg)}}
|
||||
@keyframes humanLight{0%,100%{opacity:.1}50%{opacity:.45}}
|
||||
@keyframes gaitShadow{0%,50%,100%{transform:scaleX(1);opacity:.7}25%,75%{transform:scaleX(.85);opacity:.45}}
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="449" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="48" y="45" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">RUVIEW / SPATIAL INTELLIGENCE</text><text x="44" y="140" font-size="59" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Invisible signals.</text><text x="44" y="204" font-size="55" fill="#b8f36c" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Visible possibility.</text><text x="48" y="256" font-size="18" fill="#b0c2db" text-anchor="start" font-weight="500" >Explore the space between sensing and understanding.</text><text x="48" y="284" font-size="18" fill="#b0c2db" text-anchor="start" font-weight="500" >WiFi sensing. Edge models. Local automation.</text><rect x="48" y="327" width="240" height="49" rx="24" fill="url(#accent)"/><text x="72" y="358" font-size="18" fill="#071124" text-anchor="start" font-weight="500" >Enter the field</text><path d="M246 351H266M259 344L266 351L259 358" fill="none" stroke="#071124" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><text x="49" y="418" font-size="10" fill="#b0c2db" text-anchor="start" font-weight="500" class="mono">RF SENSING / OPEN RESEARCH / EDGE COMPUTE</text><circle cx="955" cy="230" r="234" fill="url(#halo)"/><path d="M785 270L648 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M809 270L739 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M833 270L830 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M857 270L921 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M881 270L1012 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M905 270L1103 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M929 270L1194 432" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M768 286H1110" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M741 317H1126" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M714 348H1142" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M687 379H1158" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M660 410H1174" fill="none" stroke="#1b3558" stroke-width="0.8" stroke-linecap="round" stroke-linejoin="round" /><path d="M780 295L963 211L1148 303L960 400Z" fill="#0d2342" fill-opacity=".65" stroke="#315685"/><path d="M780 295V153L963 70L1148 162V303M780 153L960 244L1148 162M960 244V400" fill="none" stroke="#438fff" opacity=".55"/><path d="M963 70V211L1148 303V162Z" fill="#438fff" fill-opacity=".05"/><g class="scan"><path d="M780 286L963 202L1148 294L960 390Z" fill="#78cfff" fill-opacity=".08" stroke="#78cfff" stroke-opacity=".6"/></g><g transform="translate(957 320)"><ellipse rx="90" ry="30" fill="none" stroke="#78cfff" class="wave" style="animation-delay:-0.0s"/></g><g transform="translate(957 320)"><ellipse rx="116" ry="38" fill="none" stroke="#78cfff" class="wave" style="animation-delay:-1.3s"/></g><g transform="translate(957 320)"><ellipse rx="142" ry="46" fill="none" stroke="#78cfff" class="wave" style="animation-delay:-2.6s"/></g><g transform="translate(959 236) scale(1.8)"><ellipse cy="53" rx="37" ry="7" fill="#020816" class="gaitShadow"/><g class="humanBody"><defs><linearGradient id="humanSurface" x1="0" y1="0" x2="1" y2=".3"><stop stop-color="#153d48"/><stop offset=".42" stop-color="#338469"/><stop offset=".7" stop-color="#83c766"/><stop offset="1" stop-color="#163c4a"/></linearGradient><linearGradient id="humanRear"><stop stop-color="#0f2d40"/><stop offset="1" stop-color="#397a68"/></linearGradient></defs><g class="humanTurn"><g stroke="#88d783" stroke-width=".65" stroke-linejoin="round"><g class="armFar"><path d="M-9 -25C-15 -25 -18 -19 -21 -13L-29 -5C-32 -3 -33 1 -30 3L-25 2L-14 -7C-9 -12 -6 -19 -6 -23Z" fill="url(#humanRear)"/></g><g class="legFar"><path d="M-6 5C-13 10 -15 18 -17 26L-25 43L-29 47C-30 49 -28 51 -24 51L-17 50L-16 46L-8 30C-4 23 2 15 3 10Z" fill="url(#humanRear)"/><circle cx="-15" cy="26" r="1.8" fill="#ffb45e"/></g><g class="legNear"><path d="M3 5C10 7 14 17 19 23C24 28 23 35 24 41L29 45C32 47 32 49 28 50L20 49C17 48 17 46 17 42L14 32C8 28 2 23 -3 16L-4 10Z" fill="url(#humanSurface)"/><circle cx="19" cy="28" r="1.8" fill="#ffb45e"/></g><g class="armNear"><path d="M7 -26C14 -25 17 -20 20 -13L24 -17L29 -24C30 -27 33 -29 35 -26L35 -22L30 -16L24 -8C22 -5 18 -5 16 -8L8 -17Z" fill="url(#humanSurface)"/></g><path d="M-4 -32L4 -33L6 -28C11Line truncated
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="450" viewBox="0 0 1200 450" role="img" aria-labelledby="title desc"><title id="title">RuView: spaces become signals</title><desc id="desc">Animated conceptual RF field and room geometry. Explore the RuView user guide. This illustration is not a sensor measurement.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="449" rx="18" fill="url(#wash)" stroke="#245360"/><text x="48" y="44" font-size="13" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">RUVIEW / COGNITUM ECOSYSTEM</text><text x="48" y="121" font-size="76" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >RuView</text><text x="48" y="184" font-size="38" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Spaces become signals.</text><text x="48" y="234" font-size="32" fill="#72eee0" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Signals become understanding.</text><text x="50" y="279" font-size="18" fill="#9abac5" text-anchor="start" font-weight="500" >Explore RF sensing, edge inference and local automation.</text><rect x="48" y="326" width="270" height="52" rx="12" fill="url(#accent)"/><text x="72" y="359" font-size="20" fill="#041117" text-anchor="start" font-weight="500" >Explore the guide</text><path d="M272 352H292M285 345L292 352L285 359" fill="none" stroke="#041117" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><text x="49" y="419" font-size="11" fill="#9abac5" text-anchor="start" font-weight="500" class="mono">RF SENSING / EDGE MODELS / LOCAL ACTION</text><circle cx="950" cy="235" r="235" fill="url(#halo)"/><path d="M750 282L610 443" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M790 282L690 443" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M830 282L770 443" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M870 282L850 443" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M910 282L930 443" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M950 282L1010 443" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M990 282L1090 443" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M1030 282L1170 443" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M1070 282L1250 443" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M680 306H1168" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M680 336H1168" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M680 372H1168" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><path d="M680 418H1168" fill="none" stroke="#12343d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M803 157L1008 106L1137 177L930 236ZM803 157V314L930 391L1137 324V177M930 236V391M1008 106V268L803 314M1008 268L1137 324" fill="none" stroke="#4b9ba4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></g><g transform="translate(0 80)"><g class="scan"><path d="M803 157L1008 106L1137 177L930 236Z" fill="#72eee0" fill-opacity=".1" stroke="#72eee0" stroke-opacity=".6"/></g></g><g transform="translate(974 282)"><g class="orbit"><ellipse rx="135" ry="36" fill="none" stroke="#70b6ff" stroke-dasharray="3 11" opacity=".4"/><circle cx="135" cy="0" r="4" fill="#91f6df"/></g></g><circle cx="849" cy="198" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-0.0s"/><circle cx="893" cy="198" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-0.5s"/><circle cx="937" cy="198" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-1.0s"/><circle cx="981" cy="198" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-1.5s"/><circle cx="1025" cy="198" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-2.0s"/><circle cx="1069" cy="198" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-2.5s"/><circle cx="849" cy="233" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-3.0s"/><circle cx="893" cy="233" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-0.0s"/><circle cx="937" cy="233" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-0.5s"/><circle cx="981" cy="233" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-1.0s"/><circle cx="1025" cy="233" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-1.5s"/><circle cx="1069" cy="233" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-2.0s"/><circle cx="849" cy="268" r="1.7" stroke="#70b6ff" fill="#70b6ff" class="spark" style="animation-delay:-2.5s"/><circlLine truncated
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,147 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"style": "RuView spatial v4: navy glass, electric blue, lime and amber",
|
||||
"motion": "Decorative CSS; prefers-reduced-motion supported; no script or remote dependencies",
|
||||
"assets": [
|
||||
{
|
||||
"file": "assets/readme/hero-spatial-v6.svg",
|
||||
"title": "RuView: invisible signals, visible possibility",
|
||||
"target": "docs/user-guide.md",
|
||||
"width": 1200,
|
||||
"height": 450
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/nav-start-spatial-v4.svg",
|
||||
"title": "Start here",
|
||||
"target": "docs/user-guide.md",
|
||||
"width": 180,
|
||||
"height": 116
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/nav-hardware-spatial-v4.svg",
|
||||
"title": "Hardware",
|
||||
"target": "firmware/esp32-csi-node/README.md",
|
||||
"width": 180,
|
||||
"height": 116
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/nav-models-spatial-v4.svg",
|
||||
"title": "Models",
|
||||
"target": "https://huggingface.co/ruvnet/wifi-densepose-pretrained",
|
||||
"width": 180,
|
||||
"height": 116
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/nav-agents-spatial-v4.svg",
|
||||
"title": "AI toolkit",
|
||||
"target": "harness/ruview/README.md",
|
||||
"width": 180,
|
||||
"height": 116
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/nav-home-spatial-v4.svg",
|
||||
"title": "Smart home",
|
||||
"target": "docs/integrations/home-assistant.md",
|
||||
"width": 180,
|
||||
"height": 116
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/nav-seed-spatial-v4.svg",
|
||||
"title": "Cognitum",
|
||||
"target": "https://cognitum.one/seed",
|
||||
"width": 180,
|
||||
"height": 116
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/feature-presence-spatial-v4.svg",
|
||||
"title": "Presence & motion",
|
||||
"target": "docs/user-guide.md",
|
||||
"width": 580,
|
||||
"height": 276
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/feature-vitals-spatial-v4.svg",
|
||||
"title": "Breathing & vital signals",
|
||||
"target": "v2/crates/wifi-densepose-signal/README.md",
|
||||
"width": 580,
|
||||
"height": 276
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/feature-pose-spatial-v6.svg",
|
||||
"title": "Pose research",
|
||||
"target": "docs/benchmarks/pose-estimation-cog.md",
|
||||
"width": 580,
|
||||
"height": 276
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/feature-edge-spatial-v4.svg",
|
||||
"title": "Edge sensor mesh",
|
||||
"target": "firmware/esp32-csi-node/README.md",
|
||||
"width": 580,
|
||||
"height": 276
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/feature-automation-spatial-v4.svg",
|
||||
"title": "Local automation",
|
||||
"target": "docs/integrations/home-assistant.md",
|
||||
"width": 580,
|
||||
"height": 276
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/feature-agents-spatial-v4.svg",
|
||||
"title": "A guided AI operator",
|
||||
"target": "harness/ruview/README.md",
|
||||
"width": 580,
|
||||
"height": 276
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/overview-spatial-v4.svg",
|
||||
"title": "RuView sensing overview",
|
||||
"target": "docs/user-guide.md",
|
||||
"width": 1200,
|
||||
"height": 396
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/header-features-spatial-v4.svg",
|
||||
"title": "Explore the capabilities",
|
||||
"target": "docs/user-guide.md",
|
||||
"width": 1200,
|
||||
"height": 148
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/header-edge-spatial-v4.svg",
|
||||
"title": "Intelligence at the edge",
|
||||
"target": "firmware/esp32-csi-node/README.md",
|
||||
"width": 1200,
|
||||
"height": 148
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/header-learning-spatial-v4.svg",
|
||||
"title": "From recordings to models",
|
||||
"target": "docs/user-guide.md",
|
||||
"width": 1200,
|
||||
"height": 148
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/header-evidence-spatial-v4.svg",
|
||||
"title": "Evidence before accuracy claims",
|
||||
"target": "docs/benchmarks/pose-estimation-cog.md",
|
||||
"width": 1200,
|
||||
"height": 148
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/header-docs-spatial-v4.svg",
|
||||
"title": "Choose your next step",
|
||||
"target": "docs/user-guide.md",
|
||||
"width": 1200,
|
||||
"height": 148
|
||||
},
|
||||
{
|
||||
"file": "assets/readme/cognitum-spatial-v4.svg",
|
||||
"title": "Explore Cognitum One",
|
||||
"target": "https://cognitum.one",
|
||||
"width": 1200,
|
||||
"height": 304
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">AI toolkit</title><desc id="desc">Open AI toolkit. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(90 45) scale(0.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M0 0L0 -33" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="0" cy="-33" r="7" stroke="#78cfff" fill="none" class="breathe"/><path d="M0 0L-35 23" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="-35" cy="23" r="7" stroke="#78cfff" fill="none" class="breathe"/><path d="M0 0L35 23" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="35" cy="23" r="7" stroke="#78cfff" fill="none" class="breathe"/><circle cx="0" cy="0" r="15" stroke="#78cfff" fill="none" /><path d="M-6 0L-1 5L8 -6" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="90" y="98" font-size="16" fill="#f3f7ff" text-anchor="middle" font-weight="500" >AI toolkit</text></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">AI toolkit</title><desc id="desc">Open AI toolkit. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(90 45) scale(0.65)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><path d="M0 0L0 -36" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M0 -43l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><path d="M0 0L-38 -10" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M-38 -17l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><path d="M0 0L-23 31" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M-23 24l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><path d="M0 0L30 28" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M30 21l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><path d="M0 0L39 -17" fill="none" stroke="#438fff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M39 -24l7 4v8l-7 4l-7 -4v-8Z" fill="#102749" stroke="#78cfff" class="breathe"/><circle cx="0" cy="0" r="15" stroke="#b8f36c" fill="none" /><path d="M-6 0L-1 5L8 -6" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="90" y="98" font-size="16" fill="#f3f7ff" text-anchor="middle" font-weight="500" >AI toolkit</text><path d="M24 1H156" stroke="url(#accent)" opacity=".55"/><path d="M24 115H156" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">AI toolkit</title><desc id="desc">Open AI toolkit. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#245360"/><g transform="translate(90 45) scale(0.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M0 0L0 -33" fill="none" stroke="#70b6ff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="0" cy="-33" r="7" stroke="#72eee0" fill="none" class="breathe"/><path d="M0 0L-35 23" fill="none" stroke="#70b6ff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="-35" cy="23" r="7" stroke="#72eee0" fill="none" class="breathe"/><path d="M0 0L35 23" fill="none" stroke="#70b6ff" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="35" cy="23" r="7" stroke="#72eee0" fill="none" class="breathe"/><circle cx="0" cy="0" r="15" stroke="#72eee0" fill="none" /><path d="M-6 0L-1 5L8 -6" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="90" y="98" font-size="16" fill="#ecfafb" text-anchor="middle" font-weight="500" >AI toolkit</text></svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Hardware</title><desc id="desc">Open Hardware. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(90 45) scale(0.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><rect x="-25" y="-25" width="50" height="50" rx="7" fill="#0c2242" stroke="#78cfff"/><rect x="-13" y="-13" width="26" height="26" rx="3" fill="none" stroke="#438fff"/><path d="M-16 -36V-25M-16 25V36M-36 -16H-25M25 -16H36" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M0 -36V-25M0 25V36M-36 0H-25M25 0H36" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M16 -36V-25M16 25V36M-36 16H-25M25 16H36" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="0" r="4" stroke="#78cfff" fill="#78cfff" class="breathe"/></g></g><text x="90" y="98" font-size="16" fill="#f3f7ff" text-anchor="middle" font-weight="500" >Hardware</text></svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Hardware</title><desc id="desc">Open Hardware. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.layer{animation:layer 6s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
@keyframes layer{50%{transform:translateY(-5px)}}
|
||||
|
||||
|
||||
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(90 45) scale(0.65)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><g class="layer" style="animation-delay:-0.0s"><path d="M-38 -23L0 -42L38 -23L0 -4Z" fill="#102749" stroke="#78cfff"/><path d="M-38 -23V-16L0 3L38 -16V-23M0 -4V3" fill="#09172c" stroke="#315685"/></g><g class="layer" style="animation-delay:-0.7s"><path d="M-38 -10L0 -29L38 -10L0 9Z" fill="#102749" stroke="#438fff"/><path d="M-38 -10V-3L0 16L38 -3V-10M0 9V16" fill="#09172c" stroke="#315685"/></g><g class="layer" style="animation-delay:-1.4s"><path d="M-38 3L0 -16L38 3L0 22Z" fill="#102749" stroke="#438fff"/><path d="M-38 3V10L0 29L38 10V3M0 22V29" fill="#09172c" stroke="#315685"/></g><path d="M-12 -31L0 -37L12 -31L0 -25Z" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M-26 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M0 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M26 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/></g></g><text x="90" y="98" font-size="16" fill="#f3f7ff" text-anchor="middle" font-weight="500" >Hardware</text><path d="M24 1H156" stroke="url(#accent)" opacity=".55"/><path d="M24 115H156" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Hardware</title><desc id="desc">Open Hardware. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#245360"/><g transform="translate(90 45) scale(0.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><rect x="-25" y="-25" width="50" height="50" rx="7" fill="#0a2630" stroke="#72eee0"/><rect x="-13" y="-13" width="26" height="26" rx="3" fill="none" stroke="#70b6ff"/><path d="M-16 -36V-25M-16 25V36M-36 -16H-25M25 -16H36" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M0 -36V-25M0 25V36M-36 0H-25M25 0H36" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M16 -36V-25M16 25V36M-36 16H-25M25 16H36" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="0" r="4" stroke="#72eee0" fill="#72eee0" class="breathe"/></g></g><text x="90" y="98" font-size="16" fill="#ecfafb" text-anchor="middle" font-weight="500" >Hardware</text></svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Smart home</title><desc id="desc">Open Smart home. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(90 45) scale(0.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-37 -3L0 -34L37 -3M-28 -10V32H28V-10M-9 32V8H9V32" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="-9" r="5" stroke="#438fff" fill="none" class="breathe"/></g></g><text x="90" y="98" font-size="16" fill="#f3f7ff" text-anchor="middle" font-weight="500" >Smart home</text></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Smart home</title><desc id="desc">Open Smart home. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(90 45) scale(0.65)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><path d="M-43 12L0 -10L43 12L0 35Z" fill="#102749" stroke="#438fff"/><path d="M-32 17V-16L0 -35L32 -16V17M-32 -16L0 3L32 -16M0 3V34" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M-22 20L-10 13L12 25M-10 13V-5" fill="none" stroke="#b8f36c" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="flow"/><circle cx="-22" cy="20" r="4" stroke="#ffb45e" fill="#102749" class="breathe"/><circle cx="-10" cy="-5" r="4" stroke="#ffb45e" fill="#102749" class="breathe"/><circle cx="12" cy="25" r="4" stroke="#ffb45e" fill="#102749" class="breathe"/></g></g><text x="90" y="98" font-size="16" fill="#f3f7ff" text-anchor="middle" font-weight="500" >Smart home</text><path d="M24 1H156" stroke="url(#accent)" opacity=".55"/><path d="M24 115H156" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Smart home</title><desc id="desc">Open Smart home. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#245360"/><g transform="translate(90 45) scale(0.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-37 -3L0 -34L37 -3M-28 -10V32H28V-10M-9 32V8H9V32" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="-9" r="5" stroke="#70b6ff" fill="none" class="breathe"/></g></g><text x="90" y="98" font-size="16" fill="#ecfafb" text-anchor="middle" font-weight="500" >Smart home</text></svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Models</title><desc id="desc">Open Models. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(90 45) scale(0.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-42 6H-27L-18 -10L-9 25L3 -25L14 10L24 -3L31 6H43" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="trace"/><path d="M-42 31H43" fill="none" stroke="#233f63" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="90" y="98" font-size="16" fill="#f3f7ff" text-anchor="middle" font-weight="500" >Models</text></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Models</title><desc id="desc">Open Models. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
|
||||
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.cursor{animation:cursor 5s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
@keyframes cursor{0%,100%{transform:translateX(-35px);opacity:.3}50%{transform:translateX(35px);opacity:1}}
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(90 45) scale(0.65)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><path d="M-49 -14C-34 -14 -30 -35 -17 -35S0 7 14 7S34 -14 49 -14" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="trace" style="animation-delay:-0s" opacity="1.0"/><path d="M-49 -2C-34 -2 -30 -23 -17 -23S0 19 14 19S34 -2 49 -2" fill="none" stroke="#b8f36c" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="trace" style="animation-delay:-1s" opacity="0.8"/><path d="M-49 10C-34 10 -30 -11 -17 -11S0 31 14 31S34 10 49 10" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="trace" style="animation-delay:-2s" opacity="0.6"/><g class="cursor"><path d="M0 -42V40" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><circle cx="0" cy="-8" r="3" stroke="#ffb45e" fill="#ffb45e"/></g></g></g><text x="90" y="98" font-size="16" fill="#f3f7ff" text-anchor="middle" font-weight="500" >Models</text><path d="M24 1H156" stroke="url(#accent)" opacity=".55"/><path d="M24 115H156" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Models</title><desc id="desc">Open Models. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#245360"/><g transform="translate(90 45) scale(0.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-42 6H-27L-18 -10L-9 25L3 -25L14 10L24 -3L31 6H43" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="trace"/><path d="M-42 31H43" fill="none" stroke="#214451" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="90" y="98" font-size="16" fill="#ecfafb" text-anchor="middle" font-weight="500" >Models</text></svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Cognitum</title><desc id="desc">Open Cognitum. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(90 45) scale(0.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M0 -38L31 -20V18L0 38L-31 18V-20ZM-31 -20L0 -1L31 -20M0 -1V38" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M-15 1L-5 11L17 -12" fill="none" stroke="#438fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="trace"/></g></g><text x="90" y="98" font-size="16" fill="#f3f7ff" text-anchor="middle" font-weight="500" >Cognitum</text></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Cognitum</title><desc id="desc">Open Cognitum. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.layer{animation:layer 6s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
@keyframes layer{50%{transform:translateY(-5px)}}
|
||||
|
||||
|
||||
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
|
||||
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(90 45) scale(0.65)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><g class="layer" style="animation-delay:-0.0s"><path d="M-38 -23L0 -42L38 -23L0 -4Z" fill="#102749" stroke="#78cfff"/><path d="M-38 -23V-16L0 3L38 -16V-23M0 -4V3" fill="#09172c" stroke="#315685"/></g><g class="layer" style="animation-delay:-0.7s"><path d="M-38 -10L0 -29L38 -10L0 9Z" fill="#102749" stroke="#438fff"/><path d="M-38 -10V-3L0 16L38 -3V-10M0 9V16" fill="#09172c" stroke="#315685"/></g><g class="layer" style="animation-delay:-1.4s"><path d="M-38 3L0 -16L38 3L0 22Z" fill="#102749" stroke="#438fff"/><path d="M-38 3V10L0 29L38 10V3M0 22V29" fill="#09172c" stroke="#315685"/></g><path d="M-12 -31L0 -37L12 -31L0 -25Z" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M-26 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M0 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/><path d="M26 22V39" fill="none" stroke="#ffb45e" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="flow"/></g></g><text x="90" y="98" font-size="16" fill="#f3f7ff" text-anchor="middle" font-weight="500" >Cognitum</text><path d="M24 1H156" stroke="url(#accent)" opacity=".55"/><path d="M24 115H156" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Cognitum</title><desc id="desc">Open Cognitum. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#245360"/><g transform="translate(90 45) scale(0.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M0 -38L31 -20V18L0 38L-31 18V-20ZM-31 -20L0 -1L31 -20M0 -1V38" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><path d="M-15 1L-5 11L17 -12" fill="none" stroke="#70b6ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="trace"/></g></g><text x="90" y="98" font-size="16" fill="#ecfafb" text-anchor="middle" font-weight="500" >Cognitum</text></svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Start here</title><desc id="desc">Open Start here. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(90 45) scale(0.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-10.4 -5.2Q0 -18.2 10.4 -5.2" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="breathe" style="animation-delay:-0.65s"/><path d="M-20.0 -10.0Q0 -35.0 20.0 -10.0" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="breathe" style="animation-delay:-1.25s"/><path d="M-30.400000000000002 -15.200000000000001Q0 -53.199999999999996 30.400000000000002 -15.200000000000001" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="breathe" style="animation-delay:-1.9s"/><circle cx="0" cy="20" r="4" stroke="#78cfff" fill="#78cfff"/><path d="M0 12V-1" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="90" y="98" font-size="16" fill="#f3f7ff" text-anchor="middle" font-weight="500" >Start here</text></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Start here</title><desc id="desc">Open Start here. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
|
||||
|
||||
.sweep{animation:sweep 5s ease-in-out infinite;transform-origin:0 0}
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes sweep{0%,100%{transform:rotate(-20deg)}50%{transform:rotate(155deg)}}
|
||||
|
||||
|
||||
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
|
||||
|
||||
|
||||
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#2d4e77"/><g transform="translate(90 45) scale(0.65)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><ellipse rx="18" ry="8.64" fill="none" stroke="#78cfff" opacity=".4"/><ellipse rx="32" ry="15.36" fill="none" stroke="#78cfff" opacity=".4"/><ellipse rx="46" ry="22.08" fill="none" stroke="#78cfff" opacity=".4"/><path d="M-46 0H46M0 -23V23" fill="none" stroke="#438fff" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round" /><g class="sweep"><path d="M0 0L40 -18" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="34" cy="-15" r="3" stroke="#b8f36c" fill="#b8f36c"/></g><circle cx="-20" cy="8" r="3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="12" cy="13" r="3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="23" cy="-8" r="3" stroke="#ffb45e" fill="#ffb45e" class="spark"/></g></g><text x="90" y="98" font-size="16" fill="#f3f7ff" text-anchor="middle" font-weight="500" >Start here</text><path d="M24 1H156" stroke="url(#accent)" opacity=".55"/><path d="M24 115H156" stroke="#438fff" opacity=".15"/></svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="116" viewBox="0 0 180 116" role="img" aria-labelledby="title desc"><title id="title">Start here</title><desc id="desc">Open Start here. Animated navigation icon.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="179" height="115" rx="18" fill="url(#wash)" stroke="#245360"/><g transform="translate(90 45) scale(0.65)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-10.4 -5.2Q0 -18.2 10.4 -5.2" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="breathe" style="animation-delay:-0.65s"/><path d="M-20.0 -10.0Q0 -35.0 20.0 -10.0" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="breathe" style="animation-delay:-1.25s"/><path d="M-30.400000000000002 -15.200000000000001Q0 -53.199999999999996 30.400000000000002 -15.200000000000001" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="breathe" style="animation-delay:-1.9s"/><circle cx="0" cy="20" r="4" stroke="#72eee0" fill="#72eee0"/><path d="M0 12V-1" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="90" y="98" font-size="16" fill="#ecfafb" text-anchor="middle" font-weight="500" >Start here</text></svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="396" viewBox="0 0 1200 396" role="img" aria-labelledby="title desc"><title id="title">RuView sensing overview</title><desc id="desc">Conceptual sequence: capture RF, extract context, act locally. Links to architecture and user documentation.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="395" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="36" y="44" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">SIGNAL TO CONTEXT</text><text x="36" y="89" font-size="34" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >A sensing loop you can inspect.</text><rect x="36" y="120" width="336" height="220" rx="14" fill="#091b35" stroke="#315685"/><text x="60" y="153" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" >01</text><text x="60" y="188" font-size="26" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Capture RF</text><text x="60" y="216" font-size="15" fill="#b0c2db" text-anchor="start" font-weight="500" >CSI from supported hardware</text><g transform="translate(305 278) scale(0.35)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><g transform="translate(305 270) scale(0.5)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-10.4 -5.2Q0 -18.2 10.4 -5.2" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="breathe" style="animation-delay:-0.65s"/><path d="M-20.0 -10.0Q0 -35.0 20.0 -10.0" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="breathe" style="animation-delay:-1.25s"/><path d="M-30.400000000000002 -15.200000000000001Q0 -53.199999999999996 30.400000000000002 -15.200000000000001" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="breathe" style="animation-delay:-1.9s"/><circle cx="0" cy="20" r="4" stroke="#78cfff" fill="#78cfff"/><path d="M0 12V-1" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="60" y="311" font-size="13" fill="#b0c2db" text-anchor="start" font-weight="500" >Provision and calibrate</text><path d="M380 229H420M412 221L420 229L412 237" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="flow"/><rect x="432" y="120" width="336" height="220" rx="14" fill="#091b35" stroke="#315685"/><text x="456" y="153" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" >02</text><text x="456" y="188" font-size="26" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Extract context</text><text x="456" y="216" font-size="15" fill="#b0c2db" text-anchor="start" font-weight="500" >Signal processing and models</text><g transform="translate(701 278) scale(0.35)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><g transform="translate(701 270) scale(0.5)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#142c50" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#2e527d" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g Line truncated
|
||||
|
After Width: | Height: | Size: 9.7 KiB |
@@ -0,0 +1,31 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="396" viewBox="0 0 1200 396" role="img" aria-labelledby="title desc"><title id="title">RuView sensing overview</title><desc id="desc">Conceptual sequence: capture RF, extract context, act locally. Links to architecture and user documentation.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#102749"/><stop offset=".55" stop-color="#071429"/><stop offset="1" stop-color="#03091a"/></linearGradient><linearGradient id="accent"><stop stop-color="#9ee7ff"/><stop offset="1" stop-color="#348bff"/></linearGradient><radialGradient id="halo"><stop stop-color="#348bff" stop-opacity=".17"/><stop offset="1" stop-color="#348bff" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI Variable Display","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{stroke-dasharray:3 14;animation:flow 8s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
.wave{transform-box:fill-box;transform-origin:center;animation:wave 4s ease-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
|
||||
.sweep{animation:sweep 5s ease-in-out infinite;transform-origin:0 0}
|
||||
|
||||
|
||||
|
||||
.cursor{animation:cursor 5s ease-in-out infinite}
|
||||
@keyframes sweep{0%,100%{transform:rotate(-20deg)}50%{transform:rotate(155deg)}}
|
||||
|
||||
|
||||
@keyframes cursor{0%,100%{transform:translateX(-35px);opacity:.3}50%{transform:translateX(35px);opacity:1}}
|
||||
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@keyframes wave{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.3);opacity:0}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="395" rx="18" fill="url(#wash)" stroke="#2d4e77"/><text x="36" y="44" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" class="mono">SIGNAL TO CONTEXT</text><text x="36" y="89" font-size="34" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >A sensing loop you can inspect.</text><rect x="36" y="120" width="336" height="220" rx="14" fill="#091b35" stroke="#315685"/><text x="60" y="153" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" >01</text><text x="60" y="188" font-size="26" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Capture RF</text><text x="60" y="216" font-size="15" fill="#b0c2db" text-anchor="start" font-weight="500" >CSI from supported hardware</text><g transform="translate(305 278) scale(0.35)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><g transform="translate(305 270) scale(0.5)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><ellipse rx="18" ry="8.64" fill="none" stroke="#78cfff" opacity=".4"/><ellipse rx="32" ry="15.36" fill="none" stroke="#78cfff" opacity=".4"/><ellipse rx="46" ry="22.08" fill="none" stroke="#78cfff" opacity=".4"/><path d="M-46 0H46M0 -23V23" fill="none" stroke="#438fff" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round" /><g class="sweep"><path d="M0 0L40 -18" fill="none" stroke="#b8f36c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /><circle cx="34" cy="-15" r="3" stroke="#b8f36c" fill="#b8f36c"/></g><circle cx="-20" cy="8" r="3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="12" cy="13" r="3" stroke="#ffb45e" fill="#ffb45e" class="spark"/><circle cx="23" cy="-8" r="3" stroke="#ffb45e" fill="#ffb45e" class="spark"/></g></g><text x="60" y="311" font-size="13" fill="#b0c2db" text-anchor="start" font-weight="500" >Provision and calibrate</text><path d="M380 229H420M412 221L420 229L412 237" fill="none" stroke="#78cfff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="flow"/><rect x="432" y="120" width="336" height="220" rx="14" fill="#091b35" stroke="#315685"/><text x="456" y="153" font-size="12" fill="#78cfff" text-anchor="start" font-weight="500" >02</text><text x="456" y="188" font-size="26" fill="#f3f7ff" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Extract context</text><text x="456" y="216" font-size="15" fill="#b0c2db" text-anchor="start" font-weight="500" >Signal processing and models</text><g transform="translate(701 278) scale(0.35)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0b1b35" stroke="#2e5b8e"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#4473a5"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#438fff" fill-opacity=".12" stroke="#78cfff" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#438fff" fill="#438fff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#438fff" fill="#438fff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#438fff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#9ee7ff"/></g><ellipse cx="0" cy="36" rx="85" ry="28" fill="none" stroke="#438fff" class="wave"/></g><g transform="translate(701 270) scale(0.5)"><ellipse cy="53" rx="48" ry="8" fill="#020816" opacity=".65"/><g class="float"><path d="M-49 -14C-34 -14 -30 -35 -17 -35S0 7 14 7S34 -14 49 -14" fill="none" stroke="#78cfff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="trace" style="animation-delay:-0s" opacity="1.0"/><path d="M-49 -2C-34 -2 -30 -23 -17 -23S0 19 14 19S34 -2 49 -2" fillLine truncated
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="396" viewBox="0 0 1200 396" role="img" aria-labelledby="title desc"><title id="title">RuView sensing overview</title><desc id="desc">Conceptual sequence: capture RF, extract context, act locally. Links to architecture and user documentation.</desc><defs><linearGradient id="wash" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#0b303a"/><stop offset=".55" stop-color="#06171e"/><stop offset="1" stop-color="#030c13"/></linearGradient><linearGradient id="accent"><stop stop-color="#91f6df"/><stop offset="1" stop-color="#26bad7"/></linearGradient><radialGradient id="halo"><stop stop-color="#35d4db" stop-opacity=".17"/><stop offset="1" stop-color="#35d4db" stop-opacity="0"/></radialGradient></defs><style>
|
||||
text{font-family:"Avenir Next","Segoe UI",Helvetica,Arial,sans-serif}
|
||||
.mono{font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;letter-spacing:1.6px}
|
||||
.float{animation:float 5s ease-in-out infinite}
|
||||
.flow{stroke-dasharray:5 12;animation:flow 5s linear infinite}
|
||||
.breathe{animation:breathe 4s ease-in-out infinite}
|
||||
.trace{stroke-dasharray:400;animation:trace 6s ease-in-out infinite}
|
||||
.scan{animation:scan 7s ease-in-out infinite}
|
||||
.orbit{transform-box:fill-box;transform-origin:center;animation:orbit 18s linear infinite}
|
||||
.spark{animation:spark 3.5s ease-in-out infinite}
|
||||
@keyframes float{0%,100%{transform:translate(0,0)}50%{transform:translate(3px,-10px)}}
|
||||
@keyframes scan{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
|
||||
@keyframes orbit{to{transform:rotate(360deg)}}
|
||||
@keyframes spark{50%{opacity:.25}}
|
||||
@keyframes flow{to{stroke-dashoffset:-136}}
|
||||
@keyframes breathe{50%{opacity:.4}}
|
||||
@keyframes trace{0%,100%{stroke-dashoffset:0}50%{stroke-dashoffset:90}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}}
|
||||
</style><rect x=".5" y=".5" width="1199" height="395" rx="18" fill="url(#wash)" stroke="#245360"/><text x="36" y="44" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" class="mono">SIGNAL TO CONTEXT</text><text x="36" y="89" font-size="34" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >A sensing loop you can inspect.</text><rect x="36" y="120" width="336" height="220" rx="14" fill="#071b23" stroke="#285360"/><text x="60" y="153" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" >01</text><text x="60" y="188" font-size="26" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Capture RF</text><text x="60" y="216" font-size="15" fill="#9abac5" text-anchor="start" font-weight="500" >CSI from supported hardware</text><g transform="translate(305 278) scale(0.35)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><g transform="translate(305 270) scale(0.5)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-10.4 -5.2Q0 -18.2 10.4 -5.2" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="breathe" style="animation-delay:-0.65s"/><path d="M-20.0 -10.0Q0 -35.0 20.0 -10.0" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="breathe" style="animation-delay:-1.25s"/><path d="M-30.400000000000002 -15.200000000000001Q0 -53.199999999999996 30.400000000000002 -15.200000000000001" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="breathe" style="animation-delay:-1.9s"/><circle cx="0" cy="20" r="4" stroke="#72eee0" fill="#72eee0"/><path d="M0 12V-1" fill="none" stroke="#72eee0" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /></g></g><text x="60" y="311" font-size="13" fill="#9abac5" text-anchor="start" font-weight="500" >Provision and calibrate</text><path d="M380 229H420M412 221L420 229L412 237" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="flow"/><rect x="432" y="120" width="336" height="220" rx="14" fill="#071b23" stroke="#285360"/><text x="456" y="153" font-size="12" fill="#72eee0" text-anchor="start" font-weight="500" >02</text><text x="456" y="188" font-size="26" fill="#ecfafb" text-anchor="start" font-weight="650" letter-spacing="-0.6" >Extract context</text><text x="456" y="216" font-size="15" fill="#9abac5" text-anchor="start" font-weight="500" >Signal processing and models</text><g transform="translate(701 278) scale(0.35)"><path d="M-82 36L0 -6L82 36L0 78Z" fill="#0a2733" stroke="#286171"/><path d="M-82 36V-52L0 -94L82 -52V36M-82 -52L0 -10L82 -52M0 -10V78" fill="none" stroke="#366d80"/><g class="scan"><path d="M-81 32L0 -10L81 32L0 74Z" fill="#5fe3d8" fill-opacity=".12" stroke="#72eee0" stroke-opacity=".7"/></g><circle cx="-40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="-15" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="40" cy="6" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="-20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="20" cy="30" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><circle cx="0" cy="49" r="2" stroke="#70b6ff" fill="#70b6ff" class="spark"/><g class="orbit"><ellipse cx="0" cy="4" rx="102" ry="30" fill="none" stroke="#70b6ff" stroke-opacity=".4" stroke-dasharray="2 8"/><circle cx="102" cy="4" r="4" fill="#91f6df"/></g></g><g transform="translate(701 270) scale(0.5)"><ellipse cx="0" cy="48" rx="43" ry="12" fill="#133a45" opacity=".5"/><path d="M-43 48L0 27L43 48L0 69Z" fill="none" stroke="#285c68" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" /><g class="float"><path d="M-42 6H-27L-18 -10L-9 25L3 -25L14 10L24 -3L31 6H43" fill="none" stroke="#72eee0" stroke-width="2" stroke-linecap="round" stroke-linejoin="roundLine truncated
|
||||
|
After Width: | Height: | Size: 9.3 KiB |
@@ -0,0 +1,87 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="360" viewBox="0 0 960 540" role="img" aria-labelledby="title desc">
|
||||
<title id="title">RuView · WiFi becomes spatial awareness.</title><desc id="desc">RuView-focused animation showing WiFi sensors, spatial perception, Ruflo coordination and an illustrative ruOS sensing workspace. Room occupancy and actions are synthetic examples, not live measurements.</desc>
|
||||
<defs><radialGradient id="bg"><stop stop-color="#151518" /><stop offset="1" stop-color="#07080b" /></radialGradient><radialGradient id="aura"><stop stop-color="#edc65a" stop-opacity=".23" /><stop offset=".4" stop-color="#ba8823" stop-opacity=".07" /><stop offset="1" stop-color="#ba8823" stop-opacity="0" /></radialGradient><linearGradient id="gold" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#fff4b1" /><stop offset=".5" stop-color="#ebc456" /><stop offset="1" stop-color="#96702f" /></linearGradient><linearGradient id="panel" x2="0" y2="1"><stop stop-color="#191a20" /><stop offset="1" stop-color="#0d0e13" /></linearGradient><pattern id="grid" width="36" height="36" patternUnits="userSpaceOnUse"><circle cx="18" cy="18" r=".65" fill="#d4c78e" opacity=".22" /></pattern><filter id="bloom" x="-100%" y="-100%" width="300%" height="300%"><feGaussianBlur stdDeviation="4" /></filter><clipPath id="frame"><rect width="960" height="540" rx="18" /></clipPath><clipPath id="line1"><rect x="64" y="155" width="850" height="93" /></clipPath><clipPath id="line2"><rect x="64" y="244" width="850" height="100" /></clipPath><g id="crown" fill="url(#gold)"><path d="M0 5l8 7L15 0l7 12 8-7-4 23H4z" /><rect x="4" y="31" width="22" height="3" rx="1" /></g>
|
||||
<style>
|
||||
text{font-family:Arial,Helvetica,sans-serif;fill:#f4f2ed}.mono{font-family:monospace}.muted{fill:#888993}.gold{fill:#e8c565}.scene{opacity:0}.end{opacity:1}.wire{fill:none;stroke:#c2a155;stroke-width:1}.all{animation-duration:18s;animation-iteration-count:infinite;animation-timing-function:cubic-bezier(.22,.65,.3,1)}
|
||||
@keyframes intro{0%,17%{opacity:1;transform:translateY(0)}22%,94%{opacity:0;transform:translateY(-12px)}100%{opacity:1;transform:translateY(0)}}
|
||||
@keyframes network{0%,20%{opacity:0;transform:translateY(18px) scale(.98)}25%,44%{opacity:1;transform:translateY(0) scale(1)}49%,100%{opacity:0;transform:translateY(-15px) scale(1.02)}}
|
||||
@keyframes work{0%,46%{opacity:0;transform:translateY(18px)}51%,66%{opacity:1;transform:translateY(0)}71%,100%{opacity:0;transform:translateY(-14px)}}
|
||||
@keyframes finale{0%,69%{opacity:0}74%,92%{opacity:1}97%,100%{opacity:0}}
|
||||
.intro{animation-name:intro}.network{animation-name:network;transform-origin:480px 270px}.work{animation-name:work}.end{animation-name:finale}
|
||||
@keyframes reveal1{0%,69%{transform:translateY(100px)}77%,100%{transform:translateY(0)}}@keyframes reveal2{0%,73%{transform:translateY(110px)}81%,100%{transform:translateY(0)}}.headline1{animation-name:reveal1}.headline2{animation-name:reveal2}
|
||||
@keyframes breathe{50%{opacity:.6;transform:scale(1.12)}}.breathe{animation:breathe 4.5s ease-in-out infinite;transform-origin:480px 239px}
|
||||
@keyframes spin{to{transform:rotate(360deg)}}.orbit{animation:spin 18s linear infinite;transform-origin:480px 239px}
|
||||
@keyframes send{0%,9%{transform:translate(0,0)}14%,100%{transform:translate(-14px,-19px)}}.cursor{animation-name:send}
|
||||
@keyframes type{0%,2%{clip-path:inset(0 100% 0 0)}12%,100%{clip-path:inset(0 0 0 0)}}.typing{animation-name:type;animation-timing-function:steps(26,end)}
|
||||
@keyframes task{0%,49%{transform:translateY(25px);opacity:0}55%,100%{transform:translateY(0);opacity:1}}.task{animation-name:task}.task2{animation-delay:.3s}.task3{animation-delay:.6s}
|
||||
@keyframes grow{0%,54%{transform:scaleX(0)}63%,100%{transform:scaleX(1)}}.grow{animation-name:grow;transform-box:fill-box;transform-origin:left}
|
||||
@keyframes tick{0%,62%{opacity:0}65%,100%{opacity:1}}.tick{animation-name:tick}
|
||||
@keyframes trace{0%,22%{stroke-dashoffset:1}38%,100%{stroke-dashoffset:0}}.trace{stroke-dasharray:1;animation-name:trace}
|
||||
@keyframes drift{50%{transform:translateY(-10px);opacity:.8}}.dust{animation:drift 9s ease-in-out infinite}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important}.scene{opacity:0}.end{opacity:1}.moving{display:none}}
|
||||
|
||||
@keyframes signal{0%,13%{transform:translate(480px,205px)}20%{transform:translate(708px,301px)}26%,43%{transform:translate(480px,239px)}49%{transform:translate(215px,155px)}55%{transform:translate(479px,155px)}61%{transform:translate(743px,155px)}72%,93%{transform:translate(782px,307px)}100%{transform:translate(480px,205px)}}
|
||||
.signal{animation-name:signal}.signal-glow{animation:shimmer 3s ease-in-out infinite}@keyframes shimmer{50%{opacity:.45}}
|
||||
@keyframes haloExpand{0%,12%{opacity:0;transform:scale(.5)}16%{opacity:.7}23%,100%{opacity:0;transform:scale(2.5)}}.clickring{animation-name:haloExpand;transform-origin:708px 301px}
|
||||
@keyframes aurora{0%,100%{transform:translate(-30px,10px) rotate(-4deg)}50%{transform:translate(30px,-10px) rotate(4deg)}}.aurora{animation:aurora 18s ease-in-out infinite;transform-origin:480px 270px}
|
||||
@keyframes dash{to{stroke-dashoffset:-80}}.stream{stroke-dasharray:2 18;animation:dash 3s linear infinite}
|
||||
@keyframes count{0%,52%{opacity:0;transform:translateY(8px)}58%,100%{opacity:1;transform:translateY(0)}}.detail{animation-name:count}
|
||||
@keyframes buildLine{0%,51%{stroke-dashoffset:1}64%,100%{stroke-dashoffset:0}}.buildLine{stroke-dasharray:1;animation-name:buildLine}
|
||||
@keyframes underline{0%,78%{transform:scaleX(0)}85%,100%{transform:scaleX(1)}}.underline{animation-name:underline;transform-origin:66px 350px}
|
||||
@keyframes dock{0%,49%{opacity:0;transform:translateY(14px)}55%,100%{opacity:1;transform:translateY(0)}}.dock{animation-name:dock}
|
||||
@media(prefers-reduced-motion:reduce){.signal,.clickring{display:none}}
|
||||
|
||||
@keyframes vortexCW{to{transform:rotate(360deg)}}@keyframes vortexCCW{to{transform:rotate(-360deg)}}
|
||||
.vortex{transform-origin:480px 270px;animation:vortexCW 36s linear infinite}.counter{transform-origin:480px 270px;animation:vortexCCW 54s linear infinite}
|
||||
@keyframes current{to{stroke-dashoffset:-1200}}.current{animation:current 9s linear infinite}
|
||||
@keyframes bgEnergy{0%,12%,100%{opacity:.22}22%,40%{opacity:.6}52%,65%{opacity:.4}74%,84%{opacity:.7}94%{opacity:.28}}.bgEnergy{animation:bgEnergy 18s ease-in-out infinite}
|
||||
@keyframes wave{0%{opacity:0;transform:scale(.3)}20%{opacity:.35}80%{opacity:.07}100%{opacity:0;transform:scale(1.9)}}.wave{transform-origin:480px 270px;animation:wave 9s cubic-bezier(.15,.35,.5,1) infinite}
|
||||
@keyframes glimmer{0%,100%{opacity:.08}50%{opacity:.72}}.glimmer{animation:glimmer 6s ease-in-out infinite}
|
||||
@keyframes comet{0%{opacity:0;transform:translate(-160px,70px)}12%{opacity:.65}58%{opacity:.25}75%,100%{opacity:0;transform:translate(1060px,-300px)}}.comet{animation:comet 9s linear infinite}
|
||||
@keyframes beam{0%,100%{transform:translate(-150px,0) rotate(-12deg);opacity:0}35%{opacity:.18}65%{opacity:.07;transform:translate(1050px,0) rotate(-12deg)}80%{opacity:0}}.beam{animation:beam 18s ease-in-out infinite;transform-origin:center}
|
||||
@media(prefers-reduced-motion:reduce){.dynamic-bg{display:none}}
|
||||
|
||||
.all{animation-duration:24s}
|
||||
@keyframes work{0%,46%{opacity:0;transform:translateY(18px)}50%,72%{opacity:1;transform:translateY(0)}76%,100%{opacity:0;transform:translateY(-14px)}}
|
||||
@keyframes finale{0%,75%{opacity:0}79%,93%{opacity:1}97%,100%{opacity:0}}
|
||||
@keyframes reveal1{0%,75%{transform:translateY(100px)}82%,100%{transform:translateY(0)}}
|
||||
@keyframes reveal2{0%,78%{transform:translateY(110px)}85%,100%{transform:translateY(0)}}
|
||||
@keyframes signal{0%,13%{transform:translate(480px,205px)}20%{transform:translate(708px,301px)}26%,43%{transform:translate(480px,239px)}49%{transform:translate(803px,182px)}55%{transform:translate(803px,235px)}63%,72%{transform:translate(803px,288px)}80%,93%{transform:translate(782px,307px)}100%{transform:translate(480px,205px)}}
|
||||
@keyframes browserOpen{0%,48%{opacity:0;transform:translateY(20px) scale(.96)}53%,100%{opacity:1;transform:translateY(0) scale(1)}}.browserOpen{animation-name:browserOpen;transform-origin:380px 230px}
|
||||
@keyframes terminalOpen{0%,53%{opacity:0;transform:translateY(14px)}58%,100%{opacity:1;transform:translateY(0)}}.terminalOpen{animation-name:terminalOpen}
|
||||
@keyframes terminalText{0%,57%{opacity:0}60%,100%{opacity:1}}.terminalText{animation-name:terminalText}
|
||||
@keyframes done{0%,65%{opacity:0}69%,100%{opacity:1}}.done{animation-name:done}
|
||||
@keyframes pointerMove{0%,50%{transform:translate(350px,275px)}55%{transform:translate(529px,267px)}59%{transform:translate(570px,325px)}66%,100%{transform:translate(738px,346px)}}.desktopPointer{animation-name:pointerMove}
|
||||
@keyframes chartGrow{0%,53%{transform:scaleY(.05)}63%,100%{transform:scaleY(1)}}.chartGrow{animation-name:chartGrow;transform-box:fill-box;transform-origin:bottom}
|
||||
</style><radialGradient id="readability"><stop stop-color="#08090e" stop-opacity=".58" /><stop offset=".65" stop-color="#08090e" stop-opacity=".38" /><stop offset="1" stop-color="#08090e" stop-opacity="0" /></radialGradient><linearGradient id="beamGold"><stop stop-color="#e7bf56" stop-opacity="0" /><stop offset=".5" stop-color="#efd57f" stop-opacity=".45" /><stop offset="1" stop-color="#e7bf56" stop-opacity="0" /></linearGradient></defs><g clip-path="url(#frame)"><rect width="960" height="540" fill="url(#bg)" /><rect width="960" height="540" fill="url(#grid)" opacity=".35" /><ellipse cx="490" cy="250" rx="460" ry="320" fill="url(#aura)" />
|
||||
<g><g class="aurora" fill="none" stroke="#c6a457" opacity=".11"><ellipse cx="480" cy="260" rx="470" ry="156" transform="rotate(-18 480 260)" /><ellipse cx="480" cy="260" rx="480" ry="166" transform="rotate(-18 480 260)" /><ellipse cx="480" cy="260" rx="495" ry="180" transform="rotate(-18 480 260)" /></g></g><g><g class="dynamic-bg"><g class="bgEnergy"><rect class="beam" x="0" y="-120" width="160" height="850" fill="url(#beamGold)" /><ellipse cx="480" cy="270" rx="280" ry="150" fill="none" stroke="#dcb55e" stroke-width=".9" class="wave" style="animation-delay:-0s" /><ellipse cx="480" cy="270" rx="280" ry="150" fill="none" stroke="#dcb55e" stroke-width=".9" class="wave" style="animation-delay:-3s" /><ellipse cx="480" cy="270" rx="280" ry="150" fill="none" stroke="#dcb55e" stroke-width=".9" class="wave" style="animation-delay:-6s" /><g class="vortex" fill="none"><ellipse cx="480" cy="270" rx="355" ry="160" transform="rotate(0 480 270)" stroke="#b89342" stroke-width=".6" opacity=".3" /><ellipse cx="480" cy="270" rx="355" ry="160" transform="rotate(0 480 270)" stroke="#f7d884" stroke-width="2" stroke-dasharray="18 6 4 420 65 800" class="current" style="animation-delay:-0.0s" opacity=".65" /><ellipse cx="480" cy="270" rx="392" ry="184" transform="rotate(19 480 270)" stroke="#b89342" stroke-width=".6" opacity=".3" /><ellipse cx="480" cy="270" rx="392" ry="184" transform="rotate(19 480 270)" stroke="#f7d884" stroke-width="1.2" stroke-dasharray="18 6 4 420 65 800" class="current" style="animation-delay:-1.5s" opacity=".65" /><ellipse cx="480" cy="270" rx="429" ry="208" transform="rotate(38 480 270)" stroke="#b89342" stroke-width=".6" opacity=".3" /><ellipse cx="480" cy="270" rx="429" ry="208" transform="rotate(38 480 270)" stroke="#f7d884" stroke-width="2" stroke-dasharray="18 6 4 420 65 800" class="current" style="animation-delay:-3.0s" opacity=".65" /><ellipse cx="480" cy="270" rx="466" ry="232" transform="rotate(57 480 270)" stroke="#b89342" stroke-width=".6" opacity=".3" /><ellipse cx="480" cy="270" rx="466" ry="232" transform="rotate(57 480 270)" stroke="#f7d884" stroke-width="1.2" stroke-dasharray="18 6 4 420 65 800" class="current" style="animation-delay:-4.5s" opacity=".65" /><ellipse cx="480" cy="270" rx="503" ry="256" transform="rotate(76 480 270)" stroke="#b89342" stroke-width=".6" opacity=".3" /><ellipse cx="480" cy="270" rx="503" ry="256" transform="rotate(76 480 270)" stroke="#f7d884" stroke-width="2" stroke-dasharray="18 6 4 420 65 800" class="current" style="animation-delay:-6.0s" opacity=".65" /><ellipse cx="480" cy="270" rx="540" ry="280" transform="rotate(95 480 270)" stroke="#b89342" stroke-width=".6" opacity=".3" /><ellipse cx="480" cy="270" rx="540" ry="280" transform="rotate(95 480 270)" stroke="#f7d884" stroke-width="1.2" stroke-dasharray="18 6 4 420 65 800" class="current" style="animation-delay:-7.5s" opacity=".65" /></g><g class="counter" fill="none"><ellipse cx="480" cy="270" rx="355" ry="160" transform="rotate(0 480 270)" stroke="#b89342" stroke-width=".6" opacity=".3" /><ellipse cx="480" cy="270" rx="355" ry="160" transform="rotate(0 480 270)" stroke="#f7d884" stroke-width="2" stroke-dasharray="18 6 4 420 65 800" class="current" style="animation-delay:-0.0s" opacity=".65" /><ellipse cx="480" cy="270" rx="392" ry="184" transform="rotate(-19 480 270)" stroke="#b89342" stroke-width=".6" opacity=".3" /><ellipse cx="480" cy="270" rx="392" ry="184" transform="rotate(-19 480 270)" stroke="#f7d884" stroke-width="1.2" stroke-dasharray="18 6 4 420 65 800" class="current" style="animation-delay:-1.5s" opacity=".65" /><ellipse cx="480" cy="270" rx="429" ry="208" transform="rotate(-38 480 270)" stroke="#b89342" stroke-width=".6" opacity=".3" /><ellipse cx="480" cy="270" rx="429" ry="208" transform="rotate(-38 480 270)" stroke="#f7d884" stroke-width="2" stroke-dasharray="18 6 4 420 65 800" class="current" style="animation-delay:-3.0s" opacity=".65" /><ellipse cx="480" cy="270" rx="466" ry="232" transform="rotate(-57 480 270)" stroke="#b89342" stroke-width=".6" opacity=".3" /><ellipse cx="480" cy="270" rx="466" ry="232" transform="rotate(-57 480 270)" stroke="#f7d884" stroke-width="1.2" stroke-dasharray="18 6 4 420 65 800" class="current" style="animation-delay:-4.5s" opacity=".65" /><ellipse cx="480" cy="270" rx="503" ry="256" transform="rotate(-76 480 270)" stroke="#b89342" stroke-width=".6" opacity=".3" /><ellipse cx="480" cy="270" rx="503" ry="256" transform="rotate(-76 480 270)" stroke="#f7d884" stroke-width="2" stroke-dasharray="18 6 4 420 65 800" class="current" style="animation-delay:-6.0s" opacity=".65" /><ellipse cx="480" cy="270" rx="540" ry="280" transform="rotate(-95 480 270)" stroke="#b89342" stroke-width=".6" opacity=".3" /><ellipse cx="480" cy="270" rx="540" ry="280" transform="rotate(-95 480 270)" stroke="#f7d884" stroke-width="1.2" stroke-dasharray="18 6 4 420 65 800" class="current" style="animation-delay:-7.5s" opacity=".65" /></g><circle cx="10.1" cy="303.9" r="1.3" fill="#ffe4a0Line truncated
|
||||
<g class="scene intro all"><circle cx="480" cy="205" r="125" fill="url(#aura)" /><circle cx="480" cy="205" r="28" stroke="#f3d576" stroke-width="1" fill="none" /><text x="480" y="126" text-anchor="middle" font-size="32" letter-spacing="-1">Your room is already sending signals.</text>
|
||||
<rect x="215" y="269" width="530" height="64" rx="12" fill="url(#panel)" stroke="#554b31" /><text x="239" y="307" font-size="17" class="mono typing all">Sense. Understand. Act.</text><rect x="689" y="282" width="38" height="38" rx="9" fill="url(#gold)" /><path d="M708 307v-13m-5 5 5-5 5 5" fill="none" stroke="#222018" stroke-width="2" stroke-linecap="round" />
|
||||
<path class="cursor all" d="M731 323l0 27 7-8 8 1z" fill="#faf8e7" stroke="#151515" stroke-width="1.4" />
|
||||
<text x="480" y="382" text-anchor="middle" font-size="11" letter-spacing="3" class="mono muted">WIFI SENSING. NO CAMERAS.</text><g><circle class="clickring all" cx="708" cy="301" r="25" fill="none" stroke="#fae29b" /></g><g><g fill="none" stroke="#e7c467" opacity=".65"><path d="M437 214Q480 161 523 214" /><path d="M420 205Q480 133 540 205" opacity=".4" /><path d="M404 196Q480 108 556 196" opacity=".2" /></g></g></g>
|
||||
<g class="scene network all"><text x="480" y="107" text-anchor="middle" font-size="30" letter-spacing="-.7">From radio signals to useful actions.</text>
|
||||
<g><path d="M480 239C548 323 639 357 735 350" class="stream" fill="none" stroke="#f1d98f" stroke-width="1.5" opacity=".45" /></g><g><path d="M480 239C420 328 311 358 225 350" class="stream" fill="none" stroke="#f1d98f" stroke-width="1.5" opacity=".45" /></g><g><path d="M480 239C520 143 640 148 714 193" class="stream" fill="none" stroke="#f1d98f" stroke-width="1.5" opacity=".45" /></g><g><path d="M480 239C440 148 322 143 247 193" class="stream" fill="none" stroke="#f1d98f" stroke-width="1.5" opacity=".45" /></g><path d="M480 239C440 148 322 143 247 193" class="wire" opacity=".2" /><path d="M480 239C440 148 322 143 247 193" class="wire trace all" pathLength="1" /><g class="moving"><circle r="7" fill="#f6cf63" opacity=".5" filter="url(#bloom)"><animateMotion path="M480 239C440 148 322 143 247 193" dur="2.4s" begin="-0.0s" repeatCount="indefinite" /></circle><circle r="2.6" fill="#ffeaa1"><animateMotion path="M480 239C440 148 322 143 247 193" dur="2.4s" begin="-0.0s" repeatCount="indefinite" /></circle></g><g class="moving"><circle r="7" fill="#f6cf63" opacity=".5" filter="url(#bloom)"><animateMotion path="M480 239C440 148 322 143 247 193" dur="2.4s" begin="-1.2s" repeatCount="indefinite" /></circle><circle r="2.6" fill="#ffeaa1"><animateMotion path="M480 239C440 148 322 143 247 193" dur="2.4s" begin="-1.2s" repeatCount="indefinite" /></circle></g><path d="M480 239C520 143 640 148 714 193" class="wire" opacity=".2" /><path d="M480 239C520 143 640 148 714 193" class="wire trace all" pathLength="1" /><g class="moving"><circle r="7" fill="#f6cf63" opacity=".5" filter="url(#bloom)"><animateMotion path="M480 239C520 143 640 148 714 193" dur="2.4s" begin="-0.2s" repeatCount="indefinite" /></circle><circle r="2.6" fill="#ffeaa1"><animateMotion path="M480 239C520 143 640 148 714 193" dur="2.4s" begin="-0.2s" repeatCount="indefinite" /></circle></g><g class="moving"><circle r="7" fill="#f6cf63" opacity=".5" filter="url(#bloom)"><animateMotion path="M480 239C520 143 640 148 714 193" dur="2.4s" begin="-1.4s" repeatCount="indefinite" /></circle><circle r="2.6" fill="#ffeaa1"><animateMotion path="M480 239C520 143 640 148 714 193" dur="2.4s" begin="-1.4s" repeatCount="indefinite" /></circle></g><path d="M480 239C420 328 311 358 225 350" class="wire" opacity=".2" /><path d="M480 239C420 328 311 358 225 350" class="wire trace all" pathLength="1" /><g class="moving"><circle r="7" fill="#f6cf63" opacity=".5" filter="url(#bloom)"><animateMotion path="M480 239C420 328 311 358 225 350" dur="2.4s" begin="-0.4s" repeatCount="indefinite" /></circle><circle r="2.6" fill="#ffeaa1"><animateMotion path="M480 239C420 328 311 358 225 350" dur="2.4s" begin="-0.4s" repeatCount="indefinite" /></circle></g><g class="moving"><circle r="7" fill="#f6cf63" opacity=".5" filter="url(#bloom)"><animateMotion path="M480 239C420 328 311 358 225 350" dur="2.4s" begin="-1.6s" repeatCount="indefinite" /></circle><circle r="2.6" fill="#ffeaa1"><animateMotion path="M480 239C420 328 311 358 225 350" dur="2.4s" begin="-1.6s" repeatCount="indefinite" /></circle></g><path d="M480 239C548 323 639 357 735 350" class="wire" opacity=".2" /><path d="M480 239C548 323 639 357 735 350" class="wire trace all" pathLength="1" /><g class="moving"><circle r="7" fill="#f6cf63" opacity=".5" filter="url(#bloom)"><animateMotion path="M480 239C548 323 639 357 735 350" dur="2.4s" begin="-0.6000000000000001s" repeatCount="indefinite" /></circle><circle r="2.6" fill="#ffeaa1"><animateMotion path="M480 239C548 323 639 357 735 350" dur="2.4s" begin="-0.6000000000000001s" repeatCount="indefinite" /></circle></g><g class="moving"><circle r="7" fill="#f6cf63" opacity=".5" filter="url(#bloom)"><animateMotion path="M480 239C548 323 639 357 735 350" dur="2.4s" begin="-1.8s" repeatCount="indefinite" /></circle><circle r="2.6" fill="#ffeaa1"><animateMotion path="M480 239C548 323 639 357 735 350" dur="2.4s" begin="-1.8s" repeatCount="indefinite" /></circle></g><circle cx="480" cy="239" r="98" fill="url(#aura)" class="breathe" /><circle cx="480" cy="239" r="57" fill="#111115" stroke="#6c5830" /><circle cx="480" cy="239" r="66" fill="none" stroke="#eac55e" stroke-opacity=".6" stroke-dasharray="38 170" class="orbit" /><use href="#crown" transform="translate(465 221)" /><rect x="147" y="169" width="200" height="55" rx="10" fill="url(#panel)" stroke="#51462e" /><circle cx="164" cy="191" r="3" fill="#e8c667" /><text x="177" y="195" font-size="18">WiFi sensors</text><text x="177" y="212" font-size="8" class="mono muted" letter-spacing="1.8">CAPTURE</text><rect x="614" y="169" width="200" height="55" rx="10" fill="url(#panel)" stroke="#51462e" /><circle cx="631" cy="191" r="3" fill="#e8c667" /><text x="644" y="195" font-size="18">RuView</text><text x="644" y="212" font-size="8" class="mono muted" letter-spacing="1.8">PERCEIVE</text><rect x="125" y="326" width="200" height="55" rx="10" fill="url(#panel)" stroke="#51462e" /><circle cx="142" cy="348" r="3" fill="#e8c667" /><text x="155" y="352" font-sizeLine truncated
|
||||
<g class="scene work all"><g><text x="480" y="92" text-anchor="middle" font-size="28" letter-spacing="-.6">A sensing workspace, powered by RuView.</text>
|
||||
<rect x="58" y="113" width="844" height="331" rx="12" fill="#090c12" stroke="#6a5931" />
|
||||
<path d="M70 144H890" stroke="#292b31" /><circle cx="76" cy="129" r="3" fill="#dcbf65" /><circle cx="87" cy="129" r="3" fill="#5b5c64" /><circle cx="98" cy="129" r="3" fill="#5b5c64" /><text x="480" y="133" text-anchor="middle" class="mono muted" font-size="9">ruOS / Desktops / ruview-workspace</text>
|
||||
<rect x="59" y="145" width="125" height="287" fill="#0c0e13" />
|
||||
<use href="#crown" transform="translate(72 158) scale(.4)" /><text x="91" y="170" font-size="15" font-weight="700">ruOS</text>
|
||||
<rect x="67" y="209" width="107" height="25" rx="5" fill="#302819" stroke="#63512c" />
|
||||
<rect x="76" y="194" width="7" height="6" rx="1" fill="none" stroke="#686b79" /><text x="91" y="201" font-size="10" class="muted">Overview</text><rect x="76" y="222" width="7" height="6" rx="1" fill="none" stroke="#e1c577" /><text x="91" y="229" font-size="10" class="gold">Desktops</text><rect x="76" y="250" width="7" height="6" rx="1" fill="none" stroke="#686b79" /><text x="91" y="257" font-size="10" class="muted">Terminal</text><rect x="76" y="278" width="7" height="6" rx="1" fill="none" stroke="#686b79" /><text x="91" y="285" font-size="10" class="muted">Swarms</text><rect x="76" y="306" width="7" height="6" rx="1" fill="none" stroke="#686b79" /><text x="91" y="313" font-size="10" class="muted">Network</text><rect x="76" y="334" width="7" height="6" rx="1" fill="none" stroke="#686b79" /><text x="91" y="341" font-size="10" class="muted">Usage</text><rect x="76" y="362" width="7" height="6" rx="1" fill="none" stroke="#686b79" /><text x="91" y="369" font-size="10" class="muted">Settings</text><text x="200" y="169" font-size="14" font-weight="700">RuView workspace</text><circle cx="364" cy="165" r="3" fill="#b9cb91" /><text x="374" y="169" font-size="9" class="muted">Running</text>
|
||||
<text x="882" y="167" text-anchor="end" font-size="8" class="mono gold">SYNTHETIC DEMO</text>
|
||||
<rect x="197" y="183" width="469" height="244" rx="7" fill="#14131a" stroke="#32313d" /><path d="M197 373Q370 180 666 285M197 330Q440 390 666 210" fill="none" stroke="#b49548" opacity=".18" />
|
||||
<g class="browserOpen all"><rect x="209" y="195" width="308" height="163" rx="7" fill="#191d26" stroke="#5a5961" />
|
||||
<rect x="209" y="195" width="308" height="24" rx="7" fill="#262a33" /><text x="221" y="211" font-size="8" class="mono muted">RuView / Room overview</text><circle cx="503" cy="207" r="2" fill="#e3c477" />
|
||||
<text x="225" y="241" font-size="13" font-weight="700">Room activity</text><text x="225" y="257" font-size="9" class="muted">Synthetic scene · Presence and motion</text>
|
||||
<rect x="224" y="329" width="83" height="16" rx="4" fill="#4a3d22" /><text x="233" y="340" font-size="8" class="gold">Sensor connected</text><g><path d="M229 270H494V318H229zM390 270v18m0 12v18" fill="#121921" stroke="#727781" stroke-width="1.5" /><path d="M235 278h34v15h-34zM464 280h22v24h-22z" fill="#303843" stroke="#707786" /><circle cx="285" cy="300" r="4" fill="#f0cd70" /><circle cx="285" cy="300" r="16" fill="none" stroke="#d8b353" opacity=".4" /><circle cx="326" cy="287" r="5" fill="#b7cbd0" /><path d="M326 293v12m-7-8h14m-7 8-5 8m5-8 5 8" fill="none" stroke="#b7cbd0" stroke-width="2" /><path d="M292 290Q310 273 326 287M294 306Q312 312 326 302" fill="none" stroke="#e1bd5f" stroke-dasharray="3 5" class="stream" /></g></g>
|
||||
<g class="terminalOpen all"><rect x="366" y="287" width="284" height="117" rx="6" fill="#090c12" stroke="#777061" /><rect x="367" y="288" width="282" height="21" rx="5" fill="#25272f" /><text x="380" y="302" font-size="9" class="mono">Terminal</text>
|
||||
<text x="380" y="324" font-size="9" class="mono gold">› Room event received</text><g class="terminalText all"><text x="380" y="343" font-size="9" class="mono muted">✓ Presence detected (demo)</text><text x="380" y="358" font-size="9" class="mono muted">✓ Rule checked</text></g><text x="380" y="384" font-size="10" class="mono gold done all">✓ Action ready for review</text></g>
|
||||
<rect x="680" y="183" width="207" height="244" rx="7" fill="#12151d" stroke="#33333c" /><text x="695" y="204" font-size="12" font-weight="700">Ruflo agent team</text><path d="M694 216h178" stroke="#34323a" />
|
||||
<circle cx="699" cy="235" r="5" fill="#272317" stroke="#be9f54" /><text x="713" y="239" font-size="11">Sense</text><text x="713" y="254" font-size="8" class="muted">Read room events from RuView</text><circle cx="699" cy="288" r="5" fill="#272317" stroke="#be9f54" /><text x="713" y="292" font-size="11">Evaluate</text><text x="713" y="307" font-size="8" class="muted">Check the configured rule</text><circle cx="699" cy="341" r="5" fill="#272317" stroke="#be9f54" /><text x="713" y="345" font-size="11">Act</text><text x="713" y="360" font-size="8" class="muted">Request an approved action</text><g class="done all"><rect x="693" y="381" width="181" height="29" rx="5" fill="#332b1b" stroke="#89713b" /><text x="784" y="400" text-anchor="middle" font-size="10" class="gold">✓ Room event processed</text></g>
|
||||
<g class="desktopPointer all"><path d="M0 0v20l5-6 8 1z" fill="#fff2ce" stroke="#18181a" stroke-width="1" /></g>
|
||||
<text x="480" y="469" text-anchor="middle" class="gold" font-size="14">Example: room activity → rule check → action review.</text></g></g><g class="scene end all"><ellipse cx="810" cy="290" rx="260" ry="240" fill="url(#aura)" />
|
||||
<text x="66" y="133" class="mono gold" font-size="11" letter-spacing="3">RUVIEW PERCEPTION. RUFLO COORDINATION.</text>
|
||||
<g clip-path="url(#line1)"><text class="headline1 all" x="61" y="233" font-size="72" font-weight="700" letter-spacing="-3">WiFi becomes</text></g>
|
||||
<g clip-path="url(#line2)"><text class="headline2 all" x="61" y="322" font-size="72" font-weight="700" letter-spacing="-3">spatial awareness<tspan class="gold">.</tspan></text></g>
|
||||
<path d="M66 382H894" stroke="#3b3528" /><text x="66" y="420" class="mono gold" font-size="17">ruos.cognitum.one</text><text x="892" y="420" text-anchor="end" font-size="10" class="mono muted" letter-spacing="2">BY COGNITUM</text><g><path class="underline all" d="M66 350h310" stroke="url(#gold)" stroke-width="2" /></g></g>
|
||||
<path d="M40 490H920" stroke="#26242a" /><text x="40" y="513" class="mono muted" font-size="9" letter-spacing="1.5">RUVIEW + RUFLO + RUOS</text><circle cx="853" cy="509" r="2.5" fill="#dfbf67" /><text x="866" y="512" class="mono gold" font-size="9">READY</text><g><g class="signal all"><circle r="45" fill="url(#aura)" class="signal-glow" /><circle r="10" fill="#ebc65d" opacity=".5" filter="url(#bloom)" /><circle r="4.5" fill="#ffe5a1" /><circle r="8" fill="none" stroke="#e9c56c" opacity=".3" /></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 5.5 MiB |
@@ -37,6 +37,31 @@ services:
|
||||
# volumes: ["/path/to/models:/app/models"]
|
||||
# MODELS_DIR=/app/models
|
||||
- MODELS_DIR=${MODELS_DIR:-data/models}
|
||||
# Auth (issue #864). The entrypoint refuses to start (exit 64) unless
|
||||
# RUVIEW_API_TOKEN is set. Export it before `docker compose up`:
|
||||
# export RUVIEW_API_TOKEN=$(openssl rand -hex 32)
|
||||
# Bare names pass the host value through only when it is set.
|
||||
- RUVIEW_API_TOKEN
|
||||
# ESP32 UDP ingest (ADR-296, issue #2089). The UDP receiver defaults to
|
||||
# 127.0.0.1, which cannot receive from the published 5005/udp port.
|
||||
# Set ONE source guard and the entrypoint binds 0.0.0.0:
|
||||
# RUVIEW_UDP_ALLOW=<node-ip-or-cidr> restrict sources (preferred)
|
||||
# RUVIEW_UDP_INSECURE_LAN=true accept the spoofing risk
|
||||
# Docker Desktop and OrbStack on macOS rewrite the source address to the
|
||||
# bridge gateway, so a LAN-subnet allowlist drops every frame. There,
|
||||
# allow the gateway instead:
|
||||
# docker network inspect <project>_default \
|
||||
# --format '{{(index .IPAM.Config 0).Gateway}}'
|
||||
# RUVIEW_UDP_ALLOW=<gateway>/32
|
||||
# The gateway admits anything that reaches the published port, so keep
|
||||
# 5005/udp off untrusted networks.
|
||||
- RUVIEW_UDP_ALLOW
|
||||
- RUVIEW_UDP_INSECURE_LAN
|
||||
- RUVIEW_UDP_BIND
|
||||
# Browsing the UI from another machine also needs the host name or IP
|
||||
# in SENSING_ALLOWED_HOSTS (otherwise 421), and the TCP ports above
|
||||
# published beyond 127.0.0.1.
|
||||
- SENSING_ALLOWED_HOSTS
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
cap_drop:
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
# Default is `auto`. Set CSI_SOURCE=simulated when you want
|
||||
# fake data tagged as such; never set it implicitly.
|
||||
# MODELS_DIR — directory to scan for .rvf model files (default: data/models)
|
||||
# RUVIEW_UDP_ALLOW / RUVIEW_UDP_INSECURE_LAN — ADR-296 UDP source guard.
|
||||
# Setting either makes the entrypoint bind UDP on 0.0.0.0 so
|
||||
# ESP32 frames on the published 5005/udp port can arrive.
|
||||
# RUVIEW_UDP_BIND — explicit UDP bind; overrides the choice above.
|
||||
set -e
|
||||
|
||||
# ── Issue #864: fail-closed on default posture ───────────────────────────────
|
||||
@@ -34,8 +38,8 @@ set -e
|
||||
#
|
||||
# Escape hatches (operator must opt in explicitly):
|
||||
# * Set RUVIEW_API_TOKEN to a strong secret → auth enabled on /api/v1/*.
|
||||
# * Set RUVIEW_ALLOW_UNAUTHENTICATED=1 → preserves the pre-fix behaviour;
|
||||
# only safe on an isolated trust boundary.
|
||||
# * Set RUVIEW_ALLOW_UNAUTHENTICATED=1 (or true/yes/on, any case) →
|
||||
# preserves the pre-fix behaviour; only safe on an isolated trust boundary.
|
||||
# * Set RUVIEW_BIND_ADDR to a loopback / private interface → unauth is fine
|
||||
# when the socket isn't reachable. The auto-bind nudges toward 127.0.0.1.
|
||||
#
|
||||
@@ -45,7 +49,12 @@ set -e
|
||||
case "${1:-}" in
|
||||
cog-ha-matter|ha-matter|homecore|homecore-server) ;;
|
||||
*)
|
||||
if [ -z "${RUVIEW_API_TOKEN:-}" ] && [ "${RUVIEW_ALLOW_UNAUTHENTICATED:-}" != "1" ]; then
|
||||
# Same spellings the sensing-server accepts for its boolean env flags.
|
||||
case "${RUVIEW_ALLOW_UNAUTHENTICATED:-}" in
|
||||
1|[Tt][Rr][Uu][Ee]|[Yy][Ee][Ss]|[Oo][Nn]) __allow_unauth=1 ;;
|
||||
*) __allow_unauth=0 ;;
|
||||
esac
|
||||
if [ -z "${RUVIEW_API_TOKEN:-}" ] && [ "$__allow_unauth" != "1" ]; then
|
||||
# If the operator hasn't overridden the bind, refuse outright on
|
||||
# the default 0.0.0.0. If they've nailed it to loopback (or a
|
||||
# specific private address they trust), let it run.
|
||||
@@ -97,6 +106,50 @@ esac
|
||||
# server binary so users can just pass flags:
|
||||
# docker run <image> --source esp32 --tick-ms 500
|
||||
if [ "${1#-}" != "$1" ] || [ -z "$1" ]; then
|
||||
# ── Issue #2089: UDP CSI ingest posture inside a container ───────────────
|
||||
# ADR-296 defaults the UDP receiver to 127.0.0.1. Inside a container that
|
||||
# bind can never receive from a published port, so no node ever appears.
|
||||
# We bind 0.0.0.0 only when the operator has configured an ADR-296 guard
|
||||
# (RUVIEW_UDP_ALLOW or RUVIEW_UDP_INSECURE_LAN); without one the server
|
||||
# would refuse a routable bind, so we keep loopback and say why instead.
|
||||
# An explicit RUVIEW_UDP_BIND or --udp-bind always wins.
|
||||
# The binary parses RUVIEW_UDP_INSECURE_LAN itself (1/yes/on/true, any
|
||||
# case); here we only need to know whether it is truthy to pick the bind.
|
||||
__insecure_lan=0
|
||||
case "$(printf '%s' "${RUVIEW_UDP_INSECURE_LAN:-}" | tr 'A-Z' 'a-z')" in
|
||||
1|true|yes|on) __insecure_lan=1 ;;
|
||||
esac
|
||||
__udp_bind_arg=0
|
||||
__udp_guard_arg=0
|
||||
for __arg in "$@"; do
|
||||
case "$__arg" in
|
||||
--udp-bind|--udp-bind=*) __udp_bind_arg=1 ;;
|
||||
--udp-allow|--udp-allow=*|--udp-insecure-lan) __udp_guard_arg=1 ;;
|
||||
esac
|
||||
done
|
||||
if [ -z "${RUVIEW_UDP_BIND:-}" ] && [ "$__udp_bind_arg" = 0 ]; then
|
||||
if [ -n "${RUVIEW_UDP_ALLOW:-}" ] || [ "$__insecure_lan" = 1 ] \
|
||||
|| [ "$__udp_guard_arg" = 1 ]; then
|
||||
export RUVIEW_UDP_BIND=0.0.0.0
|
||||
echo "[entrypoint] UDP CSI receiver: binding 0.0.0.0 inside the container" >&2
|
||||
echo "[entrypoint] (a source guard is set: RUVIEW_UDP_ALLOW or RUVIEW_UDP_INSECURE_LAN)." >&2
|
||||
else
|
||||
case "${CSI_SOURCE:-auto}" in
|
||||
simulated|simulate) ;;
|
||||
*)
|
||||
echo "[entrypoint] NOTE: UDP CSI receiver stays on 127.0.0.1 (ADR-296 default)." >&2
|
||||
echo "[entrypoint] Inside a container that bind cannot receive ESP32 frames from" >&2
|
||||
echo "[entrypoint] a published 5005/udp port, so no node will appear. To ingest:" >&2
|
||||
echo "[entrypoint] -e RUVIEW_UDP_ALLOW=<node-ip-or-cidr> (restrict sources), or" >&2
|
||||
echo "[entrypoint] -e RUVIEW_UDP_INSECURE_LAN=true (accept spoofing risk)" >&2
|
||||
echo "[entrypoint] Docker Desktop/OrbStack on macOS rewrite the source to the bridge" >&2
|
||||
echo "[entrypoint] gateway, so the allowlist must name <gateway>/32, not the LAN subnet." >&2
|
||||
echo "[entrypoint] See https://github.com/ruvnet/RuView/issues/2089" >&2
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
set -- /app/sensing-server \
|
||||
--source "${CSI_SOURCE:-auto}" \
|
||||
--tick-ms 100 \
|
||||
|
||||
@@ -6,7 +6,9 @@ Known issues and fixes from the rebase-to-upstream branch (upstream #301).
|
||||
|
||||
## 1. Node not appearing in /api/v1/nodes
|
||||
|
||||
**Symptom:** ESP32-S3 node associates with WiFi, LED blinks, but no CSI frames arrive at the server. Node missing from `/api/v1/spatial/nodes`.
|
||||
**Symptom:** ESP32-S3 node associates with WiFi, LED blinks, but no CSI frames arrive at the server. Node missing from `/api/v1/nodes`.
|
||||
|
||||
**Check the server first:** the UDP receiver listens on `127.0.0.1` by default (ADR-296), so a natively run `sensing-server` never hears nodes on your network unless it was started with `--udp-bind 0.0.0.0 --udp-allow <node-ip-or-cidr>` (or `--udp-insecure-lan`). The startup log line for the UDP receiver says `loopback-only` when this is the problem. For Docker, see "Receiving ESP32 frames in Docker" in the [user guide](user-guide.md).
|
||||
|
||||
**Root cause:** After USB flash, the node enters a limping state where WiFi associates but the UDP CSI sender silently fails. The SoftAP + mDNS stack initializes but the CSI callback never fires.
|
||||
|
||||
@@ -145,18 +147,18 @@ ESP32 nodes still target the host on `--target-ip <host>:5005` — no firmware r
|
||||
|
||||
**Symptom:** `sensing-server` starts cleanly, logs `HTTP server listening on http://localhost:3000`, but loading `http://localhost:3000/` (or `/ui/index.html`) returns `404 Not Found`. Reported in #188.
|
||||
|
||||
**Root cause:** The default `--ui-path ../../ui` is resolved relative to the binary's *current working directory*, not the binary location. When the binary is launched from anywhere other than `crates/wifi-densepose-sensing-server/`, the relative path doesn't reach the UI assets and Axum's static file handler returns 404.
|
||||
**Root cause:** The default `--ui-path ../ui` is resolved relative to the *current working directory*, not the binary location. If it doesn't exist the server also tries `./ui` and `../../ui`. Launching from `v2/` works; from anywhere else (including `v2/crates/wifi-densepose-sensing-server/`) those paths miss the repo's UI, or hit some other `ui` directory, and Axum's static file handler returns 404.
|
||||
|
||||
**Fix:** Pass an absolute UI path, run the binary from the crate directory, or use the Docker image (which bundles the UI under `/app/ui`).
|
||||
**Fix:** Pass an absolute UI path, run the binary from `v2/`, or use the Docker image (which bundles the UI under `/app/ui`).
|
||||
|
||||
```bash
|
||||
# Option A — absolute path (recommended for production)
|
||||
sensing-server --source esp32 --udp-port 5005 --http-port 3000 \
|
||||
--ws-port 3001 --ui-path /absolute/path/to/ui
|
||||
|
||||
# Option B — run from the crate dir (works for local dev / cargo run)
|
||||
cd v2/crates/wifi-densepose-sensing-server
|
||||
cargo run -- --source esp32
|
||||
# Option B — run from v2/ (works for local dev / cargo run)
|
||||
cd v2
|
||||
cargo run -p wifi-densepose-sensing-server -- --source esp32
|
||||
|
||||
# Option C — Docker (no path config needed)
|
||||
docker compose -f docker/docker-compose.yml up sensing-server
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|-------|-------|
|
||||
| **Status** | Proposed |
|
||||
| **Date** | 2026-03-01 |
|
||||
| **Updated** | 2026-10-01: macOS 27 also redacts SSID without Location Services; the connected link is kept with a synthetic id, and `auto`+wifi keeps UDP bound (see Amendment 1) |
|
||||
| **Deciders** | ruv |
|
||||
| **Codename** | **ORCA** — OS-native Radio Channel Acquisition |
|
||||
| **Relates to** | ADR-013 (Feature-Level Sensing Commodity Gear), ADR-022 (Windows WiFi Enhanced Fidelity), ADR-014 (SOTA Signal Processing), ADR-018 (ESP32 Dev Implementation) |
|
||||
@@ -313,3 +314,22 @@ All verification on Mac Mini (M2 Pro, macOS 26.3).
|
||||
- ADR-022: Windows WiFi Enhanced Fidelity (analogous platform adapter)
|
||||
- ADR-013: Feature-Level Sensing from Commodity Gear
|
||||
- Issue [#56](https://github.com/ruvnet/wifi-densepose/issues/56): macOS support request
|
||||
|
||||
---
|
||||
|
||||
## Amendment 1 (2026-10-01): SSID is also redacted; keep the connected link
|
||||
|
||||
**Observed on macOS 27 (M-series Mac, CoreWLAN, unsigned CLI helper).** Without Location Services, `mac_wifi --scan-once` returns `"ssid":""` and `"bssid":"00:00:00:00:00:00"`, while `rssi`, `noise`, `channel` and `tx_rate` are real. The §1 assumption that "SSID + RSSI + channel" survive no longer holds. An unsigned CLI helper never calls `CLLocationManager`, so it never appears in Location Services and cannot be granted access.
|
||||
|
||||
Before this amendment, `resolve_bssid` abstained when both identities were blank (to avoid merging unrelated networks), so every macOS scan was dropped and `--source wifi` produced nothing, with no error.
|
||||
|
||||
**Change.**
|
||||
1. `--scan-once` marks its single sample `"connected": true`. It is always the one connected link, so it cannot collide with another network.
|
||||
2. A redacted sample marked `connected` gets a stable, locally administered synthetic BSSID derived from a reserved key plus the channel. The SSID stays empty; none is invented. Unmarked redacted lines still abstain.
|
||||
3. `--source auto` that resolves to host WiFi now also binds the UDP receiver, and `wifi_task` yields while the source is a live `esp32`. ESP32 nodes that start after the 2 s boot probe still promote the source, matching the #1004 rule for the simulator.
|
||||
4. A missing helper logs one clear error with the build command instead of a warning on every tick.
|
||||
|
||||
**Measured (2026-10-01, this change):** `--source wifi` → source `wifi:unnamed`, sensing ticks advance. `--source auto` on a quiet port → `wifi` with `udp_receiver=true`; relaying real ADR-018 frames promoted the source to `esp32`, with all 5 nodes listed.
|
||||
|
||||
**Still open:** real BSSID/SSID would need a signed `.app` helper with `NSLocationWhenInUseUsageDescription` that requests authorization. The helper still lives under `archive/v1` with no build step.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|-------|-------|
|
||||
| **Status** | Proposed |
|
||||
| **Date** | 2026-03-02 |
|
||||
| **Updated** | 2026-10-04 — multistatic fusion combines phase across nodes only when every frame declares the same shared phase reference; independent ESP32 nodes and the amplitude-only server bridge fuse amplitude only and report the reason (`phase_fusion` in `/health/ready`, issue #1752). |
|
||||
| **Deciders** | ruv |
|
||||
| **Codename** | **RuvSense** -- RuVector-Enhanced Sensing for Multistatic Fidelity |
|
||||
| **Relates to** | ADR-012 (ESP32 Mesh), ADR-014 (SOTA Signal Processing), ADR-016 (RuVector Training), ADR-017 (RuVector Signal+MAT), ADR-018 (ESP32 Implementation), ADR-024 (AETHER Embeddings), ADR-026 (Survivor Track Lifecycle), ADR-027 (MERIDIAN Generalization) |
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Status** | **Accepted** (MQTT track P1–P7 + P8a + P9 + P10 shipped 2026-05-23 in PR #778, 410 lib tests, witness bundle VERIFIED) / **Proposed** (Matter SDK wiring P8b deferred to v0.7.1 per §9.10) |
|
||||
| **Date** | 2026-05-23 |
|
||||
| **Date** | 2026-05-23 (amended 2026-10-02: P4.5 status note, §11) |
|
||||
| **Deciders** | ruv |
|
||||
| **Codename** | **HA-DISCO** (MQTT) + **HA-FABRIC** (Matter) + **HA-MIND** (semantic primitives) |
|
||||
| **Relates to** | ADR-018 (CSI binary frame format), ADR-021 (ESP32 vitals), ADR-031 (RuView sensing-first), ADR-039 (edge vitals packet 0xC511_0002), ADR-079 (camera ground-truth), ADR-103 (cog-person-count), ADR-110 (ESP32-C6 firmware), ADR-114 (cog-quantum-vitals) |
|
||||
@@ -440,7 +440,7 @@ This means: **adding a new primitive is one file change**. No MQTT schema rev, n
|
||||
| **P2** | HA discovery message emitter. New module `mqtt_discovery.rs`. Emits all entity `config` topics on connect + every `--mqtt-refresh-secs`. Schema-validated against HA's published JSON schema. | pending |
|
||||
| **P3** | State publication. Subscribe to internal `tokio::broadcast` channel (the one `tx.send(json)` writes to on line 3983 of `main.rs`). Translate `edge_vitals` / `sensing_update` / `pose_data` messages into per-entity state payloads. Apply rate-limit + privacy-mode filters. | pending |
|
||||
| **P4** | Integration tests: dockerised mosquitto in CI (extend `.github/workflows/firmware-qemu.yml` pattern), schema-validate every emitted config against HA's `homeassistant/components/mqtt` JSON schemas (pin to a tested HA version). Add a smoke test that brings up sensing-server in `--source mock --mqtt`, subscribes with `paho-mqtt` test client, asserts on entity creation. | pending |
|
||||
| **P4.5** | **Semantic inference layer (HA-MIND).** New module `semantic_inference.rs` implementing the 10 v1 primitives from §3.12. Output broadcast channel consumed by both MQTT publisher (P3) and Matter bridge (P8). Per-primitive precision/recall baselines published to `docs/integrations/semantic-primitives-metrics.md`. Unit tests per FSM + integration tests via replay of ADR-079 paired captures. | pending |
|
||||
| **P4.5** | **Semantic inference layer (HA-MIND).** New module `semantic_inference.rs` implementing the 10 v1 primitives from §3.12. Output broadcast channel consumed by both MQTT publisher (P3) and Matter bridge (P8). Per-primitive precision/recall baselines published to `docs/integrations/semantic-primitives-metrics.md`. Unit tests per FSM + integration tests via replay of ADR-079 paired captures. | partial — 6 of 10 primitives on the live MQTT publisher; see §11 |
|
||||
| **P5** | Docs: new `docs/integrations/home-assistant.md` with screenshots of the HA UI after auto-discovery completes, example HA dashboard YAML (Lovelace card configs), 8 starter blueprints from §3.12.2 (distress notify, wake routine, hallway dim, elderly anomaly alert, meeting lights, bathroom fan, fall-risk escalate, auto-arm security), and the raw-channel example automations: "turn on hall light when presence ON", "send notification on fall_detected event", "log HR/BR to InfluxDB". | pending |
|
||||
| **P6** | Ship `--mqtt` in the next sensing-server release (target: v0.7.0). Demo end-to-end on `cognitum-v0` against a Mosquitto add-on running on a Home Assistant OS install. Update README hardware-options table with "Works with Home Assistant" badge. | pending |
|
||||
| **P7** | Matter Bridge spike: build a throwaway prototype with `matter-rs` exposing one `OccupancySensor` endpoint + one `GenericSwitch` for fall. Pair against Apple Home, Google Home, and HA's Matter integration. Decision gate: if pairing works on all three, proceed to P8; if blocked, switch to chip-tool FFI and re-spike. | pending |
|
||||
@@ -667,4 +667,57 @@ Empty as of 2026-05-23. New questions discovered during implementation will be f
|
||||
|
||||
---
|
||||
|
||||
## 11. Status note: P4.5 semantic states on the live publisher (2026-10-02)
|
||||
|
||||
Issues [#2085](https://github.com/ruvnet/RuView/issues/2085) and [#2093](https://github.com/ruvnet/RuView/issues/2093) found that discovery announced 20 entities per device while only 6 ever received state, that `presence/state` was published on every CSI frame, and that HA device ids changed on every restart. The FSMs in `crate::semantic` existed but had no caller outside their tests. This note records what is now wired and what is not.
|
||||
|
||||
### 11.1 What changed
|
||||
|
||||
- **Semantic primitives run on the live path.** `mqtt::planner` holds one `SemanticBus` per node, sampled at 1 Hz (the rate the FSM constants assume). The bus feeds only the MQTT publisher. Matter does not consume it yet, so the "output broadcast channel shared with Matter" in P4.5 is not built.
|
||||
- **Announce only what has a source.** Six primitives are announced: `room_active`, `no_movement`, `elderly_inactivity_anomaly`, `someone_sleeping`, `possible_distress` and `fall_risk_elevated`. Four are not: `meeting_in_progress` needs a 1–20 % motion level, but per-node motion is a three-level classification; `bathroom_occupied`, `bed_exit` and `multi_room_transition` need zones, and the broadcast carries none (the §3.12.5 zone file is not implemented). For the same reason `zone_occupancy` (§3.1) and `pose` are not announced: `pose_keypoints` is never populated on the broadcast, and `persons[].keypoints` are synthesized.
|
||||
- **Per-entity availability (§3.6).** An announced entity is `online` only while its input exists: vitals while the calibration-gated estimate is published, `fall` while the node sends `edge_vitals`, `motion_energy` and `rssi` while present, and semantic primitives after the 60 s warmup (sleeping and distress also need breathing or heart rate, fall risk needs the fall detector). Otherwise it is `offline` and no state is sent. Transitions publish at once; all availability topics are re-sent every 30 s.
|
||||
- **No default values.** `motion_energy` was always `0.0` (MEASURED: 176 of 176 samples) because the bridge never set it. It now carries the node's `motion_band_power`, or the room value, or nothing. `fall` is driven by the rising edge of `edge_vitals.fall_detected`. Only `sensing_update` produces snapshots, which removes the phantom aggregate device that `edge_vitals` frames created. `present_still` now maps to 0 % motion instead of 100 %.
|
||||
- **Rates (§3.7).** Binary states publish on change, plus a 60 s retained heartbeat, as §3.5 already specified. Sensors keep their configured rates.
|
||||
- **Stable device identity (§3.8).** The default client id is now `wifi-densepose-<8 hex>`, persisted in `<data-dir>/mqtt_client_id`. §3.8 specified `wifi-densepose-<hostname>`; a persisted random id avoids a hostname dependency and survives hostname changes. `--mqtt-client-id` still overrides it.
|
||||
|
||||
### 11.2 Evidence
|
||||
|
||||
Unit tests (CODE-DERIVED, run with `cargo test -p wifi-densepose-sensing-server --features mqtt --lib -- mqtt:: semantic::`): `mqtt::planner::tests` covers the entity → state mapping, unavailable-without-source, warmup, on-change with heartbeat at a 73 frame/s input, sensor rates, reset and privacy mode. `mqtt::bridge::tests` covers message-type filtering, fall edges and motion energy. `mqtt::config::tests` covers client-id persistence across two "restarts" in a temp dir, override and malformed-file recovery.
|
||||
|
||||
Live measurement (MEASURED, 2026-10-02): one ESP32 node streaming CSI and `edge_vitals` over UDP to a macOS host; `sensing-server --source esp32 --mqtt` against `eclipse-mosquitto:2` in Docker on a non-default port; every topic captured with a `paho-mqtt` subscriber on `#`. "Before" is `03a89793` (main), "after" is this change, built `--release --features mqtt`, same command and window.
|
||||
|
||||
```bash
|
||||
# Broker: mosquitto.conf = "listener 1883 0.0.0.0 / allow_anonymous true / persistence false"
|
||||
docker run -d --rm -p 127.0.0.1:18830:1883 \
|
||||
-v "$PWD/mosquitto.conf:/mosquitto/config/mosquitto.conf:ro" eclipse-mosquitto:2
|
||||
# Run A (180 s, then SIGTERM) and run B (restart, 45 s) share one --data-dir.
|
||||
# A paho-mqtt subscriber on '#' starts 2 s before each run.
|
||||
RUVIEW_API_TOKEN=<random> sensing-server --source esp32 --udp-port 5006 \
|
||||
--udp-bind 0.0.0.0 --udp-allow <node-subnet> --http-port 3000 --ws-port 3001 \
|
||||
--no-mdns --data-dir <dir> --mqtt --mqtt-host 127.0.0.1 --mqtt-port 18830
|
||||
```
|
||||
|
||||
| Measure (180 s window unless noted) | Before (`03a89793`) | After |
|
||||
|---|---|---|
|
||||
| HA devices announced in run A | 2 (one phantom aggregate + `-node1`) | 1 (`-node1`) |
|
||||
| Entities announced per device | 20 | 15 |
|
||||
| Entities that received state (node device) | 6 | 10 |
|
||||
| Announced entities without state that still reported `online` | 14 | 1 (`fall`: an event, and no fall occurred) |
|
||||
| `presence/state` messages (node device) | 6,814 (37.9 / s) | 4 (one per change, plus 60 s heartbeat) |
|
||||
| `motion_energy` values | `0.0` in 176 of 176 | node band power, 177 samples |
|
||||
| Device id, run A → run B (restart, same `--data-dir`) | `wifi-densepose-<pid A>` → `<pid B>` (4 devices on the broker after B) | same persisted id in both runs (1 device) |
|
||||
| `offline` published on SIGTERM | no | no (unchanged; see 11.3) |
|
||||
| Same, plus `--privacy-mode` (75 s, fresh `--data-dir`) | — | 13 entities announced; no `heart_rate`, `breathing_rate` or `pose` topic for that device |
|
||||
|
||||
After the change, five announced entities had no state: `heart_rate` and `breathing_rate`, because no calibration had been run; `someone_sleeping` and `possible_distress`, which depend on them; and `fall`, which is an event and no fall occurred. The first four were `offline`. `fall` was `online`, because the node sent `edge_vitals`. Before the change all 14 entities without state still reported `online`. Only one node was streaming during this measurement. #2085 used five nodes and measured about 73 `presence` messages per second per node.
|
||||
|
||||
### 11.3 Not done
|
||||
|
||||
- Semantic precision/recall on real captures. The figures in `semantic-primitives-metrics.md` have no reproducer in the repository and stay CLAIMED.
|
||||
- Zone and threshold files, `--semantic*` / `--no-semantic` flags on `sensing-server`, the `reason` attribute (§3.12.4), and `semantic_events.jsonl`.
|
||||
- MQTT last-will and offline-on-shutdown (§3.6). The server registers no LWT and SIGTERM does not publish `offline`, so availability stays as last published after the server stops.
|
||||
- Matter consumption of the semantic states.
|
||||
|
||||
---
|
||||
|
||||
*ADR-115 is the integration story that turns RuView from "another sensing platform" into "drop-in upgrade for any HA install **and** any Matter-controller home." MQTT carries the rich, differentiated telemetry; Matter carries the standardised subset across every controller ecosystem. Numbers 111 and 112 remain reserved per the project ADR-numbering policy.*
|
||||
@@ -139,6 +139,32 @@ Implement the §3.3 mapping: `effective_class → PrivacyClass`, `cog-ha-matter`
|
||||
Add an opt-in `/ws/field` endpoint (or a `field_events` array on `SensingUpdate` behind a flag) carrying the signed `FieldEvent` + a privacy badge. Add an ingest route to `rufield-viewer` (it has none today — `server.rs:63-72`) so it can replay RuView's live feed instead of only `SyntheticSim`. **Gate:** a WS integration test asserting a connected client receives a privacy-badged, signature-verifiable `FieldEvent`; a viewer test asserting the new ingest route renders a live event. The `cognitum` appliance can speak RuField by consuming this endpoint (it already runs `ruview-vitals-worker`); deferred to its own ADR.
|
||||
|
||||
**P4 — fusion composition + multi-modality (ARCHITECTURE, optional).**
|
||||
|
||||
> **Update — second modality landed as a library.** Open question 5 below asked
|
||||
> whether the second modality should be `rvcsi`. It is **ultrasonic**, because
|
||||
> the cost collapsed: `rufield-adapters` now ships `UltrasonicReplayAdapter`,
|
||||
> the first adapter for `Modality::Ultrasonic` (registry code 7, empty since
|
||||
> v0.1), which parses, validates and signs [BatVu](https://github.com/ruvnet/batvu)
|
||||
> range profiles upstream. RuView only has to decide what it will put on a wire.
|
||||
>
|
||||
> `wifi-densepose-rufield::ultrasonic` is that decision, and it is expressed
|
||||
> structurally: the adapter is configured for its 32-bin coarse output (`P1`,
|
||||
> egress-safe) rather than its full per-bin frame (`P0`, edge-local), because a
|
||||
> consumer cannot un-coarsen a coarse profile whereas a runtime check can be
|
||||
> reordered. The `network_egress_allowed` gate still runs and is asserted to
|
||||
> drop nothing.
|
||||
>
|
||||
> Gates: `tests/ultrasonic_gates.rs`, 12 tests — round-trip, signature-verify,
|
||||
> fusion ingest, P1 on **both** tensor and observation, structural unreachability
|
||||
> of P4/P5, trust-tier refusal in both directions, determinism, whole-file
|
||||
> rejection of a malformed recording. Plus one asserting the honest negative
|
||||
> result: **an ultrasonic scan produces no fused inferences at all**, because the
|
||||
> adapter declines to populate `presence` (one transducer pair cannot tell a
|
||||
> person from a coat on a chair) and the engine's feature vocabulary is entirely
|
||||
> statements about a body. RuField v0.1 has no predicate for static geometry.
|
||||
>
|
||||
> Not wired into the running server. P1 shipped as a library before P3 wired it
|
||||
> in; this follows the same staging.
|
||||
Wire a second modality (cheapest: an `rvcsi`-sourced event, or recorded mmWave) into `RuFieldFusion` alongside the WiFi event, proving cross-modality fusion above ruvsense. **Gate:** a fusion test with two modalities producing ≥1 cross-modal inference, with provenance coverage 100%.
|
||||
|
||||
---
|
||||
|
||||