LumaSync-Site

releasev1.1.25

Marketing site, docs, and blog for LumaSync — the tray-first open-source ambilight + Philips Hue desktop app.

0stars
0forks
0watchers
8open issues
owner: voyvodkastatus: CORElanguage: MDXbranch: mainlicense: Otherupdated: 6/15/2026, 12:39:01 PMlast push: 6/20/2026, 10:04:46 AM
adalightambilightastrobias-lightingled-stripmarketing-siteopensourcephilips-huetauriws2812b

README Snapshot

LumaSync-Site

Marketing site, docs, and blog for LumaSync — the tray-first open-source ambilight + Philips Hue desktop app.

Stack

  • Astro 6 + MDX content collections (docs, compare, legal, blog)
  • Pagefind for offline in-browser search; Umami for cookie-free analytics
  • Cloudflare Pages (direct-upload via wrangler) + Cloudflare DNS
  • IBM Plex Sans / Mono (self-hosted WOFF2, preloaded)
  • No secrets bundled; the site never talks to the desktop app

Develop

Requires Node 22.12+ and pnpm (pinned via packageManager in package.json).

pnpm install
pnpm dev        # http://localhost:4321
pnpm lint       # prettier --check
pnpm check      # astro check (type-check + content schema)
pnpm build      # astro build + pagefind index

Deploy

Every push to main triggers .github/workflows/deploy.yml, which lint- and type-checks, builds, and ships dist/ to Cloudflare Pages.

Required repo secrets for CI: CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID.

License

  • Code (Astro components, layouts, CI, styling) — MIT
  • Content (MDX under src/content/, docs, comparisons, blog) — CC BY 4.0

See /license for the public-facing summary and LICENSE for the full text.

Contributing

Issues and PRs welcome — see CONTRIBUTING.md for scope, local preview, and commit conventions. For app-level bugs (firmware, USB pipeline, Hue streaming), file against the LumaSync app repo instead.

Security

Report vulnerabilities through GitHub's Private Vulnerability Reporting — see SECURITY.md or /.well-known/security.txt.

Changelog

Changelog — lumasync-site

This is the changelog for the marketing/docs site at lumasync.app. The LumaSync app's own release notes live in the app repo and surface on /changelog — site versions track independently from app versions.

The site follows Semantic Versioning at its own cadence; bumping the LumaSync app submodule does not require bumping the site version.

[1.1.25] — 2026-06-15

Security

  • esbuild advisory cleared (GHSA-gv7w-rqvm-qjhr, GHSA-g7r4-m6w7-qqqr): a pnpm overrides entry now pins esbuild to >=0.28.1, resolving the high- and low-severity advisories that reached the build transitively through @tailwindcss/vite > vite > esbuild. The dependency-audit CI gate (pnpm audit --prod --audit-level=high) is green again.
  • yaml advisory cleared (GHSA-48c2-rrv3-qjmp): a pnpm overrides entry forces yaml to >=2.8.3, replacing the vulnerable 2.7.1 pulled in transitively via @astrojs/check's language-server chain. With this, pnpm audit reports no known vulnerabilities at any severity, production or development.
  • External-link hardening completed site-wide: rel="noopener noreferrer" now covers the remaining outbound links on the home, download, and community pages (Hue developer portal, and the GitHub repo / releases / Code of Conduct / Contributing links), finishing the rollout begun in 1.1.24. The links open in the same tab (no target="_blank" site-wide), so this is defense-in-depth plus Referer-header suppression.

Accessibility

  • Disabled community forum links show their tooltip on hover: .forums a.disabled swaps pointer-events: none for cursor: default, so the native title ("Pending community growth") surfaces on hover for the inert Discord card. The links already render no href and guard :hover/:active styling with :not(.disabled), so there is no interactivity regression.

Dependencies

  • astro 6.4.4 → 6.4.7: routine upstream patch (manifest + lockfile only), bringing the addAttribute invalid-attribute-name hardening and prerendered-error-page origin validation from the 6.4.5–6.4.7 patch line. A full lockfile refresh also picked up the latest in-range patches across the tree.

[1.1.24] — 2026-06-09

Security

  • CSP img-src no longer allows arbitrary HTTPS origins: the Content-Security-Policy permitted images from any https: origin, but a repo-wide scan confirmed the site loads no external images at all — every image is served first-party or inlined as a data: URI. The directive is now img-src 'self' data:, so an injected or compromised markup path can no longer exfiltrate data via attacker-controlled image loads.
  • External outbound links carry rel="noopener noreferrer": the GitHub links in CompareCTA.astro, the Footer's outbound column links, and the repo/license links on /changelog/ and /license/ now set both hints. The links open in the same tab (no target="_blank" exists site-wide), so this is defense-in-depth rather than an active tabnabbing fix, plus it stops leaking the Referer header to the destination.

[1.1.23] — 2026-06-08

Build

  • Declared Node engine floor aligned to the real requirement: package.json engines.node tightened >=22.0.0>=22.12.0, and the README "Develop" note now reads "Node 22.12+", matching the actual floor imposed by Astro 6 and @astrojs/mdx 6 (both declare node >=22.12.0). No runtime or build-output change — .nvmrc already resolves a compliant Node 22.x, so CI was unaffected; this just makes the declared range honest.

[1.1.22] — 2026-06-08

Accessibility

  • Keyboard focus rings on call-to-action buttons: the primary and secondary CTAs in CompareCTA.astro and on the homepage now render a visible :focus-visible outline (2px --focus-ring, 2px offset), so keyboard and switch-device users can see which button holds focus. Mouse users are unaffected — :focus-visible only triggers for keyboard-style focus.
  • Compare-listing grid cards respond to keyboard focus and press: cards in the /compare/ index grid gain the same :focus-visible outline plus a subtle scale(0.96) active-press transform, gated behind prefers-reduced-motion, matching the interaction feedback already present on the homepage compare cards.

Dependencies

  • Minor/patch group bump (4 updates): astro 6.4.2 → 6.4.4, marked 18.0.4 → 18.0.5, dompurify 3.4.7 → 3.4.8, and isomorphic-dompurify 3.15.0 → 3.16.0 — routine upstream patches, lockfile + manifest only, no source change.
  • @astrojs/mdx 5 → 6: major bump of the MDX integration (5.0.6 → 6.0.2). Astro 6.4 satisfies the new astro: ^6.4.0 peer range; the build, type-check, and Lighthouse-CI gates all pass with MDX-rendered pages unchanged.

[1.1.21] — 2026-06-01

Accessibility

  • Disabled Discord card explains itself on hover: the "Coming soon" Discord card on /community/ — inert until the active-user count crosses its threshold — now carries a native title tooltip ("Pending community growth"), mirroring the disabled download-card treatment from v1.1.19 so hovering users understand why the card is non-interactive. The card was already kept out of the keyboard/click path via aria-disabled and an undefined href.

Dependencies

  • Minor/patch group bump (4 updates): astro 6.3.7 → 6.4.2, @astrojs/sitemap 3.7.2 → 3.7.3, dompurify 3.4.5 → 3.4.7, and isomorphic-dompurify 3.14.0 → 3.15.0. The Astro bump is a minor release; the rest are routine upstream patches — lockfile + manifest only, no source change.

[1.1.20] — 2026-05-29

Security

  • Response-header hardening: removed the deprecated block-all-mixed-content directive from the Content-Security-Policy (the upgrade-insecure-requests directive, already present, supersedes it), and added a Permissions-Policy that denies camera, microphone, geolocation, payment, USB, the motion sensors, and the Topics API. The static site calls no powerful browser APIs, so this is attack-surface reduction with no functional change.

Structured Data

  • Organization logo dimensions corrected: the logo ImageObject declared 512x128, but brand/logotype-light.svg has an intrinsic 320x80 viewBox. Aligned the declared dimensions (same 4:1 ratio, both above Google's 112px minimum) so strict validators don't flag a mismatch against the asset.

[1.1.19] — 2026-05-29

Bug Fixes

  • Dead links in llms.txt and slashless structured-data URLs: the llms.txt index linked llms-full.txt/ and .well-known/security.txt/ with trailing slashes, which 404 because those are static assets rather than HTML routes — an agent following the index to the full-text corpus or the security contact hit a dead end. Both now point at the slashless forms, and the Telemetry entry resolves to /docs/reference/telemetry/ instead of the docs index. Separately, the docs leaf ([...slug]) and docs group ([group]/index) pages emitted their breadcrumb-leaf, TechArticle/HowTo, and CollectionPage schema URLs without a trailing slash, so the structured-data entity URLs 308-redirected instead of resolving directly — they now carry the slash to match the trailingSlash:'always' canonical, as do the llms-full.txt Source: pointers.
  • /docs/ and /compare/ hub OG images 404'd: both hub pages derive an og:image URL (/og/docs.png, /og/compare.png), but the OG generation route had no matching key, so social and crawler unfurls of those two pages rendered without a card. Added both keys.
  • SoftwareApplication declared one @id with two download URLs: the homepage and /download/ both emit the app's SoftwareApplication node under the same @id but with divergent downloadUrl values, asking consumers to merge conflicting nodes. Both now resolve to the stable /download/ canonical.
  • humans.txt named the wrong host: the credits file listed a stale deploy target; corrected to Cloudflare Pages.

Content

  • Hue Sync comparison repositioned: /compare/hue-sync/ claimed Signify had discontinued the Hue Sync desktop app for PC/Mac, but official Philips release notes show that app is still actively maintained — only the separate Hue Sync mobile app was retired. The page now positions LumaSync as a free, open-source alternative to the desktop app (keeping the migration guidance), and the unresolved editorial placeholder was removed.

Accessibility

  • Muted text now meets WCAG AA contrast: --text-muted was #6b7280, below the 4.5:1 normal-text threshold on the dark surfaces (blockquotes, footer tagline, download meta). Lightened to #8b919c while keeping the muted feel.
  • Disabled download cards explain themselves on hover: unavailable-platform cards now carry a native title tooltip ("No release available for this platform yet"), so hovering users understand why the card is inert — the cards were already out of the keyboard/click path from earlier releases.

Performance

  • Long-lived caching for /media/: hero and screenshot images were served with the 4-hour must-revalidate default; added a 30-day Cache-Control block so the LCP hero stops paying a conditional round-trip on repeat visits.

Discoverability

  • Markdown entry-point Link relation: the RFC 8288 Link: header advertising llms.txt / llms-full.txt now uses rel="alternate"; type="text/markdown" — the relation header-only agents key off for markdown discovery — instead of describedby / text/plain.

Build

  • CI gates on production CVEs: added a pnpm audit --prod --audit-level=high step so a published vulnerability introduced into the shipped dependency tree fails the build. The existing license audit checks compliance only, not vulnerabilities.

[1.1.18] — 2026-05-29

Security

  • Sanitized GitHub API fetch errors on /download/: src/pages/download.astro previously surfaced the raw caught error's .message directly into the page's fetchError state, which could leak upstream API structure, internal request details, or network specifics into the rendered UI. The raw error is now logged server-side via console.error for diagnostics, while the user-facing state is pinned to a generic 'upstream API unavailable' string. No behavioral change for the success path; failed release fetches now degrade with an opaque message instead of an implementation-revealing one.

Accessibility

  • Search-hint <kbd> glyphs hidden from the accessible name in Search.astro: the modal's "Type to search. ↑↓ to navigate, ↵ to open." hint rendered raw arrow and enter symbols that screen readers announced as literal characters. The visual <kbd> clusters now carry aria-hidden="true" and are paired with sr-only text equivalents ("Up and down arrows", "Enter") so assistive technology reads meaningful labels while sighted users keep the compact symbol hint. The same treatment is applied to both the static markup and the renderEmpty() JS template that repaints the hint on an empty query, plus the modal Close button's <kbd>Esc</kbd> is now aria-hidden (the aria-keyshortcuts="Escape" already conveys the shortcut semantically).

Interaction

  • Press-state feedback on search results: added a :active transform: scale(0.98) to .search-result, gated behind @media (prefers-reduced-motion: no-preference) so it respects motion preferences. Gives keyboard and pointer users tactile confirmation when activating a result without affecting reduced-motion sessions.

[1.1.17] — 2026-05-27

Security

  • CSP hardening — https: wildcard removed from script-src and connect-src: public/_headers previously shipped script-src 'self' 'unsafe-inline' https: and connect-src 'self' https:, which let any HTTPS origin execute scripts and accept connections — neutralizi

Releases

  • v1.1.25

    Security

    • esbuild advisory cleared (GHSA-gv7w-rqvm-qjhr, GHSA-g7r4-m6w7-qqqr): pnpm override pins esbuild to >=0.28.1; the pnpm audit --prod --audit-level=high CI gate is green again.
    • yaml advisory cleared (GHSA-48c2-rrv3-qjmp): pnpm override forces yaml to >=2.8.3 (was 2.7.1 via @astrojs/check). pnpm audit now reports no known vulnerabilities at any severity, prod or dev.
    • External-link hardening completed site-wide: rel="noopener noreferrer" extended to the remaining outbound links on the home, download, and community pages, finishing the rollout begun in 1.1.24.

    Accessibility

    • Disabled community forum links now show their native title tooltip on hover (.forums a.disabled: pointer-events: nonecursor: default), with no interactivity regression.

    Dependencies

    • astro 6.4.4 → 6.4.7 (manifest + lockfile), plus a full lockfile refresh for the latest in-range patches across the tree.
    Open on GitHub
  • v1.1.24

    Security

    • CSP img-src tightened to 'self' data: — removed the https: scheme wildcard; the site loads no external images (verified by repo-wide scan), so arbitrary-origin image loads are no longer permitted.
    • rel="noopener noreferrer" on external outbound links — GitHub links in CompareCTA, Footer outbound links, and repo/license links on /changelog/ and /license/ now carry both hints; defense-in-depth (no target="_blank" exists site-wide) plus Referer-leak prevention.

    Full details in CHANGELOG.md.

    Open on GitHub
  • v1.1.23

    Build

    • Declared Node engine floor aligned to the real requirement: package.json engines.node tightened >=22.0.0>=22.12.0, and the README "Develop" note now reads "Node 22.12+", matching the floor imposed by Astro 6 and @astrojs/mdx 6 (both declare node >=22.12.0).
    • No runtime or build-output change — .nvmrc already resolves a compliant Node 22.x, so CI was unaffected; this only makes the declared range honest. No redeploy needed.
    Open on GitHub
  • v1.1.22

    Accessibility

    • Keyboard focus rings (:focus-visible, 2px --focus-ring) on the primary/secondary CTAs in CompareCTA.astro and on the homepage.
    • Compare-listing (/compare/) grid cards gain the same focus ring plus a prefers-reduced-motion-gated scale(0.96) active-press transform.

    Dependencies

    • Minor/patch group: astro 6.4.2 → 6.4.4, marked 18.0.4 → 18.0.5, dompurify 3.4.7 → 3.4.8, isomorphic-dompurify 3.15.0 → 3.16.0.
    • @astrojs/mdx 5.0.6 → 6.0.2 (major) — Astro 6.4 satisfies the new astro: ^6.4.0 peer range; build, type-check, and Lighthouse-CI gates green.
    Open on GitHub
  • v1.1.21

    Accessibility

    • Disabled Discord card explains itself on hover — the "Coming soon" Discord card on /community/ now carries a native title tooltip ("Pending community growth"), mirroring the disabled download-card treatment so hovering users see why the card is inert. Already kept out of the keyboard/click path via aria-disabled and an undefined href.

    Dependencies

    • Minor/patch group bump (4 updates)astro 6.3.7 → 6.4.2, @astrojs/sitemap 3.7.2 → 3.7.3, dompurify 3.4.5 → 3.4.7, isomorphic-dompurify 3.14.0 → 3.15.0. Astro is a minor release; the rest are routine upstream patches — lockfile + manifest only, no source change.
    Open on GitHub
  • v1.1.20

    Security

    • Response-header hardening — removed the deprecated block-all-mixed-content directive from the CSP (upgrade-insecure-requests supersedes it) and added a Permissions-Policy denying camera, microphone, geolocation, payment, USB, the motion sensors, and the Topics API. No functional change — the static site calls no powerful browser APIs.

    Structured Data

    • Organization logo dimensions corrected — the logo ImageObject now declares 320x80 to match the SVG's intrinsic viewBox (was 512x128), so strict validators don't flag a dimension mismatch.
    Open on GitHub
  • v1.1.19

    Bug Fixes

    • Dead links + slashless structured-data URLsllms.txt linked llms-full.txt/ and .well-known/security.txt/ (both 404 with a trailing slash) and the docs leaf/group schema URLs (breadcrumb, TechArticle/HowTo, CollectionPage) 308-redirected; all now resolve directly and the Telemetry link points at /docs/reference/telemetry/.
    • /docs/ and /compare/ hub OG images 404'd — added the missing OG route keys so social/crawler unfurls render a card.
    • SoftwareApplication shared one @id with two downloadUrls — homepage and /download/ now both resolve to the stable /download/ canonical.
    • humans.txt — corrected the deploy host to Cloudflare Pages.

    Content

    • Hue Sync comparison repositioned — corrected the inaccurate "discontinued" claim (the Hue Sync desktop app is still maintained; only the mobile app was retired) and reframed LumaSync as a free, open-source alternative, keeping the migration guidance.

    Accessibility

    • Muted text now meets WCAG AA contrast--text-muted lightened from #6b7280 to #8b919c.
    • Disabled download cards carry a native title tooltip explaining why they're inert.

    Performance

    • 30-day caching for /media/ — the LCP hero and screenshots no longer pay the 4h must-revalidate round-trip.

    Discoverability

    • Link header advertising llms.txt / llms-full.txt now uses rel="alternate"; type="text/markdown".

    Build

    • CI gates on production CVEs via pnpm audit --prod --audit-level=high.
    Open on GitHub
  • v1.1.18

    Security

    • Sanitized GitHub API fetch errors on /download/ — raw error messages are no longer surfaced to the UI; failures are logged server-side and degrade with a generic upstream API unavailable string, avoiding leakage of upstream API structure or network details.

    Accessibility

    • Search-hint <kbd> glyphs hidden from the accessible name — the modal hint's arrow/enter symbols now carry aria-hidden="true" paired with sr-only text equivalents ("Up and down arrows", "Enter"), applied to both the static markup and the empty-query repaint; the Close button's Esc kbd is also aria-hidden (covered by aria-keyshortcuts).

    Interaction

    • Press-state feedback on search results — added a :active scale(0.98) to search results, gated behind prefers-reduced-motion: no-preference.
    Open on GitHub
  • v1.1.17

    Security

    • CSP hardening — https: wildcard removed from script-src and connect-src in public/_headers. Both directives are now pinned to 'self'. The site serves no third-party scripts at runtime, so this is a no-op for legitimate traffic and narrows the XSS / data-exfiltration attack surface.

    Accessibility

    • aria-keyshortcuts + dialog-popup semantics on search triggers: header search button and 404-page .search-cta now expose aria-keyshortcuts="Control+K Meta+K", aria-haspopup="dialog", and aria-controls="search-dialog", with their visual <kbd>⌘</kbd><kbd>K</kbd> wrappers hidden from AT via aria-hidden="true". The search modal's Close button also gains aria-keyshortcuts="Escape". 404 CTA additionally gets an explicit aria-label="Search".
    • Focus-visible outline on landing-page compare cards — closes the last landing-page interactive surface that lacked a keyboard outline, matching the focus pattern used across the rest of the site.

    Dependencies

    • Minor/patch group bump (4 updates): astro 6.3.3 → 6.3.7, marked 18.0.3 → 18.0.4, dompurify 3.4.4 → 3.4.5, isomorphic-dompurify 3.13.0 → 3.14.0.
    Open on GitHub
  • v1.1.16

    Bug Fixes

    • Stale search queries no longer overwrite fresher results in Search.astro: a monotonic queryId is now captured per input event and re-checked after every await (loadPagefind, pf.search, data()), so a superseded query bails before touching the DOM. Clearing the input also invalidates any in-flight query.

    Accessibility

    • Disabled download cards on /download/ now drop their href entirely, removing unavailable-platform cards from the keyboard tab order and disabling Enter-key activation. Mirrors the community-forum-card fix from v1.1.15.

    Dependencies

    • Minor/patch group: astro 6.3.1 → 6.3.3, @astrojs/mdx 5.0.4 → 5.0.6, dompurify 3.4.2 → 3.4.4, isomorphic-dompurify 3.12.0 → 3.13.0.
    • pnpm/action-setup 6.0.6 → 6.0.8 (CI + deploy).
    • cloudflare/wrangler-action 3.15.0 → 4.0.0 (deploy) — non-breaking, wranglerVersion: '4' already pinned; stale pin comment corrected to # v4.0.0.
    Open on GitHub
  • v1.1.15

    Accessibility

    • Disabled forum cards on /community/ now drop their href entirely: the "Coming soon" anchor previously rendered with href="#" + aria-disabled="true" + pointer-events: none, but the dummy # href left the element in the keyboard tab sequence and pressing Enter would scroll the page to the top. The href is now conditionally omitted, so the browser treats the <a> as a non-interactive placeholder and removes it from the focus order. aria-disabled is still set for assistive tech.

    UX

    • Focus-visible outline + tactile click feedback on /community/ forum cards: the same anchors render an explicit :focus-visible outline using var(--focus-ring) with a 2px offset, and the :active state scales to 0.96 wrapped in prefers-reduced-motion: no-preference. Disabled cards are excluded via :not(.disabled). Closes the last navigation surface lacking tactile / keyboard parity with the rest of the site.

    Performance

    • Manual indexed loops in pickAsset on /download/: replaced the inner .find() inside the matchers loop with a manual indexed for loop, eliminating per-asset closure allocation when resolving GitHub release assets at build time. Build-time-only — runtime user behavior is unchanged.
    Open on GitHub
  • v1.1.14

    Dependencies

    • devalue bumped 5.8.0 → 5.8.1: transitive dep via Astro, used to serialize server-rendered state into the client hydration bundle. Upstream patch forces sparse arrays to allocate sparsely (sveltejs/devalue@206ca67), a defensive fix for a memory-blowup vector when hydration payloads contain sparse-array structures. Lockfile-only — no source change in this repo.
    Open on GitHub
  • v1.1.13

    Security

    • Single-quote escape in Pagefind result rendering (Search.astro): escapeHtml was neutralizing &, <, >, and " before injecting Pagefind result excerpts into the DOM but left ' untouched, leaving an attribute-context breakout vector if a result excerpt was ever rendered inside a single-quoted attribute. Added '&#39; to the chain — mirrors the v1.1.11 hardening on Schema.astro.

    Performance

    • Cached Pagefind init Promise + O(1) keyboard navigation in Search.astro: loadPagefind now memoizes the in-flight Promise rather than only the resolved module, so concurrent callers (keyboard shortcut + rapid keystrokes) share one init cycle. setActive updates only the previously-active and newly-active result nodes instead of iterating the full NodeList per keypress (O(N) → O(1)).

    UX

    • Tactile click feedback + focus ring on /download/ installer cards: .card elements now scale to 0.96 on :active (wrapped in prefers-reduced-motion: no-preference) and render an explicit :focus-visible outline. Disabled cards are excluded. Extends the v1.1.12 landing-page CTA affordance to the download surface.
    • Focus-visible + active states on DocsSidebar.astro links: docs sidebar links now show a 2px inset focus-visible outline and scale to 0.96 on :active, honouring reduced-motion. Closes the last navigation surface that lacked keyboard / tactile parity.

    CI

    • pnpm/action-setup bumped 6.0.5 → 6.0.6 (upstream fix: bin_dest output now points to the self-updated pnpm rather than the bootstrap binary).
    Open on GitHub
  • v1.1.12

    Security

    • Content-Security-Policy header on all responses: public/_headers now sets a baseline CSP under /* so every HTML response carries it. Policy is restrictive-by-default (default-src 'self', frame-ancestors 'none', object-src 'none', base-uri 'self', form-action 'self', block-all-mixed-content, upgrade-insecure-requests) with the minimum allowances Astro and the analytics bundle need: 'unsafe-inline' on script-src / style-src (Astro emits inline hydration shims and scoped style blocks), https: on script-src / connect-src / img-src for the third-party analytics endpoint, and data: on img-src / font-src. Adds a defense-in-depth layer behind the existing input-sanitization fixes from v1.1.9 / v1.1.11 — if any future XSS vector slipped through, the CSP would block eval, mixed content, framing, and external object loads.

    Performance

    • Cached focus-trap NodeList in Header.astro: the mobile-nav focus trap was calling panel.querySelectorAll(focusableSelector) inside the keydown handler on every Tab press, repeating the same DOM query and risking layout thrashing during rapid keyboard navigation. The query now runs once when the nav opens and is stored in a closure-scoped cachedFocusable; the keydown branch reads the cached NodeList instead. Same focus-trap semantics, near-zero per-keystroke DOM cost.

    UX

    • Tactile click feedback on landing-page CTAs and comparison cards: src/pages/index.astro and src/components/CompareCTA.astro now apply transform: scale(0.96) on :active for .cta-primary, .cta-secondary, and .compare-card, with transform added to each element's transition list so the scale eases in / out at var(--duration-fast) rather than snapping. The :active rule is wrapped in @media (prefers-reduced-motion: no-preference) to honour the reduced-motion contract. Extends the same tactile affordance shipped on the 404 page in v1.1.11 to the primary conversion surfaces on the landing page.

    Full changelog: https://github.com/voyvodka/LumaSync-Site/blob/v1.1.12/CHANGELOG.md

    Open on GitHub
  • v1.1.11

    Security

    • Single-quote escape in JSON-LD serialization: src/components/Schema.astro was injecting JSON.stringify output into <script type="application/ld+json"> via set:html with <, >, and & escaped to their \u00xx forms, but single quotes left through unchanged. While JSON does not require escaping ', leaving it raw inside an HTML script-context payload is a latent script-breakout vector if the script-tag is ever wrapped in a single-quoted attribute or the surrounding template shifts. Added .replace(/'/g, '\\u0027') to the existing escape chain so all four script-context-sensitive characters are uniformly neutralized regardless of where the schema string ends up.

    UX

    • Tactile click feedback on 404 page CTAs: the Search, Home, and recovery-link controls on src/pages/404.astro now scale to 0.96 on :active, wrapped in @media (prefers-reduced-motion: no-preference) so reduced-motion users are unaffected. Matches the same affordance applied to header / search / nav controls in v1.1.9, restoring perceived responsiveness on the one user-facing page that had been missed.

    Full changelog: https://github.com/voyvodka/LumaSync-Site/blob/v1.1.11/CHANGELOG.md

    Open on GitHub
  • v1.1.10

    SEO

    • Internal-link canonicalization across the URL surface. Astro config sets trailingSlash: 'always' so canonical URLs and sitemap entries end with /, but the rest of the site had drifted to slashless internal references — every header / footer nav item, every body link, every breadcrumbSchema / itemList / softwareApp.downloadUrl field, both compareHref / docHref helpers in src/lib/content.ts, the legacy alias targets in astro.config.mjs, every URL in public/llms.txt, and ~100 markdown links across src/content/**/*.mdx. Each slashless link triggered a 308 redirect, and the legacy aliases formed a 2-hop meta-refresh + 308 chain. The April fix repaired the sitemap; this commit completes the consistency pass across the remaining surfaces. Expected impact: clears the redirect-related "Page indexing" entries in Search Console and frees crawl budget previously wasted on internal redirects.
    • Header.astro isActive simplified. With trailing-slash hrefs, the previous pathname === href || pathname.startsWith(\${href}/`)form no longer matches sub-pages. Replaced withpathname.startsWith(href)` — same semantics, fewer special cases.
    Open on GitHub
  • v1.1.9

    Security

    • DOM-based XSS in Pagefind search results: src/components/Search.astro was injecting Pagefind result excerpts into the DOM via innerHTML with ${r.excerpt || ''} unescaped. Indexed content reaching the excerpt could break out and execute arbitrary HTML. Excerpts now flow through a sanitizeExcerpt helper that HTML-escapes the whole string and then selectively restores the <mark> / </mark> tags Pagefind needs for search-term highlighting, preserving the highlight UI without trusting raw excerpt content.

    Accessibility

    • Native tooltips on icon-only buttons: the header search trigger, the mobile nav open/close buttons, and the search modal Esc close button now carry matching title attributes alongside their aria-labels. Visual users hovering an icon now get the same affordance keyboard / screen-reader users already had, removing ambiguity for buttons that have no text label.
    • Tactile click feedback: the same controls gain a subtle transform: scale(0.96) on :active, wrapped in @media (prefers-reduced-motion: no-preference) so users who opt out of motion are unaffected. Adds perceived responsiveness on click without compromising the reduced-motion contract.
    Open on GitHub
  • v1.1.8 — Surface LumaSync v1.5.x

    Site catches up with three upstream releases (v1.5.0 + v1.5.1 + v1.5.2). Submodule pin advanced from the v1.4.0 merge to post-v1.5.2, so version.ts now resolves LATEST_VERSION / LATEST_VERSION_DATE to v1.5.2 — 2026-05-05 without code changes.

    Content

    • Landing Shipped column rewrote from v1.4 highlights to v1.5.2 — WLED bridge, Hue Zones, Linux X11 capture, SK6812 RGBW, OS keychain credentials, per-bulb gamut clipping, beta update channel, macOS lifecycle hardening, visibility-aware polling, frontend log bridge.
    • Next column rewrote from "v1.5 — in flight" to "v1.6 — queued" (Flathub, glib / gtk-rs migration, OpenRGB sink, companion firmware repo).
    • Three-sink narrative — feature grid expanded to 4 cards (USB · WLED · Hue · all three synchronized). Hero copy, ItemList JSON-LD, and softwareAppSchema description rewrote.
    • Linux platform support promoted from "Experimental" to "Supported" across landing, FAQ, hero platform-note, and download page asset hint.

    Docs

    • New docs/usb-leds/wled.mdx — full WLED bridge reference: DDP-over-UDP, mDNS auto-discovery, IP guard, WLED_INVALID_LED_COUNT rejection, network reachability checklist.
    • getting-started/ — three Linux installers documented, Windows MSI v1.5.1+ stable, first-run onboarding banner, WLED pairing step, chip-type selector, expanded six-chipset USB list, corrected WS2812B (aka SK6812) mistake (SK6812 RGBW is a distinct 4-channel chip).
    • usb-leds/ — six chipsets, USB-class endpoint filtering (PORT_UNSUPPORTED), strip-chip selector documented, RGBW wire format, keyboard input on edge counts (v1.5.2), amber Rev 07 + 32 px tap targets, Bluetooth virtual port reject troubleshooting.
    • hue/ — mDNS-as-primary discovery, OS keychain credential storage with idempotent v1.4 → v1.5 migration, Hue Zones (zone-relative coords, AR-locked sizing, schema 1→2 migration), per-bulb gamut clipping, HUE_STREAM_NOT_READY_ACTIVE_STREAMER 403 retired in v1.5.2 via DTLS close_notify + idempotent deactivate token.
    • advanced/ — beta update channel (updateChannel: 'stable' | 'beta'), Linux hot-plug via xcap RandR.
    • ambilight/screen-capture.mdx — Linux X11 via xcap as default, Windows hardware-accelerated downscale scaffold.
    • reference/ — runtime network call table extended (mDNS rows, WLED /json/info + DDP), visibility-aware polling, OS keychain credential storage callout, wled.connected event, one-shot window.closed-to-tray notification, macOS template tray icon, frontend console.* → file-sink log bridge, compact-mode deep-link auto-expand, kick_off_shutdown_and_die lifecycle path with single-instance socket-leak fix and detached stop_hue_stream worker thread, schemaVersion / updateChannel / wled.targets config fields.
    • compare/wled.mdx — reframed: WLED is a sink LumaSync drives natively over DDP. Recommended setup is "WLED + LumaSync together" for ESP-based hardware.

    Discoverability

    • public/llms.txt opening summary mentions WS2812B / SK6812 RGBW USB, ESP32 / ESP8266 over DDP, OS keychain credentials. WLED moved out of "alternatives" into a complementarity note.
    • download.astro Linux note: AppImage · experimentalAppImage · deb · rpm.

    Pre-deploy patches now live

    The four PRs merged into main after v1.1.7 but never tagged are now part of v1.1.8 (deploy.yml is release-driven, not push-driven):

    • fix(security) Sentinel — community.astro wraps triage[i].a in DOMPurify.sanitize() before <dd set:html>. Closes a latent XSS surface.
    • feat(a11y) Palette — Pagefind .search-result links get :global(.search-result:focus-visible) outline; Astro's scoped CSS otherwise ignored the rule.
    • chore(deps) — Astro 6.1.9 → 6.2.1, marked 18.0.2 → 18.0.3, @astrojs/check 0.9.8 → 0.9.9, prettier-plugin-tailwindcss 0.7.3 → 0.8.0.
    • chore(deps) — pnpm/action-setup SHA pin refreshed (v6.0.3 → v6.0.5).
    Open on GitHub
  • v1.1.7

    Security

    • Markdown→HTML XSS hardening: the /changelog/ page reads vendor/lumasync/CHANGELOG.md from the pinned submodule, parses it with marked, and injects the result via Astro's set:html. Because marked preserves inline raw HTML, an upstream payload (<script> / onclick= etc.) would have rendered verbatim into the deployed page. The parsed HTML now passes through DOMPurify.sanitize() (via isomorphic-dompurify for SSR) before being assigned, so unsafe tags and attributes are stripped at build time. Defends against a supply-chain compromise of the vendor changelog content path.
    Open on GitHub
  • v1.1.6

    Fixed

    • /security URL alias: added public/_redirects with single-hop 301 rules for /security and /security/ pointing at the canonical /.well-known/security.txt. Closes the UX gap where bare /security probes (the convention exposed by GitHub, Stripe, Cloudflare) returned 404 even though the RFC 9116 endpoint was always live. Cloudflare Pages evaluates _redirects ahead of the trailing-slash 308 layer, so each rule catches the request directly without the double-hop a meta-refresh redirect would introduce.
    Open on GitHub