diff --git a/HANDOFF.md b/HANDOFF.md new file mode 100644 index 0000000..9395586 --- /dev/null +++ b/HANDOFF.md @@ -0,0 +1,21 @@ +# Home-page consistency handoff + +Goal: align compressionKIT with the KIT documentation sites and physioKIT. + +State: +- Done locally in `issue-79-kit-home-consistency`: replace the hero dot with the existing product icon, render the links below the hero with the shared helia-ui Button, and set `header.titleRegularPrefix` so the prefix is regular and KIT stays bold. The hero headline blends from icon-matched yellow on “Carry” toward bright green across “less data.” The home body follows the shared order: overview, four feature cards, source-checkout installation, and four navigation cards. Cards use CardHeader's full-card link and shared interactive focus treatment. +- Verified: Astro check and build pass. Link and layout audits pass (1,867 links; 404 layout checks), as do 12 content checks. The layout audit verifies readable shared quick buttons in both themes and pointer clicks in card bodies reaching their intended pages. Desktop, 785px and 390px mobile screenshots were inspected in light and dark mode; the icon renders and the page has no horizontal overflow. +- Preview: http://127.0.0.1:8778/compressionkit/ +- Tracked by AmbiqAI/compressionkit#79. Draft PR #80 is open; no release or deployment has occurred. + +Decisions: +- Reuse the repository's existing product icon and keep its current hero color and destination links. +- Use the shared Button component for the links under the hero; do not introduce a site-specific pill design. +- Pin helia-ui v0.1.0-alpha.24, published from f7158bf, with an npm 11.19.0 lockfile. Clean installs reproduce the shared header without a local patch. + +Next: finish checks against the released package, final review and CI, merge under Adam's authorization, then verify the Pages deployment. + +Not-found handling: restrict the product hero to the home route so unknown routes show the 404 page; built output and browser checks cover the fallback. + + +Release validation: clean installation of alpha.24 passed. Final check/build/output checks pass, with 404 rendered acceptance checks passing against the clean released dependency. User authorized merging after green CI. diff --git a/astro-site/astro.config.mjs b/astro-site/astro.config.mjs index a0b85e9..81320bf 100644 --- a/astro-site/astro.config.mjs +++ b/astro-site/astro.config.mjs @@ -64,6 +64,7 @@ export default defineConfig({ sidebar: "always", header: { title: "compressionKIT", + titleRegularPrefix: "compression", hub: { label: "HELIA", href: "https://ambiqai.github.io/helia-developer-hub/", diff --git a/astro-site/package-lock.json b/astro-site/package-lock.json index abada68..7281c2f 100644 --- a/astro-site/package-lock.json +++ b/astro-site/package-lock.json @@ -8,7 +8,7 @@ "name": "compressionkit-site", "version": "0.0.0", "dependencies": { - "@ambiqai/helia-ui": "https://codeload.github.com/AmbiqAI/helia-ui/tar.gz/f523f6008aca7e1f9b4c3a17198f3f48da83cd7a", + "@ambiqai/helia-ui": "https://codeload.github.com/AmbiqAI/helia-ui/tar.gz/refs/tags/v0.1.0-alpha.24", "@astrojs/markdown-remark": "^7.3.1", "@astrojs/react": "7.0.0", "@astrojs/starlight": "^0.41.5", @@ -35,9 +35,9 @@ } }, "node_modules/@ambiqai/helia-ui": { - "version": "0.1.0-alpha.23", - "resolved": "https://codeload.github.com/AmbiqAI/helia-ui/tar.gz/f523f6008aca7e1f9b4c3a17198f3f48da83cd7a", - "integrity": "sha512-iJHUxf+O7RgA18Nl9TL4DY255fLY8P1BGH3Rg9p3gEKTRLkv0msD02qi0FZ8f4ihB0XkpU7/AxUEu4v1y7KgwQ==", + "version": "0.1.0-alpha.24", + "resolved": "https://codeload.github.com/AmbiqAI/helia-ui/tar.gz/refs/tags/v0.1.0-alpha.24", + "integrity": "sha512-9AXS5ZN95zlaGeCVZgSaM1r6/jHAiksqkTiUp4EX7l7hWkiDrguMeFgvfIR2q0i8XsjdA29lFlnoQH5RHq4AGg==", "license": "BSD-3-Clause", "dependencies": { "@fontsource-variable/roboto": "5.3.0", @@ -428,7 +428,6 @@ "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-7.3.1.tgz", "integrity": "sha512-QCjsjZQl0+Cgb91+T3Ip9hyUe1r5aLm4udi584rML9YO3syupbAYE+jWpAxYg+z4lFLNUugPrylFxZ+8qFTClg==", "license": "MIT", - "peer": true, "dependencies": { "@astrojs/internal-helpers": "0.11.0", "@astrojs/prism": "4.0.2", @@ -788,7 +787,6 @@ "resolved": "https://registry.npmjs.org/@astrojs/starlight/-/starlight-0.41.11.tgz", "integrity": "sha512-hM95Mbsl4l60SBwaNQA/HTxpOLGfeB5EfR9qY3kr0SsAVKUspCssjO0RVBsLiPAE6EA5xuORcCoz/Q6DTX+MuQ==", "license": "MIT", - "peer": true, "dependencies": { "@astrojs/markdown-satteri": "^0.3.5", "@astrojs/mdx": "^7.0.5", @@ -1183,7 +1181,6 @@ "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@emnapi/wasi-threads": "1.2.3", "tslib": "^2.4.0" @@ -1195,7 +1192,6 @@ "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -3167,7 +3163,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -3177,7 +3172,6 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.3.0.tgz", "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.3.0" } @@ -3359,7 +3353,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3382,7 +3375,6 @@ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -3527,7 +3519,6 @@ "resolved": "https://registry.npmjs.org/astro/-/astro-7.3.3.tgz", "integrity": "sha512-NF08hk3edFkVmr9avf9HW/rQyf6NrpbVDyYj2cVN3JfijDhfJYh1ivWVTY5PUd5+rRZn/Vtu4iaeyNlP0Iv6mg==", "license": "MIT", - "peer": true, "dependencies": { "@astrojs/compiler-rs": "^0.4.0", "@astrojs/internal-helpers": "0.11.0", @@ -4218,7 +4209,6 @@ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.3.tgz", "integrity": "sha512-yfYGhRcGAntq6YBD583j4n0Eg3jIxvWmZtz/5uz9UYkeIStSlMxuUja+ec5j3iBD8nv1rwaOAYMW09tBdkSeaQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10" } @@ -4619,7 +4609,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -5007,7 +4996,6 @@ "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", "hasInstallScript": true, "license": "MIT", - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -8014,7 +8002,6 @@ "integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "playwright-core": "1.63.0" }, @@ -8073,7 +8060,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.18", "picocolors": "^1.1.1", @@ -8127,7 +8113,6 @@ "integrity": "sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -8177,7 +8162,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz", "integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -8187,7 +8171,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz", "integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.28.0" }, @@ -9207,7 +9190,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9645,7 +9627,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.1.tgz", "integrity": "sha512-/bvH9E9tmCXRGp2uXY3WbOldqpTwFkbha/8ANaEQ6VkxhH60KyqLwgZq6lG2y+4uT55x9+9eUHMpQ7uGnOCKjA==", "license": "MIT", - "peer": true, "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", @@ -10088,7 +10069,6 @@ "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", "devOptional": true, "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, diff --git a/astro-site/package.json b/astro-site/package.json index bbd0825..662bd0c 100644 --- a/astro-site/package.json +++ b/astro-site/package.json @@ -26,7 +26,7 @@ "refresh:fidelity": "python3 scripts/refresh-fidelity.py" }, "dependencies": { - "@ambiqai/helia-ui": "https://codeload.github.com/AmbiqAI/helia-ui/tar.gz/f523f6008aca7e1f9b4c3a17198f3f48da83cd7a", + "@ambiqai/helia-ui": "https://codeload.github.com/AmbiqAI/helia-ui/tar.gz/refs/tags/v0.1.0-alpha.24", "@astrojs/markdown-remark": "^7.3.1", "@astrojs/react": "7.0.0", "@astrojs/starlight": "^0.41.5", diff --git a/astro-site/scripts/audit-layout.mjs b/astro-site/scripts/audit-layout.mjs index c063c2c..cdb85a9 100644 --- a/astro-site/scripts/audit-layout.mjs +++ b/astro-site/scripts/audit-layout.mjs @@ -27,18 +27,43 @@ try { const issues = await page.evaluate(() => { const main = document.querySelector('main'); const visible = element => element.getBoundingClientRect().height > 0; + const probe = document.createElement('span'); + probe.style.color = 'var(--helia-ink-primary)'; + document.body.append(probe); + const buttonColor = getComputedStyle(probe).color; + probe.remove(); return { overflow: document.documentElement.scrollWidth > innerWidth + 1, images: [...main.querySelectorAll('img')].filter(image => visible(image) && (!image.complete || !image.naturalWidth)).map(image => image.getAttribute('src')), headings: main.querySelectorAll('h1').length, emptyLinks: [...main.querySelectorAll('a')].filter(link => visible(link) && !link.textContent.trim() && !link.getAttribute('aria-label') && !link.querySelector('img[alt],svg')).map(link => link.getAttribute('href')), codeCards: [...main.querySelectorAll('.helia-card')].filter(card => card.querySelector('pre')).length, + unreadableButtons: [...main.querySelectorAll('.task-links a')].filter(link => getComputedStyle(link).color !== buttonColor).length, }; }); checked++; - if (resourceFailures.length || response.status() !== 200 || issues.overflow || issues.images.length || issues.headings !== 1 || issues.emptyLinks.length || issues.codeCards) { + if (resourceFailures.length || response.status() !== 200 || issues.overflow || issues.images.length || issues.headings !== 1 || issues.emptyLinks.length || issues.codeCards || issues.unreadableButtons) { failures.push({ width, theme, route, status: response.status(), resourceFailures, ...issues }); } + if (route === '/compressionkit/') { + const prefix = page.locator('.helia-site-header__prefix'); + if (await prefix.textContent() !== 'compression') failures.push({ width, theme, route, titlePrefix: await prefix.textContent() }); + if (!await page.locator('.hero-meta img').isVisible()) failures.push({ width, theme, route, missingHeroLogo: true }); + const card = page.locator('.kit-home-nav .helia-card').first(); + const destination = await card.locator('a').first().getAttribute('href'); + const description = card.locator('.helia-card-content p').first(); + await description.scrollIntoViewIfNeeded(); + const body = await description.boundingBox(); + await page.mouse.click(body.x + body.width / 2, body.y + body.height / 2); + await page.waitForURL(url => url.pathname === destination); + if (new URL(page.url()).pathname !== destination) failures.push({ width, theme, route, cardDestination: page.url(), expected: destination }); + } + } + const missingRoute = '/compressionkit/this-route-does-not-exist/'; + const missingResponse = await page.goto(base + missingRoute); + const missingTitle = await page.locator('main h1').textContent(); + if (missingResponse.status() !== 404 || missingTitle.trim() !== '404') { + failures.push({ width, theme, route: missingRoute, status: missingResponse.status(), title: missingTitle }); } await page.close(); } diff --git a/astro-site/src/components/HomeHero.astro b/astro-site/src/components/HomeHero.astro index 232ba42..fa99b55 100644 --- a/astro-site/src/components/HomeHero.astro +++ b/astro-site/src/components/HomeHero.astro @@ -1,11 +1,13 @@ --- import { readFileSync } from 'node:fs'; import DefaultHero from '@astrojs/starlight/components/Hero.astro'; +import Button from '@ambiqai/helia-ui/astro/Button'; const { data } = Astro.locals.starlightRoute.entry; const source = readFileSync('../pyproject.toml', 'utf8'); const version = source.match(/^version\s*=\s*"([^"]+)"/m)?.[1]; if (!version) throw new Error('Missing compressionKIT version in pyproject.toml'); const base = import.meta.env.BASE_URL; +const isHome = Astro.url.pathname.replace(/\/+$/, '') === base.replace(/\/+$/, ''); const tasks = [['PPG codecs', 'signals/ppg'], ['ECG codecs', 'signals/ecg'], ['Build your own codec', 'adding-a-codec-family']]; const capabilities = [ ['01', 'Prepare signals', 'ECG and PPG preprocessing'], @@ -14,9 +16,9 @@ const capabilities = [ ['04', 'Prepare for the edge', 'Models, manifests and reference vectors'], ]; --- -{data.hero?.tagline ? <> +{isHome && data.hero?.tagline ? <>
-
compressionKITv{version}
+
compressionKITv{version}

Keep the signal.
Carry less data.

@@ -33,36 +35,36 @@ const capabilities = [
: } diff --git a/astro-site/src/content/docs/index.mdx b/astro-site/src/content/docs/index.mdx index 2ddcc9c..43ba81b 100644 --- a/astro-site/src/content/docs/index.mdx +++ b/astro-site/src/content/docs/index.mdx @@ -12,49 +12,46 @@ import CardContent from '@ambiqai/helia-ui/astro/CardContent'; import CardGrid from '@ambiqai/helia-ui/astro/CardGrid'; import Icon from '@ambiqai/helia-ui/astro/Icon'; -## Less data to store. More signal to work with. + -compressionKIT is a Python-based AI Development Kit for compressing ECG and PPG waveforms. It brings together codec models, signal preprocessing, evaluation tools, and export utilities so you can compare compression methods using the same workflow. +## What is compressionKIT? -A **codec** encodes a frame of samples into a smaller representation, then decodes it back into a waveform. Compression is lossy: a smaller payload can also change the reconstructed signal. Use the included scorecards to measure that tradeoff before choosing a configuration. +compressionKIT is a Python development kit for compressing ECG and PPG waveforms. It brings codec models, signal preprocessing, evaluation and export into one workflow, so you can compare approaches before preparing an application for the edge. -## Why it matters +A codec encodes a frame of samples into a smaller representation and decodes it back into a waveform. Compression can change the reconstructed signal. The [evidence pages](/compressionkit/customer-evidence/) help you inspect that tradeoff alongside payload size, rather than relying on compression ratio alone. - -

Explore smaller payloads for local storage, transfer, and later analysis. Measure reconstructed signal quality alongside the reduction in data size.

Explore use cases →

-

Inspect waveform error, heart-rate error, and behavior under noise across PPG and ECG configurations.

Review the evidence →

-

Export models, codebooks, manifests, and reference vectors. Use these to validate the codec and plan its integration into your application.

Explore deployment →

-

Use the provided experiments or compose your own workflow from datasets, models, evaluation functions, and exporters.

Build your own workflow →

-
- -## Start with a codec. Expand when you need to. + -1. **Try a round trip.** [Install from source](/compressionkit/getting-started/) and encode/decode a synthetic frame. You do not need a training dataset. -2. **Evaluate your signal.** Use an [example notebook](/compressionkit/examples/) to inspect reconstructions and errors on your recordings. -3. **Compare configurations.** Browse [PPG and ECG models](/compressionkit/models/) and choose candidates against your quality and payload requirements. -4. **Prepare integration.** [Validate the deploy package](/compressionkit/deployment/#recommended-validation), then measure memory, latency, and quality in your target application. +## What you can do - - - + +

Explore smaller payloads for storage and transfer, while checking the quality of the reconstructed signal.

Explore use cases →

+

Inspect waveform and physiological measures across PPG and ECG configurations.

Review the evidence →

+

Export models, codebooks, manifests and reference vectors for integration work.

Explore deployment →

+

Use a provided experiment or compose your own workflow from the available blocks.

Build your own workflow →

+
- + - +## Installation - +Use Python 3.12 and a source checkout to get started: - +```bash +git clone https://github.com/AmbiqAI/compressionkit.git +cd compressionkit +uv sync --python 3.12 --extra hf +``` - +The `hf` extra supports loading remote Hugging Face bundles. The [Getting Started guide](/compressionkit/getting-started/) runs a first encode/decode example; no training dataset is needed for that path. - + -## Explore the toolkit +## Explore the documentation - -

Install compressionKIT and run your first encode/decode example.

Start here →

-

Load a remote bundle or an existing local deploy directory.

Load a codec →

-

Review signal-specific results, configurations, and reconstruction plots.

Browse models →

-

Find a registered configuration, prepare its dataset, and run the workflow.

Explore experiments →

+ +

Install compressionKIT and run your first encode/decode example.

Start here →

+

Load a remote bundle or an existing local deploy directory.

Load a codec →

+

Review signal-specific results, configurations and reconstruction plots.

Browse models →

+

Find a registered configuration, prepare its dataset and run the workflow.

Explore experiments →

diff --git a/astro-site/src/styles/site.css b/astro-site/src/styles/site.css index d4f0d63..8afe2b7 100644 --- a/astro-site/src/styles/site.css +++ b/astro-site/src/styles/site.css @@ -1,4 +1,4 @@ -:root { --ck-accent: #26a69a; } :root[data-theme="light"] { --ck-accent: #0d7377; } +:root { --ck-accent: #9cf050; } :root[data-theme="light"] { --ck-accent: #276d2b; } .sl-markdown-content img { max-width: 100%; height: auto; } :root[data-theme="dark"] img[src$="#only-light"], :root[data-theme="light"] img[src$="#only-dark"] { display: none; } @@ -15,7 +15,10 @@ .sl-markdown-content summary:focus-visible { outline: 2px solid var(--ck-accent); outline-offset: 4px; } .sl-markdown-content .helia-card-grid { margin-block: 1.5rem 2rem; } .sl-markdown-content .helia-card-header__title { font-size: 1.125rem; line-height: 1.4; } +.sl-markdown-content .helia-card-header .helia-icon__glyph { color: var(--ck-accent); } .sl-markdown-content .helia-card-content { font-size: .95rem; line-height: 1.7; } +.sl-markdown-content :is(.kit-home-features, .kit-home-nav) .helia-card-content { display: flex; flex: 1; flex-direction: column; } +.sl-markdown-content .ck-card-cue { color: var(--ck-accent); font-weight: 600; margin-top: auto; } @media (max-width: 40rem) { .sl-markdown-content > h2 { font-size: 1.65rem; } .sl-markdown-content :is(th, td) { padding: .6rem; }