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 | ||
|
|
bbbb14169d | ||
|
|
36e4df95b7 |
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
|
||||
@@ -117,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: |
|
||||
@@ -202,3 +219,40 @@ jobs:
|
||||
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/*
|
||||
@@ -41,8 +41,12 @@ jobs:
|
||||
build: false
|
||||
publishable: true
|
||||
# ADR-283/325: brain + local hosts + replay assets + guarded Spaces OAuth adapter;
|
||||
# still runtime-dependency-free. 160 KiB is the reviewed hard ceiling.
|
||||
unpacked_budget: 163840
|
||||
# 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
|
||||
@@ -131,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,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/325: brain + hosts + replay + guarded Spaces OAuth; no runtime deps.
|
||||
harness/ruview) export UNPACKED_BUDGET=163840 ;;
|
||||
# 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);"
|
||||
|
||||
@@ -322,3 +322,6 @@ v2/crates/ruview-offaxis/pkg/
|
||||
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
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
@@ -6,6 +6,27 @@
|
||||
</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://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** ##
|
||||
|
||||
@@ -21,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
|
||||
@@ -37,32 +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, an honesty check for accuracy claims, and an explicitly granted OAuth-only Cognitum Spaces read.
|
||||
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.4.0 doctor
|
||||
npx @ruvnet/ruview@0.4.0 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.4.0 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.4.0 brain search --query "calibration"
|
||||
npx @ruvnet/ruview@0.4.0 brain verify --repo .
|
||||
|
||||
# Check claims, replay the deterministic proof, or expose the MCP server
|
||||
npx @ruvnet/ruview@0.4.0 claim-check --file REPORT.md
|
||||
npx @ruvnet/ruview@0.4.0 verify
|
||||
npx @ruvnet/ruview@0.4.0 spaces
|
||||
npx @ruvnet/ruview@0.4.0 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>
|
||||
|
||||
@@ -100,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).
|
||||
@@ -114,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:
|
||||
@@ -227,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>
|
||||
@@ -281,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>
|
||||
@@ -455,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:
|
||||
|
||||
```
|
||||
@@ -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.4.0`; 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.4.0`; the quick c
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
[](docs/user-guide.md)
|
||||
|
||||
Start with the user, build, and calibration guides; expand for the full reference map.
|
||||
|
||||
<details>
|
||||
@@ -743,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.
|
||||
|
||||
@@ -20,6 +20,10 @@ func main() {
|
||||
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,
|
||||
|
||||
@@ -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 |
@@ -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.*
|
||||
@@ -66,10 +66,64 @@ hardware claims.
|
||||
timestamps, sequence behavior, calibration, maximum size, and report rate.
|
||||
- Validate OpenWrt One first, then BPI-R3 4x4, before considering MT7996/MLO.
|
||||
|
||||
## Amendment 1 — vendor CSI on MT7981, still unvalidated
|
||||
|
||||
- **Date**: 2026-09-19, recorded here 2026-10-01
|
||||
- **Status**: proposed. One board model (two units). The hardware gates below are still open.
|
||||
|
||||
The 2026-07-18 decision said the public `mt76` tree has no supported CSI export,
|
||||
and that a firmware change might be required before physical CSI exists. Both
|
||||
statements need a narrower reading.
|
||||
|
||||
Mainline `openwrt/mt76` still has no CSI export. MediaTek's public OpenWrt feed
|
||||
does: vendor id `0x0ce7`, MCU event `0xc2`, patch
|
||||
`1001-wifi-mt76-mt7915-csi-implement-csi-support`. On a Wavlink WL-WN586X3
|
||||
Rev A (MT7981BA + MT7976CN + MT7531AE) that patch, rebased onto the `mt76`
|
||||
revision pinned by OpenWrt 24.10.8, produced complex samples without a firmware
|
||||
blob swap. The `0xc2` hook is already in the MT7981 firmware that the OpenWrt
|
||||
24.10.8 image carries. The
|
||||
rebased patch and the two userspace fixes are in `firmware/openwrt-wn586x3/`.
|
||||
|
||||
What the first capture was: one record, 2.4 GHz, 20 MHz, legacy OFDM, 64
|
||||
subcarriers, a single chain. CSI arrived only while a client sent frames.
|
||||
The rate is client traffic, not a sensor sample clock. The capture is not in
|
||||
this repository.
|
||||
|
||||
What it was not:
|
||||
|
||||
- Not a calibration, a sequence check, a timestamp check, or a repeatability run.
|
||||
The label on the wire is `mediatek:physical-unvalidated`. Plain `mediatek` stays
|
||||
reserved for a frame that has passed those gates.
|
||||
- Not a 4x4 array. Each radio is two chains. The four antennas are a 2.4 GHz pair
|
||||
and a 5 GHz pair. Two routers are two receivers. Cross-box phase is not a
|
||||
shared local oscillator, so it is not a beam.
|
||||
- Not the OpenWrt One or the BPI-R3. Those remain the upstream-friendly targets
|
||||
in the original decision. The WN586X3 is the board this path was actually run on.
|
||||
|
||||
`wifi-densepose-mtk-bridge` translates `mt76-vendor` JSON, or an MtkCSIdump
|
||||
datagram, into ADR-267 MTC1 and sends it to the sensing server. The server keeps
|
||||
one snapshot and a bounded ring of per-subcarrier amplitude and phase per
|
||||
`device_id`. It runs `mediatek-amplitude-heuristic-v0` on mean and peak amplitude,
|
||||
and `activity-index-v0` on per-subcarrier fluctuation. Both are `CLAIMED`. Neither
|
||||
is the ESP32 vital-sign path.
|
||||
|
||||
One measured property supports further work, and nothing more. Offline, on six
|
||||
local dump captures from two units (2.4 GHz, HT20, chains rx0 and rx1 of transmit
|
||||
stream 0), the cross-chain phase `arg(H0·conj(H1))`, summed over subcarriers,
|
||||
moved 0.014-0.039 rad (p50) between adjacent frames for well-sampled
|
||||
transmitters. Raw per-chain phase moved about 1.56 rad (p50), which is what
|
||||
uniformly random phase gives (MEASURED; reproducer
|
||||
`scripts/mediatek-csi-phase-stability.py`). That shows a stable observable inside
|
||||
one radio. It does not show that the observable tracks people.
|
||||
|
||||
The operator guide is [`docs/mediatek-router-csi.md`](../mediatek-router-csi.md).
|
||||
|
||||
## Links
|
||||
|
||||
- [ADR-123: BFLD capture path](ADR-123-bfld-capture-path-nexmon-and-esp32.md)
|
||||
- [ADR-264: RTL8720F radar wire protocol](ADR-264-rtl8720f-radar-wire-protocol.md)
|
||||
- [ADR-267: MediaTek MIMO CSI wire protocol](ADR-267-mediatek-mimo-csi-wire-protocol.md)
|
||||
- [MediaTek router CSI guide](../mediatek-router-csi.md)
|
||||
- [upstream mt76](https://github.com/openwrt/mt76)
|
||||
- [OpenWrt One](https://openwrt.org/toh/openwrt/one)
|
||||
- [MediaTek OpenWrt feed](https://git01.mediatek.com/openwrt/feeds/mtk-openwrt-feeds/)
|
||||
@@ -34,6 +34,81 @@ Define `MTC1` version 1 as a little-endian, self-delimiting envelope:
|
||||
- Flags distinguish calibrated, saturated, time-synchronized, dropped-predecessor,
|
||||
and synthetic frames. Synthetic provenance cannot be cleared by downstream code.
|
||||
|
||||
## Amendment 1 — PPDU types `Legacy` and `Unknown`
|
||||
|
||||
- **Date**: 2026-09-19
|
||||
- **Status**: proposed. Demonstrated on one WL-WN586X3 capture. Not a maintainer acceptance.
|
||||
- **Scope**: `PpduType` discriminants only. The 72-byte header layout, CRC,
|
||||
payload ordering, flags, and caps are unchanged.
|
||||
|
||||
### What changed
|
||||
|
||||
`PpduType` gains two variants:
|
||||
|
||||
| Value | Name | Meaning |
|
||||
|---|---|---|
|
||||
| 6 | `Legacy` | Pre-HT: 802.11b CCK or 802.11a/g OFDM |
|
||||
| 7 | `Unknown` | A PPDU format the producer could not classify |
|
||||
|
||||
Values 1-5 (`Ht`, `Vht`, `HeSu`, `HeMu`, `Eht`) are untouched.
|
||||
|
||||
### Why
|
||||
|
||||
The original set assumed every CSI report would be HT or later. The first real
|
||||
MT7981 capture disproved that. A Wavlink WL-WN586X3 (MT7981B + MT7976C) running
|
||||
an OpenWrt 24.10.8 image built with the patches in `firmware/openwrt-wn586x3/`
|
||||
reported `rx_mode = 1` (`MT_PHY_TYPE_OFDM`) for a client associated on 2.4 GHz
|
||||
channel 6 at 20 MHz. The bridge had no way to express it and dropped the frame.
|
||||
|
||||
That was a real data loss, not a corner case. MediaTek's CSI driver treats legacy
|
||||
OFDM as a first-class mode: `mt7915_vendor_csi_tone_mask` skips only
|
||||
`MT_PHY_TYPE_CCK`, and its `mode_map` is keyed by `MT_PHY_TYPE_OFDM`, `_HT`,
|
||||
`_VHT` and `_HE_SU`, giving OFDM its own tone-mask group
|
||||
(`1001-wifi-mt76-mt7915-csi-implement-csi-support.patch:1070-1088`). Association
|
||||
and management exchanges are legacy-rate by design, so a sensing deployment will
|
||||
see these continuously.
|
||||
|
||||
`Unknown` exists so the enum's gaps (5-7 and 12 in `mt76_phy_type`) and future
|
||||
modes are carried explicitly rather than guessed at or dropped. It also covers
|
||||
transports that omit the field: the MtkCSIdump UDP datagram carries no `rx_mode`,
|
||||
and reporting `Unknown` there is honest where defaulting to a concrete format was
|
||||
not.
|
||||
|
||||
### Compatibility
|
||||
|
||||
- **Forward, not backward.** A decoder built before this amendment rejects
|
||||
discriminants 6 and 7 with `UnknownPpduType`, because the original parser
|
||||
rejects unknown types by design. `TryFrom<u8>` returns `Err` rather than
|
||||
panicking, so an old decoder fails safely — it just drops legacy frames, and
|
||||
does so silently. **Rebuild MTC1 consumers after this codec change.**
|
||||
- **Scope is narrower than "the workspace".** `wifi-densepose-hardware` defines
|
||||
three independent `PpduType` enums — `csi_frame.rs` (ESP32),
|
||||
`qualcomm_csi.rs`, and `mediatek_csi.rs` — and this amendment touches only the
|
||||
MediaTek one. Neither of the others changes, so no other vendor bridge is
|
||||
affected. The complete set of `mediatek_csi::PpduType` consumers is:
|
||||
`wifi-densepose-hardware`'s own `mediatek-csi-sim` binary,
|
||||
`wifi-densepose-mtk-bridge`, and `wifi-densepose-sensing-server`, which renders the
|
||||
value with `{:?}` and so needed no code change. In particular the
|
||||
`ppdu_type > 3` bound in `bootstrap_baseline.rs` is fed from the **ESP32**
|
||||
enum via `CsiGridKey::from_frame(&Esp32Frame)`, not from MediaTek frames, so
|
||||
`Legacy` and `Unknown` cannot reach it.
|
||||
- Because the variants were added rather than renumbered, and Rust requires
|
||||
exhaustive matches, the compiler locates any consumer that must be updated.
|
||||
Nothing outside the files above needed one.
|
||||
- Producers must emit 6 only for frames that genuinely are pre-HT, and 7 only
|
||||
where the format is truly unclassified. Neither is a dumping ground for a
|
||||
mapping the producer has not done.
|
||||
- The mapping from `rx_mode` to `PpduType` is now infallible, so no MTC1 producer
|
||||
may drop a frame on PPDU grounds.
|
||||
- Unchanged: synthetic provenance still cannot be cleared by downstream code.
|
||||
|
||||
### Observed dimensions
|
||||
|
||||
The same capture assembled to 1x1x64. That is the client's behaviour, not a
|
||||
protocol limit: the handset sent single-stream frames to a 2.4 GHz 20 MHz AP.
|
||||
Expect 1x2 or 2x2 on 5 GHz, and size consumers for the chipset profile's
|
||||
`max_chains` rather than for what one capture happened to show.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
@@ -59,3 +134,8 @@ Define `MTC1` version 1 as a little-endian, self-delimiting envelope:
|
||||
- [ADR-266: MediaTek Filogic CSI platform](ADR-266-mediatek-filogic-csi-platform.md)
|
||||
- [ADR-018: ESP32 binary CSI framing](ADR-018-esp32-csi-frame-protocol.md)
|
||||
- [ADR-264: RTL8720F radar wire protocol](ADR-264-rtl8720f-radar-wire-protocol.md)
|
||||
- Amendment 1 implementation: `v2/crates/wifi-densepose-hardware/src/mediatek_csi.rs`
|
||||
(codec) and `v2/crates/wifi-densepose-mtk-bridge` (`ppdu_from_rx_mode`). The
|
||||
motivating capture is a lab record and is not in this tree: it contains a
|
||||
client transmitter address and raw CSI. The in-repo check is a fabricated
|
||||
legacy-OFDM record in `wifi-densepose-mtk-bridge/tests/hardware_capture.rs`.
|
||||
@@ -0,0 +1,218 @@
|
||||
# ADR-323: RTL8721Dx (Realtek AmebaDplus) CSI Wire Protocol
|
||||
|
||||
- **Status**: accepted
|
||||
- **Date**: 2026-09-15
|
||||
- **Deciders**: RuView maintainers
|
||||
- **Tags**: realtek, ameba, amebadplus, rtl8721dx, csi, protocol, rust, udp
|
||||
|
||||
## Context
|
||||
|
||||
Unlike the MediaTek/Qualcomm CSI paths (ADR-266..269), which are simulator-first
|
||||
because no supported public vendor interface exports complex CSI, Realtek's
|
||||
official Ameba RTOS SDK (`Ameba-AIoT/ameba-rtos`, Apache-2.0) documents and
|
||||
exposes a real, callback-driven CSI API for the RTL8721Dx ("AmebaDplus")
|
||||
family: `wifi_csi_config()` plus the `RTW_EVENT_CSI_DONE` event delivering a
|
||||
`struct rtw_event_csi_report_info` (per-tone signed I/Q, 8-bit or 16-bit
|
||||
precision, selectable tone decimation, passive or active/triggered capture).
|
||||
This has been confirmed directly against SDK source
|
||||
(`component/wifi/api/wifi_api_event.h`) and against the official
|
||||
`example/wifi/wifi_csi` example, and validated on real PKM8721DAF-C13-F10
|
||||
hardware (build+flash+boot confirmed on branch `feat/rtl8721dx-csi-bringup`).
|
||||
|
||||
The RTL8721Dx is a 1x1 WiFi 4 part — single TX/RX chain, not MIMO — so the
|
||||
MediaTek/Qualcomm wire format (Tx/Rx dimensioned matrices, chipset chain
|
||||
counts) does not fit. The vendor SDK's raw struct is also not a safe host
|
||||
wire format as-is: it has no CRC, a C flexible-array-member payload, and
|
||||
fields sized for firmware convenience (e.g. a wrapping `u32` microsecond
|
||||
timestamp) rather than network robustness.
|
||||
|
||||
Per the existing repo convention (ESP32/ADR-018, MediaTek/ADR-266-267,
|
||||
Qualcomm/ADR-268-269, RTL8720F radar/ADR-263-264), each vendor CSI/radar
|
||||
source gets its own self-delimiting envelope and its own Rust module pair
|
||||
(`wifi-densepose-hardware` for framing+codec+simulator,
|
||||
`wifi-densepose-sensing-server` for the bounded JSON-safe snapshot), never a
|
||||
shared "generic vendor CSI" struct that would either lose vendor-specific
|
||||
fields or invite magic-space collisions. `SourceKind::Realtek` (value 2) is
|
||||
already assigned to the RTL8720F FMCW radar path (ADR-263/264) and must not
|
||||
be reused for CSI.
|
||||
|
||||
## Decision
|
||||
|
||||
Define `RAC1` ("Realtek Ameba CSI", version 1) as a little-endian,
|
||||
self-delimiting envelope, magic `0x3143_4152` (distinct from `MTC1`
|
||||
`0x3143544d`, `QCS1` 0x31535143, `RTR1` 0x31525452, and all ADR-018
|
||||
`0xC511000x` siblings):
|
||||
|
||||
Fixed 49-byte header (explicit field-by-field serialization, no `#[repr(C)]`
|
||||
padding, matching the MediaTek/Qualcomm modules' style):
|
||||
|
||||
| Field | Type | Notes |
|
||||
|---|---|---|
|
||||
| magic | u32 LE | `0x3143_4152` |
|
||||
| version | u8 | 1 |
|
||||
| header_len | u16 LE | 49 |
|
||||
| frame_len | u32 LE | header + payload + 4-byte CRC |
|
||||
| node_id | u8 | disambiguates multi-board illuminator/receiver deployments; 0 = unset |
|
||||
| csi_mode | u8 | 0=passive, 1=active, 2=board-to-board (`CsiMode`) |
|
||||
| sequence | u32 LE | from firmware `csi_sequence` |
|
||||
| timestamp_us | u32 LE | from firmware `hw_assigned_timestamp` (hardware-clock microseconds, wraps ~71 min — consumers must not assume monotonic across a capture longer than that) |
|
||||
| peer_mac | [u8; 6] | firmware `mac_addr` |
|
||||
| trig_mac | [u8; 6] | firmware `trig_addr` |
|
||||
| channel | u8 | operating channel |
|
||||
| bandwidth | u8 | 0=20MHz, 1=40MHz |
|
||||
| rx_rate | u8 | firmware `rx_rate` |
|
||||
| protocol_mode | u8 | 0=OFDM,1=HT,2=VHT,3=HE (`ProtocolMode`) |
|
||||
| num_sub_carrier | u16 LE | tone count in payload |
|
||||
| num_bit_per_tone | u8 | 16 (8-bit I + 8-bit Q) or 32 (16-bit I + 16-bit Q) |
|
||||
| decimation | u8 | tone group (1/2/4/8 — every Nth tone) |
|
||||
| rssi_dbm | i8 | single RF chain (1x1 hardware) |
|
||||
| rxsc | u8 | sub-20 MHz channel used |
|
||||
| csi_valid | u8 | 0/1 from firmware |
|
||||
| flags | u8 | bit 0 = SYNTHETIC (simulator provenance, never clearable downstream) |
|
||||
| payload_len | u32 LE | bytes, == `num_sub_carrier * (num_bit_per_tone / 8)` |
|
||||
|
||||
Payload: `num_sub_carrier` consecutive (I, Q) tone pairs, each
|
||||
`num_bit_per_tone / 16` bytes per component (1 byte/component when
|
||||
`num_bit_per_tone == 16`, 2 bytes/component little-endian signed when `== 32`)
|
||||
— i.e. exactly the byte layout the firmware already produces in
|
||||
`csi_data[]`, just framed. CRC-32/IEEE over header+payload, final 4
|
||||
little-endian bytes. One envelope per UDP datagram.
|
||||
|
||||
Parsers reject: unknown version, wrong `header_len`, `frame_len` exceeding
|
||||
the IPv4 UDP payload cap (65,507 bytes), `num_bit_per_tone` outside
|
||||
`{16, 32}`, `payload_len` inconsistent with `num_sub_carrier *
|
||||
(num_bit_per_tone/8)`, trailing bytes, and bad CRC — mirroring the
|
||||
MediaTek/Qualcomm parser contract exactly.
|
||||
|
||||
Host side: add `realtek_csi.rs` to both
|
||||
`wifi-densepose-hardware` (frame + codec + simulator, mirroring
|
||||
`mediatek_csi.rs`/`qualcomm_csi.rs`) and `wifi-densepose-sensing-server`
|
||||
(bounded `RealtekCsiSnapshot`, mirroring `QualcommCsiSnapshot`), wired into
|
||||
the same UDP listener loop and `/api/v1/csi/realtek/latest` route as the
|
||||
existing vendor sources. The initial Mac compatibility port keeps Realtek CSI
|
||||
as a separate bounded diagnostic stream. Fresh ESP32 frames remain the primary
|
||||
sensing source. This change does not add `SourceKind::RealtekCsi` to a signed
|
||||
ingest contract; that requires a separate reviewed identity-bound hardware
|
||||
proof. RAC1 CRC checks corruption, not origin.
|
||||
|
||||
Firmware side (`example/wifi/wifi_csi` derivative, built against the
|
||||
official Ameba RTOS SDK, tracked outside this repository per the existing
|
||||
`CLAUDE.local.md` convention — the vendor SDK itself is never vendored into
|
||||
this repo): join the board to the deployment's WiFi AP in STA mode
|
||||
(passive CSI against the real AP as peer, since only one physical board is
|
||||
available in this bring-up), read the AP's BSSID at runtime after
|
||||
association (never hardcode a MAC into firmware source), pack each
|
||||
`RTW_EVENT_CSI_DONE` report into one `RAC1` datagram, and `sendto()` it over
|
||||
UDP to the host sensing-server's existing CSI port.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- CSI is real, MEASURED hardware output from day one — no simulator-first
|
||||
bridge phase is needed the way MediaTek/Qualcomm required, because the
|
||||
vendor SDK genuinely exposes the capability and we have the board in hand.
|
||||
- One board is sufficient for a first useful signal (passive CSI against the
|
||||
home AP); active and board-to-board modes are additive later without a
|
||||
wire-format break (`csi_mode` already reserves the values).
|
||||
- Reuses the bounded UDP parser and status-route pattern without changing
|
||||
existing ESP32 sensing. Unsigned RAC1 diagnostics are not authorized as
|
||||
calibrated presence, person count, pose, or vital evidence.
|
||||
|
||||
### Negative
|
||||
|
||||
- 1x1 hardware means no spatial (multi-antenna) diversity from a single
|
||||
board; multi-board deployment is required for the differential/localization
|
||||
use cases described in the original RTL8721Dx capability analysis.
|
||||
- The 71-minute microsecond timestamp wraparound (inherited from the
|
||||
firmware's `u32` field) means long unattended captures need host-side
|
||||
sequence-based reordering, not raw timestamp arithmetic, across a wrap.
|
||||
|
||||
### Neutral
|
||||
|
||||
- The RAC1 envelope intentionally does not carry the SDK's raw
|
||||
`csi_signature` (0xABCD) marker — our own `magic`/CRC supersede it as the
|
||||
framing integrity check.
|
||||
|
||||
## Hardware gates
|
||||
|
||||
- [x] Confirm SDK source exposes `RTW_EVENT_CSI_DONE` / `rtw_event_csi_report_info` (done — `component/wifi/api/wifi_api_event.h`).
|
||||
- [x] Build and flash a baseline image on real PKM8721DAF-C13-F10 hardware, confirm boot over serial (done — `feat/rtl8721dx-csi-bringup`).
|
||||
- [x] Flash the CSI-streaming firmware and confirm `RAC1` datagrams parse on the host from the real board (done, 2026-09-15 — see below).
|
||||
- [x] Record MEASURED throughput/latency/jitter from the real running firmware (done, 2026-09-15 — see below).
|
||||
- [ ] A human walk-test across the link (amplitude perturbation vs. static baseline) is deferred — requires the operator physically present; not claimed until performed.
|
||||
|
||||
### MEASURED: real RAC1 capture and sustained throughput (2026-09-15)
|
||||
|
||||
Passive CSI (`RTW_CSI_MODE_NORMAL`, `RTW_CSI_TRIG_BEACON | RTW_CSI_TRIG_DATA | RTW_CSI_TRIG_QOS_DATA`)
|
||||
against the deployment AP. A single `RAC1` datagram was first
|
||||
cross-checked field-by-field against the firmware's own serial log of the
|
||||
same report — every byte matched: magic `0x31434152`, RSSI byte exact match,
|
||||
channel/bandwidth/protocol/subcarrier-count exact match, 157-byte total frame
|
||||
(49-byte header + 104-byte payload + 4-byte CRC, exactly as specified above).
|
||||
|
||||
`RTW_CSI_MODE_RX_RESP` (estimate CSI from ACKs to the STA's own transmissions)
|
||||
never fired `RTW_EVENT_CSI_DONE` across two full test runs with confirmed
|
||||
real traffic (not a hang) — this mode does not work for this hardware/AP
|
||||
combination and `RTW_CSI_MODE_NORMAL` with beacon+data triggers is the
|
||||
working configuration.
|
||||
|
||||
**An earlier note here claimed `NORMAL` mode fires only once per CSI enable
|
||||
— that was wrong**, caused by a debug log line gated to print only every
|
||||
50th frame (`frame_count % 50 == 1`), which was misread as "only one report
|
||||
total." A follow-up capture with a UDP listener running concurrently with a
|
||||
board reset measured **277 real RAC1 datagrams in 40 seconds (43,489 bytes)**,
|
||||
with `csi_sequence` climbing continuously and monotonically in the firmware's
|
||||
own serial log across six separate 50-frame log checkpoints in one 45s
|
||||
session — CSI reporting is continuous, roughly 7-12 fps, not sparse.
|
||||
|
||||
### MEASURED: throughput optimization pass (2026-09-15)
|
||||
|
||||
Formalized as a repeatable tool: `scripts/benchmark-rtl8721dx-csi.py` (listens
|
||||
on the sensing-server's CSI UDP port, reports fps/throughput/RSSI/inter-frame
|
||||
interval/sequence-gap stats from real received `RAC1` datagrams).
|
||||
|
||||
**Baseline** (`trig_period=200` [64ms], `trig_frame_ctrl=0`,
|
||||
`CSI_REPORT_BUF_NUM=1`), 30s capture:
|
||||
|
||||
| Metric | Value |
|
||||
|---|---|
|
||||
| RAC1 fps | 14.67 |
|
||||
| Throughput | 2,302.7 bytes/s |
|
||||
| Mean inter-frame interval | 68.3 ms |
|
||||
| RSSI | mean -34.4 dBm |
|
||||
|
||||
`trig_period` (units of 320µs) was hypothesized as the rate-limiting
|
||||
throttle — the observed 68.3ms mean interval tracks the 64ms configured
|
||||
period almost exactly. Confirmed by tuning:
|
||||
|
||||
1. `trig_period`: 200 → 15 (the SDK doc's stated minimum recommended value,
|
||||
~4.8ms)
|
||||
2. `trig_frame_ctrl`: 0 → `RTW_CSI_TRIG_ACK` (second trigger source: every
|
||||
link-layer ACK the AP sends for the heartbeat's own outgoing traffic, on
|
||||
top of the existing beacon trigger)
|
||||
3. `CSI_REPORT_BUF_NUM`: 1 → 4 (a "lack of csi buf!" drop was observed even
|
||||
at the slower baseline rate; more headroom needed at a higher rate)
|
||||
|
||||
**Tuned**, 30s capture:
|
||||
|
||||
| Metric | Value | vs. baseline |
|
||||
|---|---|---|
|
||||
| RAC1 fps | 66.40 | **4.5x** |
|
||||
| Throughput | 10,424.8 bytes/s | **4.5x** |
|
||||
| Mean inter-frame interval | 14.9 ms | 4.6x lower |
|
||||
| Sequence gaps | 78 / ~2036 (~3.8%) | new (0 observed at the slower baseline rate) |
|
||||
| RSSI | mean -31.1 dBm | (different session/position, not a controlled variable here) |
|
||||
|
||||
The `trig_period` hypothesis is confirmed as the primary lever. The ~3.8%
|
||||
frame-loss rate at 66 fps is a reasonable place to stop for now — it is
|
||||
UDP-over-WiFi loss, not a firmware defect, and is small enough not to block
|
||||
downstream sensing use; revisit only if a use case needs stronger delivery
|
||||
guarantees (sequence-gap-triggered re-request, TCP fallback, etc.).
|
||||
|
||||
## Links
|
||||
|
||||
- [ADR-266](ADR-266-mediatek-filogic-csi-platform.md) / [ADR-267](ADR-267-mediatek-mimo-csi-wire-protocol.md) — sibling vendor CSI ADR pair (simulator-first precedent)
|
||||
- [ADR-268](ADR-268-qualcomm-atheros-csi-platform.md) / [ADR-269](ADR-269-qualcomm-csi-wire-protocol.md) — sibling vendor CSI ADR pair
|
||||
- [ADR-263](ADR-263-rtl8720f-2-4ghz-fmcw-radar-platform.md) / [ADR-264](ADR-264-rtl8720f-radar-wire-protocol.md) — existing Realtek (RTL8720F radar) path; `SourceKind::Realtek` owner
|
||||
- `CLAUDE.local.md` — RTL8721Dx toolchain setup, board/COM port, first bring-up log
|
||||
@@ -1,4 +1,4 @@
|
||||
# ADR 348: Native macOS USB node onboarding
|
||||
# ADR 363: Native macOS USB node onboarding
|
||||
|
||||
## Status
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
# ADR-364: BFI capture admission and continuity
|
||||
|
||||
- **Status**: proposed
|
||||
- **Date**: 2026-09-29
|
||||
- **Deciders**: RuView maintainers; acceptance pending
|
||||
- **Tags**: bfi, capture, evidence, continuity, hardware
|
||||
|
||||
## Context
|
||||
|
||||
The Archer BE550, associated iPhone and MT7927 capture host have produced
|
||||
readable beamforming feedback information (BFI). Monitor-mode support alone
|
||||
does not establish this capability, and readable reports do not establish
|
||||
continuous sensing. Router channel width also does not guarantee an identical
|
||||
feedback grid in every report.
|
||||
|
||||
**MEASURED:** two saved trials contain 66 and 96 unique reports. During their
|
||||
approximately 30-second sender intervals, rates were 2.2 and 3.2 reports/s,
|
||||
with maximum silence of 8.392 and 6.437 seconds. No reports followed in the
|
||||
approximately 15-second post-traffic intervals. All 162 reports received an
|
||||
independent tshark angle/control/SNR comparison. Reproducer commands, capture
|
||||
hashes and limitations are in the [capture results](../../tools/bfi/OPTIMIZATION.md)
|
||||
and [continuity report](../../tools/bfi_learning/CAPTURE-CONTINUITY.md).
|
||||
|
||||
## Decision
|
||||
|
||||
Admit a hardware/driver/profile combination only from its actual packet
|
||||
evidence. Apply these boundaries before using its output for sensing:
|
||||
|
||||
1. Keep originals and receipts outside Git, with raw own-network captures on
|
||||
the capture host. Record hardware, driver, channel, source hashes, capture
|
||||
interval and restoration outcome. Select the authorized AP/client direction
|
||||
explicitly; missing provenance cannot be inferred from an SSID.
|
||||
2. Enforce container, radiotap, MAC, length, fragmentation and supported-format
|
||||
checks in [bfi_decode.py](../../tools/bfi/bfi_decode.py). Validate FCS when
|
||||
present and reject flagged corruption; absent FCS is a recorded limitation.
|
||||
Unsupported tuples remain counted rejections. Compare every admitted angle
|
||||
against an independent dissector before extending a format's support claim.
|
||||
3. Deduplicate retries over the whole capture before slicing time intervals.
|
||||
Preserve integer timestamps and separate feedback grids. Sequence numbers
|
||||
and sounding tokens do not measure lost packets. BFI steering matrices are
|
||||
not full CSI; the identity product of a square unitary matrix with its
|
||||
conjugate transpose cannot serve as a changing channel feature.
|
||||
4. Preserve full-observation quality metrics and add separate before-traffic,
|
||||
sender-interval and after-traffic metrics. Include leading/trailing silence,
|
||||
report rate, maximum gap and duration-weighted occupied one-second bins.
|
||||
Sender timestamps bound attempted UDP sends, not verified over-air sounding.
|
||||
5. Use an initial continuity gate of reports in at least 27 of the first 30
|
||||
complete one-second sender bins and no silence longer than two seconds
|
||||
anywhere in the actual sender interval, repeated in three comparable trials.
|
||||
Report any partial final bin separately; never count it as a complete second.
|
||||
This is a project engineering gate, not a published sensing accuracy result.
|
||||
|
||||
The current traffic receipt lacks a PCAP hash and AP/client binding. The
|
||||
analyzer checks caller-selected file associations and hashes all inputs in its
|
||||
output; this establishes content integrity, not authenticated session binding.
|
||||
Stronger binding is required before automated capture admission can treat
|
||||
receipt association as independently verified.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Monitor-mode declarations, average report rate alone and interpolating missing
|
||||
reports would each hide a different failure. Retain explicit packet validation
|
||||
and interval coverage instead. ESP32/Realtek CSI remains a separate modality;
|
||||
multiple unsynchronized boards do not establish a coherent BFI array.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
Packet validity, capture continuity and sensing accuracy have separate,
|
||||
reproducible acceptance criteria. Changes in denominators cannot appear as RF
|
||||
performance gains.
|
||||
|
||||
### Negative
|
||||
|
||||
Strict format and continuity gates can exclude usable but sparse observations.
|
||||
New PHY formats and hardware require additional captures and independent checks.
|
||||
|
||||
### Neutral
|
||||
|
||||
The current trials fail continuity. Further motion modeling requires a new
|
||||
capture result; this ADR does not authorize hardware changes or establish
|
||||
identity recognition.
|
||||
|
||||
## Validation and links
|
||||
|
||||
Run `python -B -m unittest discover -s tools/bfi -v` and the focused
|
||||
`test_traffic_coverage.py` suite under `tools/bfi_learning`. Synthetic tests
|
||||
check parsing and interval rules; acceptance additionally requires retained
|
||||
real captures and the three successful trials above.
|
||||
|
||||
- Extends proposed [ADR-118](ADR-118-bfld-beamforming-feedback-layer-for-detection.md)
|
||||
and [ADR-123](ADR-123-bfld-capture-path-nexmon-and-esp32.md); neither is superseded.
|
||||
- Preserves [ADR-120](ADR-120-bfld-privacy-class-and-hash-rotation.md)'s privacy boundary.
|
||||
- Public-data admission has a separate contract in
|
||||
[ADR-365](ADR-365-public-bfi-dataset-and-decoder-contract.md).
|
||||
@@ -0,0 +1,121 @@
|
||||
# ADR-365: Public BFI dataset and decoder contract
|
||||
|
||||
- **Status**: proposed
|
||||
- **Date**: 2026-09-29
|
||||
- **Deciders**: RuView maintainers; acceptance pending
|
||||
- **Tags**: bfi, datasets, decoding, provenance, benchmarks
|
||||
|
||||
## Context
|
||||
|
||||
Public activity recordings offer a separate route to BFI model development
|
||||
while local capture continuity is insufficient. They introduce different frame
|
||||
formats, collection assumptions and licenses. Public HAR activity labels do
|
||||
not reproduce KIT's person-identification experiment.
|
||||
|
||||
**MEASURED:** the pinned CSI-BFI-HAR train/validation download passed exact
|
||||
size/hash checks for 120 captures plus its license card. A separate body decoder
|
||||
matched 13,104 quantized angles across 14 sample bodies against tshark 4.2.2 in
|
||||
two independent executions. Whole-packet admission and activity training remain
|
||||
incomplete. See [results](../../tools/bfi_learning/RESULTS.md) and the
|
||||
[decoder audit and reproducer](../../tools/bfi_learning/PUBLIC-BFI-DECODE.md).
|
||||
|
||||
## Decision
|
||||
|
||||
### Pin provenance and partitions
|
||||
|
||||
Use the [author dataset](https://huggingface.co/datasets/foysalhaque/CSI-BFI-HAR-Dataset/tree/c3013b3edc5a563a9cf6759f5d464a9d9b6f456a)
|
||||
at revision `c3013b3edc5a563a9cf6759f5d464a9d9b6f456a`. The
|
||||
[manifest](../../tools/bfi_learning/manifests/csi-bfi-har-c3013b3-subset.json)
|
||||
pins URLs, lengths, SHA-256, labels and split membership. Preserve the pinned
|
||||
dataset card's GPL-3.0 declaration and attribution separately from code licenses.
|
||||
|
||||
| Partition | Author directory | Domain |
|
||||
| --- | --- | --- |
|
||||
| Training | HAR-1/BFI/M1 | Day 1, kitchen |
|
||||
| Validation | HAR-3/BFI/M1 | Day 3, classroom |
|
||||
| Held out | HAR-5/BFI/M1 and M2 | Day 5, living room; two views |
|
||||
|
||||
Keep all views of one event in the same partition. Day and room are confounded;
|
||||
M1/M2 labels do not establish heterogeneous-chipset transfer. The selected
|
||||
filenames cover A–T activities and P1–P3 participants.
|
||||
|
||||
Default downloads exclude held-out views. The bounded
|
||||
[downloader](../../tools/bfi_learning/download_public_bfi.py) verifies exact
|
||||
bytes before atomic completion, rehashes resumed files, retains failed partials
|
||||
and enforces transfer deadlines and byte limits. Data stays outside Git;
|
||||
downloaded code is never executed by the downloader.
|
||||
|
||||
### Keep body decoding separate from packet admission
|
||||
|
||||
[public_bfi_decode.py](../../tools/bfi_learning/public_bfi_decode.py) accepts
|
||||
only the audited VHT MU 3x1, 80 MHz, Ng=1, codebook-1 complete action body:
|
||||
1,003 bytes containing one SNR byte, 936 angle bytes and 61 opaque MU-exclusive
|
||||
bytes. It exposes quantized/radian angles and tone ordinals. Frequency indices,
|
||||
exclusive-field interpretation and validated matrix reconstruction remain
|
||||
separate acceptance work.
|
||||
|
||||
Twelve sample frames have nonzero fragment-number bits. Successful tshark
|
||||
decoding and valid CRCs do not resolve their semantics. Retain live MAC guards;
|
||||
quarantine these frames until an explicit, independently reviewed dataset
|
||||
policy can justify admission. Require lossless pcapng conversion evidence for
|
||||
integer timestamps, packet lengths, link types and all original packet bytes.
|
||||
Do not silently strip headers or rewrite fragment fields to gain admission.
|
||||
|
||||
The natural circular representation needs 1,404 features, exceeding the current
|
||||
trainer's 1,024-feature limit. Approve a bounded representation or revised limit
|
||||
with allocation tests before integration; do not truncate tones implicitly.
|
||||
|
||||
### Admit recording quality before scoring models
|
||||
|
||||
Inventory every manifest file, including tiny or unusable traces. Freeze a
|
||||
five-second observed-interval rule: at least 20 valid unique reports, with no
|
||||
inter-report gap above one second and no interpolation. Require at least two
|
||||
independent recordings per activity in each partition/view group that supply
|
||||
an eligible interval. Missing A–T coverage fails benchmark admission.
|
||||
Before implementing the census, also freeze interval anchoring, stride and
|
||||
leading/trailing gap rules: an inter-report gap bound alone does not bound
|
||||
silence at interval edges. These details remain required acceptance work.
|
||||
|
||||
Public files lack trusted recorder start/end manifests. Observed packet spans
|
||||
cannot establish unobserved leading/trailing coverage. Report rejection reasons,
|
||||
eligible recording/time coverage and accuracy together. Freeze event/file groups
|
||||
before generating windows; inspect held-out quality without model selection
|
||||
against held-out outcomes.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Reusing the HE/SU parser without format admission, weakening live fragment
|
||||
guards, or silently dropping sparse classes would change the task while hiding
|
||||
the change. Keep this adapter explicit and fail incomplete benchmark coverage.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
Data provenance, protocol support and score coverage remain independently
|
||||
auditable. New public formats cannot silently weaken live capture validation.
|
||||
|
||||
### Negative
|
||||
|
||||
Sparse files or unresolved framing may prevent a benchmark despite a successful
|
||||
download. Format and representation work must precede model optimization.
|
||||
|
||||
### Neutral
|
||||
|
||||
This is offline research/reference tooling. Production integration must reuse
|
||||
the Rust protocols in [ADR-291](ADR-291-public-benchmark-evaluation-harness.md)
|
||||
and scorecards in [ADR-317](ADR-317-benchmark-multi-domain-scorecard.md); this ADR
|
||||
does not establish a second production trainer or an integrated benchmark score.
|
||||
|
||||
## Validation and links
|
||||
|
||||
Use `test_download_public_bfi.py` and `test_public_bfi_decode.py` under
|
||||
`tools/bfi_learning`, then the full packet oracle and quality census specified
|
||||
in the [decode audit](../../tools/bfi_learning/PUBLIC-BFI-DECODE.md) and
|
||||
[benchmark protocol](../../tools/bfi_learning/RESEARCH-NEXT.md).
|
||||
|
||||
- Depends on [ADR-364](ADR-364-bfi-capture-admission-and-continuity.md)'s distinction
|
||||
between packet validity and coverage.
|
||||
- Preserves [ADR-120](ADR-120-bfld-privacy-class-and-hash-rotation.md).
|
||||
- [ADR-119](ADR-119-bfld-frame-format-and-wire-protocol.md) defines a BFLD envelope;
|
||||
that envelope does not replace raw 802.11 decoding.
|
||||
@@ -0,0 +1,115 @@
|
||||
# ADR-366: CSI controls and frozen evaluation
|
||||
|
||||
- **Status**: proposed
|
||||
- **Date**: 2026-09-29
|
||||
- **Deciders**: RuView maintainers; acceptance pending
|
||||
- **Tags**: csi, evaluation, controls, holdout, evidence
|
||||
|
||||
## Context
|
||||
|
||||
The public NTU-Fi HumanID experiment uses 14 classes and a custom directory
|
||||
split of 238 training, 56 validation and 546 held-out recordings. It differs
|
||||
from the author's folder mapping. Physical acquisition-session independence
|
||||
is unknown; absence of exact duplicates cannot establish it.
|
||||
|
||||
**MEASURED:** each of six LSTM/GRU runs classified 56/56 validation recordings
|
||||
correctly. A fixed-alpha ridge model using only mean amplitudes also scored
|
||||
56/56. In a matched three-seed GRU diagnostic, raw/original, raw/shuffled and
|
||||
demeaned/original inputs each scored 56/56 for every seed; demeaned/shuffled
|
||||
scored 52/56, 55/56 and 56/56. Chronological motion is unnecessary for perfect
|
||||
accuracy on this validation split. The physical source of the predictive signal
|
||||
remains unresolved. [Measured results and reproduction receipts](../../tools/bfi_learning/RESULTS.md)
|
||||
|
||||
## Decision
|
||||
|
||||
### Separate diagnostics from claims of generalization
|
||||
|
||||
Use static and temporal controls before interpreting a sequence-model score.
|
||||
Keep input files, optimizer budgets and seeds matched across raw/original,
|
||||
raw/shuffled, demeaned/original and demeaned/shuffled conditions. Permute whole
|
||||
feature rows within one recording, using source/seed information without labels.
|
||||
Never mix partitions. Mark shuffled time coordinates as administrative.
|
||||
|
||||
Whole-recording demeaning is an offline diagnostic that sees the complete
|
||||
recording. It cannot substantiate causal streaming inference. These nondefault
|
||||
controls are restricted to the custom public identity protocol and cannot alter
|
||||
next-observation BFI forecasting. Fit normalization on training inputs only.
|
||||
|
||||
Report recording-level accuracy, macro-F1, included recordings and seed variation
|
||||
alongside validation cross entropy averaged over selected windows. Recording
|
||||
predictions aggregate softmax probabilities across their selected windows;
|
||||
the current loss is not computed from those recording aggregates. Treat window
|
||||
accuracy as secondary because overlapping windows and repeated seeds on the same
|
||||
recordings are not independent participant trials. Retain session-independence
|
||||
limitations beside every custom-split result.
|
||||
|
||||
### Freeze selection before final evaluation
|
||||
|
||||
Keep the [predeclared control protocol](../../tools/bfi_learning/CONTROLS.md):
|
||||
the twelve 50-epoch diagnostic runs are excluded from final-model selection.
|
||||
Only the six original raw/original 200-epoch LSTM/GRU runs are eligible. Select
|
||||
lowest window-averaged validation cross entropy, breaking ties by earlier
|
||||
completion. Do not substitute recording-aggregated loss or change this rule in
|
||||
response to a held-out outcome.
|
||||
|
||||
Freeze source, dataset, metadata, configuration and checkpoint hashes before
|
||||
the scheduled final evaluation. Load frozen weights without retraining. The
|
||||
trainer creates an exclusive one-use claim before holdout scoring and retains
|
||||
it even if scoring fails; a failure requires explicit review, not an automatic
|
||||
retry. This claim is scoped to the selected frozen-run directory; the controller
|
||||
enforces one final evaluation across the task's candidate directories. Stop
|
||||
tuning against that holdout after its result is inspected. At this decision's
|
||||
evidence checkpoint, final holdout metrics remain absent.
|
||||
|
||||
### Preserve executable provenance
|
||||
|
||||
Use bounded numeric NPZ inputs/checkpoints with pickle disabled and validate ZIP
|
||||
central-directory bounds before allocation. Verify hashes and restore recorded
|
||||
transformations during frozen evaluation. The launcher checks returned seed,
|
||||
protocol, configuration and `test: null` during tuning. Save incomplete runs
|
||||
and denominator changes explicitly rather than substituting successful runs.
|
||||
|
||||
Current Python tools are bounded offline reference experiments. Production
|
||||
benchmark integration continues through the Rust protocols and per-domain
|
||||
scorecards of ADR-291/317. A fair state-of-the-art comparison needs matched data,
|
||||
task, representation, partition, adaptation access and evaluation; this custom
|
||||
CSI result establishes neither BFI identity performance nor paper reproduction.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Validation accuracy alone cannot distinguish temporal learning from static
|
||||
cues. Random window splits would leak recordings across partitions. Expanding
|
||||
the eligible model set after diagnostics would change the predeclared selection
|
||||
procedure. Retain the frozen recording split and candidate set.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
Controls expose when model complexity or temporal claims lack experimental
|
||||
support. The final evaluation has a traceable selection rule and one-use record.
|
||||
|
||||
### Negative
|
||||
|
||||
A saturated validation set limits further optimization, and strict one-use
|
||||
evaluation makes interrupted scoring an explicit recovery decision. New-session
|
||||
evidence requires new data rather than additional fitting to this split.
|
||||
|
||||
### Neutral
|
||||
|
||||
The GRU has 24.8% fewer parameters than the tested LSTM, but measured peak GPU
|
||||
allocation was higher and elapsed times do not isolate an architecture speedup.
|
||||
Preserve these separate resource findings when comparing models.
|
||||
|
||||
## Validation and links
|
||||
|
||||
Run the focused `test_prepare.py`, `test_train.py`, `test_static_baseline.py`
|
||||
and `test_run_batch.py` suites under `tools/bfi_learning`. Synthetic isolation
|
||||
and restore tests complement the retained real-data receipts; neither establishes
|
||||
new-session generalization.
|
||||
|
||||
- Extends [ADR-291](ADR-291-public-benchmark-evaluation-harness.md) and
|
||||
[ADR-317](ADR-317-benchmark-multi-domain-scorecard.md) without superseding them.
|
||||
- [Comparison contract](../../tools/bfi_learning/RESEARCH.md),
|
||||
[trainer](../../tools/bfi_learning/train.py) and
|
||||
[overnight frozen-selection procedure](../../tools/bfi_learning/OVERNIGHT.md).
|
||||
@@ -0,0 +1,110 @@
|
||||
# ADR-367: Bounded research swarm and compute ownership
|
||||
|
||||
- **Status**: proposed
|
||||
- **Date**: 2026-09-29
|
||||
- **Deciders**: RuView maintainers; acceptance pending
|
||||
- **Tags**: orchestration, ruflo, codex, compute, provenance
|
||||
|
||||
## Context
|
||||
|
||||
Research, implementation and independent review can run concurrently, while
|
||||
GPU training, capture hardware and final evaluation need clear ownership.
|
||||
Registration in a swarm registry does not prove that a worker executed a task.
|
||||
Unbounded retries, duplicate schedulers or overlapping jobs can corrupt evidence
|
||||
and spend resources without improving an experiment.
|
||||
|
||||
**MEASURED at the September 29 checkpoint:** local GPU runs and Codex reviews
|
||||
completed with receipts. Federation enrollment returned `registration paused`
|
||||
and relay membership was rejected; no cross-host worker accepted a task.
|
||||
Shared-memory writes were blocked by the native-WAL guard. These limitations
|
||||
and the actual work locations are recorded in the
|
||||
[overnight procedure](../../tools/bfi_learning/OVERNIGHT.md).
|
||||
|
||||
## Decision
|
||||
|
||||
### Assign one owner to each mutable resource
|
||||
|
||||
The root controller owns each capture action, GPU batch, checkpoint-selection
|
||||
decision and final evaluation. Delegated workers receive bounded source/review
|
||||
tasks and explicit file ownership. Worker findings are untrusted proposals for
|
||||
controller review. Distinguish registration, dispatch, execution and verified
|
||||
completion in receipts; only execution evidence supports a completed-work claim.
|
||||
|
||||
Use the existing app heartbeat as the sole recurring scheduler for this task.
|
||||
Finite serial GPU loops are jobs within a wake, not independent recurring
|
||||
schedulers. Resume from receipts and verified lock ownership; completed runs
|
||||
are not repeated merely because a wake or supervisor restarts.
|
||||
|
||||
### Bound execution and audit outputs
|
||||
|
||||
The [GPU launcher](../../tools/bfi_learning/run_batch.py) uses Linux process
|
||||
groups, an exclusive batch lock, a 900-second trainer budget and a 1,020-second
|
||||
child timeout. The current experiment requires at least 4 GiB free GPU memory,
|
||||
caps the trainer's PyTorch allocator fraction at 20%, and bounds logs/metrics
|
||||
to 8 MiB. This allocator limit is not a whole-device memory reservation.
|
||||
Verify child hashes, seed, protocol, configuration and absence of test metrics
|
||||
before declaring success. Preserve unrelated GPU services; cleanup targets only
|
||||
owned processes. Audit matrix and batch ownership before changing stale locks.
|
||||
|
||||
The task-specific [Codex review wrapper](../../tools/bfi_learning/codex_iteration.py)
|
||||
uses bounded source snapshots on stdin, read-only sandboxing, execution rules,
|
||||
an exclusive lock, timeout and private event logs. This differs from the generic
|
||||
contributor adapter's configuration contract. Check events for unexpected tool
|
||||
execution; never execute suggestions automatically or grant child text authority.
|
||||
|
||||
Preserve federation and memory safety guards when a backend is unavailable.
|
||||
Use private local receipts as the fallback and report degraded coordination.
|
||||
Retry only after a relevant service/writer change or a concrete causal fix.
|
||||
|
||||
### Bind compute to an explicit task budget and end time
|
||||
|
||||
Use local capacity first. A paid GPU needs a measured capacity requirement and
|
||||
an explicitly authorized cumulative budget covering actual spend, outstanding
|
||||
reservations and fees. Before rental, check current prices, active instances
|
||||
and remaining allowance; reserve maximum bounded cost, enforce termination and
|
||||
verify resource cleanup. Transfer only authorized public licensed data and
|
||||
reviewed source. A future run needs its own applicable authorization.
|
||||
|
||||
For the current run, the authorized cap is USD 200, local RTX 5080 capacity has
|
||||
been sufficient and the recorded spend is USD 0. The existing schedule ends
|
||||
September 30, 2026 at 07:00 America/Toronto. Its final wake performs the frozen
|
||||
evaluation, reconciles owned jobs/resources and the ledger, records results,
|
||||
then pauses the heartbeat. These are run-specific values, not durable spending
|
||||
or scheduling authority granted by this ADR.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Multiple controllers per GPU, detached indefinite loops, and treating a
|
||||
registration response as an executed agent task make ownership unverifiable.
|
||||
Retain explicit owners, finite jobs and execution receipts instead.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
Parallel review remains useful while resource mutation and final evaluation
|
||||
have one accountable owner. Receipts support recovery without silent reruns.
|
||||
|
||||
### Negative
|
||||
|
||||
Serial GPU ownership can leave capacity unused. Federation or memory outages
|
||||
reduce coordination features, and bounded jobs may need reviewed continuation.
|
||||
|
||||
### Neutral
|
||||
|
||||
Source and sanitized documentation belong in the isolated worktree. Raw RF
|
||||
data, subject recordings, weights, logs, credentials and transcripts stay outside
|
||||
Git. A completed experiment does not authorize model promotion, firmware
|
||||
flashing, merging or publication.
|
||||
|
||||
## Validation and links
|
||||
|
||||
Run `test_run_batch.py` and `test_codex_iteration.py` under `tools/bfi_learning`.
|
||||
Audit real execution/cleanup receipts, lock owners, ledger and scheduler state
|
||||
at completion; successful synthetic tests alone cannot establish these outcomes.
|
||||
|
||||
- Preserves [ADR-283](ADR-283-ruview-community-metaharness-flywheel.md)'s
|
||||
proposal-only learning and maintainer promotion boundary.
|
||||
- Follows [ADR-321](ADR-321-decision-policy-action-authorization.md).
|
||||
- Depends on [ADR-366](ADR-366-csi-controls-and-frozen-evaluation.md) for frozen
|
||||
candidate selection and final holdout handling.
|
||||
@@ -0,0 +1,187 @@
|
||||
# ADR-368: RuView compute kernel as a WASM + napi-rs npm package
|
||||
|
||||
- **Status**: proposed
|
||||
- **Date**: 2026-09-30
|
||||
- **Deciders**: RuView maintainers; acceptance pending
|
||||
- **Tags**: npm, wasm, napi-rs, metaharness, vitals, supply-chain
|
||||
- **Related**: ADR-021 (vitals), ADR-263/265 (npm harness review and
|
||||
distribution), ADR-283 (community metaharness), ADR-285 (WASM-first Homecore
|
||||
metaharness)
|
||||
|
||||
## Context
|
||||
|
||||
`@ruvnet/ruview` (ADR-283) is a dependency-free operator/contributor harness:
|
||||
it guides, verifies, and delegates, but it cannot run RuView signal processing.
|
||||
JavaScript consumers (MCP hosts, dashboards, browser demos, agents) that want
|
||||
real RuView computation must today start the Rust sensing server or re-implement
|
||||
DSP in JS, which drifts from the Rust source of truth.
|
||||
|
||||
We want one Rust implementation reachable from npm with:
|
||||
|
||||
1. a portable default that works on every Node platform and in browsers;
|
||||
2. an optional native path for hosts that want it;
|
||||
3. the metaharness trust posture: least authority by default, the backend that
|
||||
actually ran is always reported, fail-closed on missing or tampered
|
||||
artifacts, and no accuracy claim without an evidence tag.
|
||||
|
||||
## Decision
|
||||
|
||||
### One core, one ABI, two transports
|
||||
|
||||
- **`v2/crates/ruview-kernel`** (workspace member) wraps the ADR-021 pipeline
|
||||
from `wifi-densepose-vitals` (EMA preprocessing, breathing 0.1–0.5 Hz, heart
|
||||
0.8–2.0 Hz, anomaly z-score) in a streaming `Session`, a deterministic
|
||||
SplitMix64 synthetic-CSI generator, and a bounded session registry.
|
||||
- The entire ABI is one function: `call(op, request_json) -> envelope_json`,
|
||||
returning `{"ok":true,"result":…}` or
|
||||
`{"ok":false,"error":{"code","message"}}`. Operations: `info`,
|
||||
`validate_config`, `analyze`, `synthesize`, `session_open|push|summary|close`.
|
||||
Keeping the ABI to a single string function makes backend parity a property
|
||||
of the transport rather than of duplicated bindings.
|
||||
- **WASM transport** (`src/wasm_abi.rs`, `wasm32-unknown-unknown` only):
|
||||
`rvk_alloc`/`rvk_free`/`rvk_call`/`rvk_abi_version`. The module has **zero
|
||||
imports** — no filesystem, network, clock, or randomness. The JS loader
|
||||
refuses any module that imports host functions.
|
||||
- **napi-rs transport** (`v2/crates/ruview-kernel-napi`): exports only
|
||||
`abiVersion()` and `call(op, json)`. It is a standalone Cargo workspace
|
||||
(listed in the v2 `exclude`) so napi never enters
|
||||
`cargo test --workspace`, and it builds with `panic = "unwind"` plus
|
||||
`catch_unwind` so a defect becomes an error envelope, not a Node crash.
|
||||
|
||||
### Input is untrusted at the ABI
|
||||
|
||||
Requests are bounded before processing: 16 MiB per request, 512 subcarriers,
|
||||
100 000 frames per call or synthesis, 64 concurrent sessions. Unknown JSON
|
||||
fields are rejected (`deny_unknown_fields`); frame widths must match the
|
||||
configured subcarrier count; values must be finite with magnitude ≤ 1e9; all
|
||||
frames of a batch are validated before any is processed. The core returns an
|
||||
error envelope instead of panicking on caller data (release builds of the WASM
|
||||
module use `panic = "abort"`, which the loader surfaces as a `trap` and
|
||||
recovers from with a fresh instance).
|
||||
|
||||
### npm package `@ruvnet/ruview-kernel` (`harness/ruview-kernel`)
|
||||
|
||||
- Zero runtime dependencies. `loadKernel({backend})` with
|
||||
`backend ∈ {wasm (default), napi, auto}` or `RUVIEW_KERNEL_BACKEND`.
|
||||
WASM is the default because it carries no host authority. `napi` never
|
||||
silently falls back; `auto` prefers napi and records `fallbackReason`.
|
||||
- Artifacts are built from source by `npm run build` (`scripts/build.mjs`,
|
||||
no shell) into `wasm/` and `native/ruview_kernel.<triple>.node`, with
|
||||
`SHA256SUMS`. The loader verifies checksums; a mismatch is always fatal and
|
||||
never an `auto` fallback trigger; `requireIntegrity` also refuses
|
||||
unchecksummed artifacts. Built artifacts are git-ignored and never committed.
|
||||
- `src/wasm.js` is filesystem-free, so browsers can use
|
||||
`loadWasmKernelFromBytes(bytes)`.
|
||||
- CLI `ruview-kernel`: `doctor`, `info`, `selftest`, `parity`, `synth`,
|
||||
`analyze --file`, `bench`. `synth --out` refuses to overwrite files;
|
||||
`analyze` reads only a bounded regular file.
|
||||
- `selfTest()` runs synthesize → analyze → chunked streaming session → hostile
|
||||
input, and asserts known-tone recovery. `parity()` diffs every output of
|
||||
both backends with a 1e-9 relative tolerance, because `sin`/`exp` come from
|
||||
different libm implementations on wasm32 and native targets; exact JSON
|
||||
equality is reported separately and is not required.
|
||||
|
||||
### Metaharness integration
|
||||
|
||||
`@ruvnet/ruview` gains the read-only tool `ruview_kernel_selftest`
|
||||
(CLI: `ruview kernel [--backend …]`). It dynamically imports the fixed
|
||||
specifier `@ruvnet/ruview-kernel`, so `@ruvnet/ruview` keeps zero runtime
|
||||
dependencies, and it returns `kernel_not_installed` when the package is absent.
|
||||
MCP arguments are limited to `backend` and `seconds`; they cannot choose a
|
||||
module or artifact path. The capability appears in `ruview_guidance` as
|
||||
`portable-compute-kernel`.
|
||||
|
||||
## Evidence
|
||||
|
||||
- **SYNTHETIC** (`cd harness/ruview-kernel && node bin/cli.js selftest`):
|
||||
60 s at 20 Hz, 56 subcarriers, 15 bpm breathing and 72 bpm heart tones →
|
||||
recovered 15.0 bpm respiratory (valid) and 70.6 bpm heart (degraded
|
||||
confidence 0.44). Tolerances asserted: ±3 bpm respiratory, ±8 bpm heart.
|
||||
- **SYNTHETIC** parity (`node bin/cli.js parity`): 900 frames / 45 readings,
|
||||
no difference above 1e-9 relative between wasm32 and linux-x64-gnu napi;
|
||||
outputs are not byte-identical.
|
||||
- **MEASURED** on one Linux x64 development container
|
||||
(`node bin/cli.js bench --backend wasm|napi --seconds 120`): about 78 ms
|
||||
(wasm) and 63 ms (napi) per 2 400-frame `analyze`, including JSON transfer.
|
||||
Single-host timing, not a cross-platform claim.
|
||||
- The WASM release artifact is about 230 KB and imports nothing
|
||||
(`node scripts/verify-artifacts.mjs --require-wasm`).
|
||||
|
||||
None of these numbers says anything about real-world vital-sign accuracy.
|
||||
That still requires the ADR-293 ground-truth protocol with a reference device.
|
||||
|
||||
## Amendment 1 (2026-10-01): binary transport and optimization evidence
|
||||
|
||||
**Profile (MEASURED on one Linux x64 development container, 2 400 frames ×
|
||||
56 subcarriers).** JSON was the dominant cost:
|
||||
|
||||
- JS `JSON.stringify` of the request alone took 52–78 ms against
|
||||
107–124 ms for a whole `analyze`.
|
||||
- Rust then re-parsed about 270 000 numbers.
|
||||
|
||||
**Decision.** Add a binary fast path without changing the ABI version.
|
||||
|
||||
- New operations `analyze_flat` and `session_push_flat`, carried by
|
||||
`call_f64(op, json, &[f64])`:
|
||||
- WASM: `rvk_call_f64`, which reads bytes so alignment does not matter;
|
||||
- napi: `callF64(op, json, Float64Array)`.
|
||||
- `analyze()` and `session.push()` pack uniform frames into one
|
||||
`Float64Array` (all amplitudes, then all phases) and use the binary path
|
||||
automatically. Irregular input still takes the JSON path so its error names
|
||||
the bad frame.
|
||||
- `analyzeFlat(Float64Array, …)` is the zero-copy entry.
|
||||
- `Session::step` is shared by both paths.
|
||||
|
||||
**Evidence.**
|
||||
|
||||
- **Byte-identical outputs.** On identical `f64` inputs the two paths
|
||||
produce byte-identical JSON (`tests/abi.rs`).
|
||||
- **A JSON precision finding.** serde_json's default float parser is not
|
||||
correctly rounded, so the JSON transport perturbs inputs by ULPs (34 of 160
|
||||
amplitude values in a 2 s, 4-subcarrier SYNTHETIC sample). The binary path is bit-exact.
|
||||
- **Speed.** MEASURED, `ruview-kernel bench --seconds 120`, same host:
|
||||
|
||||
| Backend | JSON transport | Binary transport | Speed-up |
|
||||
|---|---|---|---|
|
||||
| wasm | 134.8 ms | 47.8 ms (~50 000 frames/s) | 2.82× |
|
||||
| napi | 109.7 ms | 44.8 ms (~53 600 frames/s) | 2.45× |
|
||||
|
||||
- **Remaining cost is DSP.** Native timing gives heart-rate extraction
|
||||
20.8–22.9 ms of 30.6–38.3 ms (about 60–68%, MEASURED; reproducer:
|
||||
`cargo run --release -p ruview-kernel --example profile_stages`): the per-frame autocorrelation over the 15 s window
|
||||
in `wifi-densepose-vitals`. That crate is shared with the production sensing
|
||||
server, and an incremental ACF would change floating-point summation order
|
||||
and therefore outputs. It is left as a follow-up that needs its own review
|
||||
and regression evidence.
|
||||
|
||||
**Rejected after measurement.** MEASURED, three runs on the same host;
|
||||
reproducer: `node bench/wasm-variants.mjs` in `harness/ruview-kernel`. Each
|
||||
run is the median of 15 `analyzeFlat` calls on 2 400 frames. All variants
|
||||
produced byte-identical outputs.
|
||||
|
||||
| Variant | Size | Median ms (3 runs) | Decision |
|
||||
|---|---|---|---|
|
||||
| baseline (`opt-level = 3`) | 244 KB | 38.3–40.6 | kept |
|
||||
| `+simd128` | 242 KB | 37.4–54.7 | rejected: no consistent gain, and it needs SIMD-capable engines |
|
||||
| `opt-level = "s"` | 227 KB | 40.8–70.1 | rejected: consistently slower for a 17 KB size saving |
|
||||
|
||||
## Consequences
|
||||
|
||||
- JavaScript consumers get real RuView DSP without a server, in Node or the
|
||||
browser, with one Rust source of truth.
|
||||
- A second native build matrix exists. Until per-platform packages
|
||||
(`@ruvnet/ruview-kernel-<triple>`) are published by CI, only WASM is
|
||||
portable; the loader already resolves those package names.
|
||||
- JSON transfer dominates the cost of small calls; a typed-array fast path can
|
||||
be added later behind a new ABI version.
|
||||
|
||||
## Rollout and rollback
|
||||
|
||||
1. CI (`ruview-kernel-npm.yml`) builds both transports from source, runs the
|
||||
Rust tests, the package tests with `RUVIEW_KERNEL_REQUIRE_NAPI=1`, parity,
|
||||
artifact verification, and `npm pack --dry-run`.
|
||||
2. Publication stays CI-only with provenance (ADR-265) and requires explicit
|
||||
maintainer approval; this ADR does not add a publish job.
|
||||
3. Rollback: remove the `ruview_kernel_selftest` tool (the harness has no
|
||||
dependency on the package) and deprecate the npm version; the Rust crates
|
||||
are additive.
|
||||
@@ -0,0 +1,74 @@
|
||||
# ADR-369: npm RuView operator surface — CLI, MCP, and SDK over one registry
|
||||
|
||||
- **Status**: proposed
|
||||
- **Date**: 2026-09-30
|
||||
- **Deciders**: RuView maintainers; acceptance pending
|
||||
- **Tags**: npm, mcp, sdk, cli, metaharness, least-authority
|
||||
- **Related**: ADR-263/265 (npm harness review and distribution), ADR-283
|
||||
(community metaharness), ADR-368 (compute kernel), ADR-370 (flashing),
|
||||
ADR-371 (training), ADR-372 (doctor)
|
||||
|
||||
## Context
|
||||
|
||||
`@ruvnet/ruview` 0.5.x could onboard, lint claims, verify the proof, monitor a
|
||||
node, and read Cognitum Spaces. Three operator jobs still left the package:
|
||||
|
||||
- **Flashing** was a Windows-only stub that returned `manual_step_required`.
|
||||
- **Training** had only a skill document; nothing ran a trainer or checked
|
||||
results mechanically.
|
||||
- **Diagnostics**: `doctor` printed six PASS/FAIL lines without remedies.
|
||||
|
||||
There was also no programmatic API. Integrators had to shell out to the CLI or
|
||||
speak MCP.
|
||||
|
||||
## Decision
|
||||
|
||||
1. **One registry, three front ends.** Every capability is a `ruview_*` tool
|
||||
in `src/tools.js`, with a JSON schema, a `TOOL_POLICY` class, and a
|
||||
structured, fail-closed result. The CLI verbs, the MCP server, and the new
|
||||
SDK all go through `runTool`. There is one argument validator and one
|
||||
authorization path.
|
||||
2. **SDK** (`@ruvnet/ruview/sdk`, typed by `src/sdk.d.ts`). `createRuView()`
|
||||
returns a frozen object with `doctor`, `firmware.{ports,plan,flash,monitor}`,
|
||||
`training.{plan,run,gate,calibrate}`, `kernel.{selfTest,load}`, `guidance`,
|
||||
`claimCheck`, `verify`, `spaces`, `memorySearch`, `call`, `tools`, and
|
||||
`startMcpServer`.
|
||||
- Calls run with `source: 'sdk'`: trusted in-process code, like the CLI.
|
||||
Mutating tools still refuse to act without `confirm: true`.
|
||||
- `{ strict: true }` turns `ok:false` into a `RuViewError`.
|
||||
3. **Plan/act split for every mutation.**
|
||||
- `ruview_firmware_plan` and `ruview_train_plan` are read-only and their
|
||||
schemas do not accept `confirm`. An MCP client without write grants can
|
||||
review the exact command.
|
||||
- The acting tools (`ruview_node_flash`, `ruview_train`) keep the existing
|
||||
grant-plus-confirm gate: `hardware-write` and `workspace-write`.
|
||||
4. **New tools**: `ruview_doctor`, `ruview_firmware_plan`,
|
||||
`ruview_firmware_ports`, `ruview_train`, `ruview_train_plan`,
|
||||
`ruview_train_gate`. `ruview_node_flash` is re-implemented (ADR-370).
|
||||
`TOOL_POLICY`, `.harness/claims.json`, and `.harness/mcp-policy.json` are
|
||||
kept in lock-step, and a test fails on any drift.
|
||||
5. **Process execution** for operator tools goes through `src/exec.js`:
|
||||
- argv only, never a shell;
|
||||
- a scrubbed environment: the base allowlist plus toolchain locations such
|
||||
as `LIBTORCH`, `CARGO_HOME`, `VIRTUAL_ENV` and `IDF_PATH`, and no
|
||||
credentials;
|
||||
- bounded output, and secrets redacted.
|
||||
6. **Zero runtime dependencies stays.** The optional compute kernel
|
||||
(ADR-368) is loaded dynamically. Version 0.6.0. The unpacked-size ceiling
|
||||
rises from 160 KiB to 224 KiB for the new modules, with the budget recorded
|
||||
in both npm workflows.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Agents, scripts, and humans get the same behaviour and the same refusals.
|
||||
- The package now drives real hardware and training. Keeping the plan/act
|
||||
split and argv-only execution is essential, and tests pin both.
|
||||
- The surface is larger (16 MCP tools). Hosts that cap tool counts can
|
||||
filter by annotations (`readOnlyHint`).
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `cd harness/ruview && npm test && npm run test:security` (drift test in
|
||||
`test/sdk.test.mjs`).
|
||||
- `npx @ruvnet/ruview tools` lists 16 tools. `node -e "import('@ruvnet/ruview/sdk')"`
|
||||
resolves from an installed tarball.
|
||||
@@ -0,0 +1,83 @@
|
||||
# ADR-370: Cross-platform, verified ESP32 firmware flashing from npm
|
||||
|
||||
- **Status**: proposed
|
||||
- **Date**: 2026-09-30
|
||||
- **Deciders**: RuView maintainers; acceptance pending
|
||||
- **Tags**: firmware, esp32, esptool, supply-chain, hardware-evidence
|
||||
- **Related**: ADR-028 (capability audit / witness), ADR-369, firmware
|
||||
`README.md` §0 and §2
|
||||
|
||||
## Context
|
||||
|
||||
The documented flash procedure is four `esptool write_flash` offsets. It is
|
||||
typed by hand, and a wrong chip, wrong flash size, or tampered image can brick
|
||||
a board or silently run the wrong firmware. The previous `ruview_node_flash`
|
||||
was Windows-only and never flashed. Project rules also say that a successful
|
||||
build or write is **not** hardware validation; that requires a captured
|
||||
boot/runtime log from real silicon.
|
||||
|
||||
## Decision
|
||||
|
||||
`src/firmware.js` implements plan → verify → preflight → write → evidence:
|
||||
|
||||
1. **Variants**:
|
||||
- `s3-8mb` → `esp32s3` / 8MB
|
||||
- `s3-4mb` → `esp32s3` / 4MB; prefers `*-4mb.bin` images
|
||||
- `c6` → `esp32c6` / 4MB
|
||||
|
||||
Offsets follow the shipped partition tables: bootloader `0x0`, partition
|
||||
table `0x8000`, optional OTA data `0xf000`, app `0x20000`. NVS is never
|
||||
written, so WiFi and node configuration survive.
|
||||
2. **Bundle verification**. A bundle is an extracted release flash bundle,
|
||||
`release_bins/<variant>`, or an ESP-IDF `build/` directory.
|
||||
- Every image must match `SHA256SUMS` or `SHA256SUMS.txt`. A mismatch is
|
||||
always fatal.
|
||||
- Missing checksums are refused unless `allow_unverified` is set, which is
|
||||
for local builds only.
|
||||
- Images must be regular, non-empty files of at most 16 MiB, inside the
|
||||
bundle; symlinks that escape the bundle are refused.
|
||||
- An 8 MB variant refuses a 4 MB partition table.
|
||||
- A bundle without OTA data produces an explicit warning (a node on `ota_1`
|
||||
keeps booting `ota_1`).
|
||||
3. **Argv, not shell.**
|
||||
- The port must match `COM<n>` or `/dev/(tty|cu)*`.
|
||||
- Baud comes from a fixed set.
|
||||
- The command is `python -m esptool --chip … --port … --baud … write_flash
|
||||
--flash_mode dio --flash_size … <offset> <file>…`. The underscore forms
|
||||
work in both esptool 4.x and 5.x.
|
||||
4. **Chip preflight.** `esptool chip_id` must report the variant's chip. The
|
||||
parser covers the 4.x "Chip is" and 5.x "Chip type:" / "Detecting chip
|
||||
type…" formats. A mismatch or missing response stops the flow before any
|
||||
write.
|
||||
5. **Evidence.** After a write, a read-only pyserial capture (default 15 s,
|
||||
port and duration passed as argv) is summarized: line count, CSI
|
||||
callbacks, MGMT+DATA upgrade, panic markers, firmware version.
|
||||
- `hardwareValidated: true` only when CSI callbacks appear with no panic;
|
||||
the result's `evidence` is then `MEASURED` with a boot-log reason.
|
||||
- Otherwise the result states the board is not validated.
|
||||
6. **Authority.** Without `confirm` the result is a plan. MCP needs the
|
||||
`hardware-write` grant plus `confirm`. `ruview_firmware_plan` and
|
||||
`ruview_firmware_ports` are read-only.
|
||||
7. **Provisioning stays out.** WiFi credentials remain in `provision.py`, so
|
||||
they never enter harness arguments, logs, or MCP transcripts.
|
||||
|
||||
## Evidence
|
||||
|
||||
- `npx @ruvnet/ruview doctor --group firmware` verified all four checked-in
|
||||
`release_bins` bundles (c6-adr110, c6-onboarding, s3-adr110,
|
||||
s3-fair-adr110) against their `SHA256SUMS.txt` in this change's development
|
||||
container.
|
||||
- The write and preflight paths are covered by tests with injected fake
|
||||
hardware: mismatch refusal, probe failure, flash failure, boot-log
|
||||
validation, and a silent log that yields no validation.
|
||||
- **No real board was flashed** during this change, so real-silicon validation
|
||||
is outstanding.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Operators on any OS get one verified command. Agents can review plans
|
||||
without hardware authority.
|
||||
- The workflow depends on Python, esptool, and pyserial. `doctor` reports each
|
||||
one with a fix.
|
||||
- Follow-up: an ADR-028 witness record could store the boot-log summary and
|
||||
image digests.
|
||||
@@ -0,0 +1,91 @@
|
||||
# ADR-371: Harness training runner and mean-pose evidence gate
|
||||
|
||||
- **Status**: proposed
|
||||
- **Date**: 2026-09-30
|
||||
- **Deciders**: RuView maintainers; acceptance pending
|
||||
- **Tags**: training, evaluation, evidence, pose, honesty
|
||||
- **Related**: ADR-079 (camera-supervised pose), ADR-151 (room calibration),
|
||||
ADR-181 (baseline-relative PCK), ADR-369
|
||||
|
||||
## Context
|
||||
|
||||
RuView has a retracted pose result (a CLAIMED 92.9%/100% that did not survive
|
||||
baseline and leakage review). The project rule is that pose
|
||||
PCK is quoted only with the mean-pose baseline, on a leakage-free held-out
|
||||
split, with an evidence tag. The `train-pose` skill says this in prose, but
|
||||
nothing enforces it. Running the trainers also needs repository knowledge:
|
||||
the `tch-backend` feature, a libtorch version match, and where checkpoints go.
|
||||
|
||||
## Decision
|
||||
|
||||
### Gate (`ruview_train_gate`, pure, read-only)
|
||||
|
||||
The input is a small report: metric, model and baseline score, split,
|
||||
train/test subjects, train end and test start, `n_test`, reproducer, and data
|
||||
source.
|
||||
|
||||
**Hard failures:**
|
||||
- no baseline;
|
||||
- a random-frame split, or any split outside chronological / blocked-gap /
|
||||
grouped-subject / grouped-session;
|
||||
- subject overlap in a grouped-subject split;
|
||||
- missing or overlapping time bounds for chronological or blocked-gap splits;
|
||||
- no improvement over the baseline.
|
||||
|
||||
**Warnings:**
|
||||
- subjects not reported;
|
||||
- subjects overlapping in non-subject splits;
|
||||
- `n_test` < 100;
|
||||
- a near-perfect score: at or above the `implausible_score` threshold in
|
||||
`src/training.js`.
|
||||
|
||||
**Evidence tag:** `SYNTHETIC` when `data: synthetic`, `MEASURED` only with a
|
||||
reproducer, otherwise `CLAIMED`.
|
||||
|
||||
On PASS the gate returns the one acceptable sentence:
|
||||
`Held-out <metric> X% vs Y% mean-pose baseline = +Z pp (<tag>, …, <split> split).`
|
||||
|
||||
### Runner (`ruview_train`, `ruview_train_plan`)
|
||||
|
||||
Modes:
|
||||
- `pose-smoke`: `wifi-densepose-train` `train --dry-run` on the synthetic
|
||||
dataset.
|
||||
- `pose`: `--data-dir`, MM-Fi recordings.
|
||||
- `room`: `wifi-densepose train-room`, or `cargo run -p wifi-densepose-cli`
|
||||
when the binary is absent.
|
||||
|
||||
Rules:
|
||||
- All caller paths (config, data, checkpoints, enrollment, output) must
|
||||
resolve inside the trusted checkout. Realpaths are checked for inputs that
|
||||
already exist.
|
||||
- Pose runs use `cargo run --manifest-path v2/Cargo.toml` with the working
|
||||
directory set to the checkpoint directory, default
|
||||
`v2/target/ruview-train/<mode>`. The trainer's relative `logs/` therefore
|
||||
never lands in the source tree.
|
||||
- Without `confirm` it returns a plan. MCP requires `workspace-write` plus
|
||||
`confirm`.
|
||||
- Failures are classified with remedies:
|
||||
- libtorch absent;
|
||||
- libtorch version mismatch (tch 0.24 expects torch 2.11.0);
|
||||
- link failure.
|
||||
|
||||
## Evidence
|
||||
|
||||
- **SYNTHETIC** (`npx @ruvnet/ruview train --mode pose-smoke --samples 16
|
||||
--confirm`, CPU PyTorch 2.11.0, `LIBTORCH_USE_PYTORCH=1`, Linux x64): the
|
||||
real trainer compiled, ran 20 epochs with early stopping, and wrote
|
||||
safetensors checkpoints and `logs/training_log.csv` under
|
||||
`v2/target/ruview-train/pose-smoke`. The trainer labels its own smoke
|
||||
metrics "DO NOT REPORT". None are reported here.
|
||||
- With PyTorch 2.14.1 the tch 0.24 C++ shim failed to compile. The runner
|
||||
classified this as a version mismatch rather than a missing install.
|
||||
- The gate is covered by `test/training.test.mjs`, including the leakage
|
||||
patterns behind the retraction.
|
||||
|
||||
## Consequences
|
||||
|
||||
- A number can pass through the harness only with its baseline and split
|
||||
attached. The gate does not verify the arithmetic that produced the input;
|
||||
reviewers must still re-run the reproducer.
|
||||
- Training needs the Rust toolchain and a matching libtorch. `doctor` covers
|
||||
Rust; libtorch is detected at run time.
|
||||