LumaSync-Site

releasev1.2.2

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

0stars
0forks
0watchers
2open issues
owner: voyvodkastatus: CORElanguage: MDXbranch: mainlicense: Otherupdated: last push:
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 Bun (pinned via packageManager in package.json). Bun is the package manager only; the build itself runs on Node.

bun install
bun run dev     # http://localhost:4321
bun run lint    # prettier --check
bun run check    # astro check (type-check + content schema)
bun run 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
  • Palmye logo (src/assets/brand/palmye-logo-dark.svg) — Palmye's brand asset, not covered by either license

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.2.2] — 2026-11-03

Changed

  • The note at the top of every page can no longer be dismissed. The × button is gone and the site stores nothing in the browser for it; a note hidden earlier shows again.

[1.2.1] — 2026-11-02

Fixed

  • Social preview images refresh when they change. /og/* images are revalidated instead of cached as immutable for a year, since their URLs do not change when the image does.

[1.2.0] — 2026-11-02

Added

  • A dismissible note at the top of every page points to Palmye, a travel eSIM from LumaSync's maker. It is a plain nofollow link with the logo served from this site; × hides it and the choice stays in the browser's local storage.

Changed

  • The privacy notice describes the note and the local-storage flag behind ×; its effective date is 2 November 2026. The license page and README state that the Palmye logo is not covered by the site's licenses.

Build

  • satori 0.63.2. Social preview images are re-rendered; title letter spacing shifts slightly.

[1.1.50] — 2026-11-02

Security

  • One critical and seven high-severity dependency advisories are cleared. dompurify 3.4.17 (GHSA-cg2g-xh64-v4q7, GHSA-mrv2-3pqr-j5jr) and undici 8.12.3 (GHSA-xjj6-f33q-929c, GHSA-4w7w-5xrc-9h26, GHSA-2m5v-pch6-74hx, GHSA-qrxm-fqhp-jwvm) arrive through in-range updates; new overrides floors for vite and zod close GHSA-587h-7wmj-h5pm and GHSA-mrhx-c7xc-m3w5.

Build

  • Dependencies updated within their ranges. Astro 7.4.5, @astrojs/mdx 8.1.2, Pagefind 1.6.0, marked 18.1.3, satori 0.33.5, @astrojs/check 0.9.12, isomorphic-dompurify 4.6.0 and Prettier 3.9.10.
  • prettier-plugin-astro 1.1.2. Astro files are reformatted to its output; the built pages are unchanged.
  • The deploy workflow uses cloudflare/wrangler-action 4.1.3.

Docs

  • CONTRIBUTING.md asks for feature claims to be checked against the app source, not its changelog.
  • Older changelog entries are shortened to what changed.

[1.1.49] — 2026-10-14

Changed

  • The footer names the person behind LumaSync. It now ends with "Made by Samet Özkan", linking to the author's site with rel="author"; humans.txt names the maintainer too.

SEO

  • The Organization schema's founder is the author, not just a handle. founder now carries the author's name, site, LinkedIn and the same @id the author's own site uses.

Security

  • Three high-severity advisories in transitive dependencies are cleared. overrides floors for sharp, http-cache-semantics and source-map-js close GHSA-wq5f-xc86-pv6w, GHSA-ch52-4w7c-c8xp and GHSA-68fv-2mgg-jv7q.

Build

  • Bun 1.4.3. packageManager moves from 1.4.2 to 1.4.3.

[1.1.48] — 2026-09-25

Fixed

  • The homepage roadmap no longer promises Wayland capture for v1.6. The item now says no release is committed for it.
  • The screen-capture page names the libraries the Linux packages actually carry. It now lists GTK 3, WebKitGTK 4.1, libudev and libdbus as bundled, libxcb from the system, and points to the install page.

Changed

  • Last-Modified reflects this release.

[1.1.47] — 2026-09-25

Fixed

  • Structured-data dates are full datetimes. datePublished and dateModified on the homepage and comparison pages now carry a UTC time instead of a bare date.
  • The SoftwareApplication node's @id carries the trailing slash.

Changed

  • Last-Modified reflects this release.

[1.1.46] — 2026-09-25

Fixed

  • The ambient-mode callout shows ambient mode. It had reused the full-mode screenshot; it is now a crop of the real edge-signal panel from the hero screenshot.
  • No invented telemetry over the screenshot. The static Δ 12 ms · Σ 60 fps overlay is gone.
  • The install page names the libraries the AppImage actually ships. GTK 3, WebKitGTK 4.1, libudev and libdbus are bundled; libxcb comes from the system, and libpipewire is not included.
  • Image alt text describes the image. The ambient and full-mode screenshots had alts naming things their images did not show.

Changed

  • Last-Modified reflects this release.

[1.1.45] — 2026-09-25

Fixed

  • Wayland is described the way the app actually behaves. The screen-capture, multi-display and install docs and the homepage Linux card now say Wayland is not a supported capture path; use an X11 session.
  • llms.txt no longer names a config file the app does not write. Its config-reference entry now names shell-state.json instead of ~/.config/lumasync/app.json.
  • robots.txt enforces its own ai-train=no. ClaudeBot and Applebot-Extended are now disallowed, Claude-SearchBot is allowed by name, and the retired anthropic-ai token is removed.
  • robots.txt passes Lighthouse's validity audit. The Content-Usage line is removed; Content-Signal stays.
  • /favicon.ico exists. It is now built from the 16/32/48 brand SVGs and linked alongside the SVG favicon.
  • The search button's accessible name contains its visible label. Lighthouse's label-in-name audit flagged aria-label="Open search" against the visible ⌘K.

Changed

  • Homepage screenshots are served at the size they are displayed. They now render through astro:assets as responsive WebP srcsets with PNG fallbacks under /_astro/.
  • Descriptions fit the snippet. Five page descriptions and two docs-group ledes were trimmed to 160 characters or fewer.
  • mask-icon is gone — Safari's pinned-tab icon.
  • Last-Modified reflects this release.

[1.1.44] — 2026-09-21

Changed

  • Bun replaces pnpm as the package manager; the site it builds is unchanged. bun.lock replaces pnpm-lock.yaml, and security floors move to the top-level overrides key.
  • The CVE gate now covers dev dependencies too. CI runs bun audit, the licence gate uses bun pm licenses --prod, and Dependabot tracks the bun ecosystem.
  • Last-Modified reflects this release.

[1.1.43] — 2026-09-21

Fixed

  • The homepage has a title longer than its own brand name. It now reads LumaSync — Ambilight for Philips Hue, WLED and WS2812B.
  • The homepage description fits the snippet. The rewritten 146-character version leads with "Local-only, brand-agnostic, MIT-licensed".
  • /sitemap.xml answers instead of 404ing. It now 301-redirects to sitemap-index.xml.

Changed

  • Last-Modified reflects this release.

[1.1.42] — 2026-09-21

Fixed

  • Legacy aliases resolve in one edge 301 instead of two hops. All thirteen redirect aliases moved from Astro's redirects map to public/_redirects.
  • The six docs group hubs have OG cards instead of a 404. /docs/getting-started/, /docs/hue/, /docs/usb-leds/, /docs/ambilight/, /docs/advanced/ and /docs/reference/ now have their own cards.
  • X-Markdown-Tokens no longer reports 0 on a HEAD request. It falls back to Content-Length, or is omitted when neither a body nor a length is available.

Changed

  • Last-Modified reflects this release.

[1.1.41] — 2026-09-21

Fixed

  • The site stopped claiming analytics it does not run. The privacy notice, telemetry reference and llms.txt now say lumasync.app collects nothing; the Umami wiring is described as dormant.
  • Every external footer link carries rel="noopener noreferrer", not just the tracked ones.
  • fflate is floored at 0.7.5, closing GHSA-px8p-9vwx-vf98. The override is capped below 0.8.0.

Changed

  • Dependencies moved to latest stable, with three deliberate exceptions. Astro 7.3.3, @astrojs/mdx 8.0.1 (major), @astrojs/sitemap 3.7.4, Satori 0.33.4, marked 18.0.13, DOMPurify 3.4.15, isomorphic-dompurify 4.3.0 (major), Prettier 3.9.8 and pnpm/action-setup 6.1.0; held: TypeScript 6.x, prettier-plugin-astro 0.14.1, @astrojs/language-server 2.16.13.

[1.1.40] — 2026-08-20

Fixed

  • The docs stop describing behaviour the app does not have. WLED mDNS auto-discovery, the app.json config file and the Wayland figures on the performance page are gone; the config-file reference now documents shell-state.json.
  • Privacy and telemetry now agree on where the Hue credential lives. It is in the OS keychain.
  • Last-Modified reflects this release. The updated: dates on the thirteen corrected pages do too.

Changed

  • sanitizeUrl in the search component returns the parser's own output rather than validating one string and handing back another.
  • Dependencies: Astro 7.2.0 → 7.2.2.

[1.1.39] — 2026-08-11

Fixed

  • The install guide now describes the first launch that actually happens. It covers macOS's System Settings → Privacy & Security → Open Anyway step and the Windows SmartScreen and Smart App Control prompts.
  • "Signed" no longer means two different things on the same page. The Windows section now says the MSI carries only a minisign signature for the updater, not Authenticode.
  • Inline links, code spans, and emphasis no longer swallow the space before them. Fifteen places across the site rendered words run together, such as "standardCode of Conduct".
  • The /compare listing heading uses the sans-serif page title like every other listing page.

Changed

  • System requirements read macOS 12.3, matching the app. Corrected in the install guide, the USB controller driver notes and the FAQ schema.
  • The Flathub package is no longer promised. The landing page roadmap lists Wayland capture via xdg-desktop-portal in its place.

[1.1.38] — 2026-08-10

Added

  • Hue Bridge Pro is documented as a supported bridge. A new Bridge Pro section on Hue pairing and an entry on Hue troubleshooting cover v1.5.4's HTTPS-first pairing.

Changed

  • The Hue pairing error table no longer under-describes the link-button case. The pairing and troubleshooting pages now say how v1.5.3 and v1.5.4 each report a rejected link button.
  • The outbound-call table on the Telemetry page reflects the real bridge transport. It now reads HTTPS with HTTP fallback.
  • Manual-IP guidance records the readiness-check guard. v1.5.4 rejects loopback, multicast and broadcast addresses before the Hue stream-readiness probe connects.
  • Room map editor notes extended for v1.5.4 — accessible names on context-menu entries and a faster object drag.

Fixed

  • The landing page's "Shipped" roadmap column no longer mislabels itself on a submodule bump. Its bullets now describe v1.5.4, including Bridge Pro pairing and RUSTSEC-2026-0235.

[1.1.37] — 2026-08-10

Security

  • The fast-uri override no longer pins the toolchain to a vulnerable release. The floor moves to ^3.1.5, closing GHSA-7p8r-x3mc-p8w7 in this development-only dependency.
  • Dependabot's security update for fast-uri can complete again.

[1.1.36] — 2026-08-10

Security

  • Two high-severity CVEs in the shipped dependency tree are closed. js-yaml resolves to 4.3.1 (GHSA-5p4m-2wfm-xmqj) and nanoid to 3.3.18 (GHSA-2v37-7h3g-55p8).
  • **Transitive override fl

Releases

  • v1.2.2

    Changed

    • The note at the top of every page can no longer be dismissed. The × button is gone and the site stores nothing in the browser for it; a note hidden earlier shows again.
    Open on GitHub
  • v1.2.1

    Fixed

    • Social preview images refresh when they change. /og/* images are revalidated instead of cached as immutable for a year, since their URLs do not change when the image does.
    Open on GitHub
  • v1.2.0

    Added

    • A dismissible note at the top of every page points to Palmye, a travel eSIM from LumaSync's maker. It is a plain nofollow link with the logo served from this site; × hides it and the choice stays in the browser's local storage.

    Changed

    • The privacy notice describes the note and the local-storage flag behind ×; its effective date is 2 November 2026. The license page and README state that the Palmye logo is not covered by the site's licenses.

    Build

    • satori 0.63.2. Social preview images are re-rendered; title letter spacing shifts slightly.
    Open on GitHub
  • v1.1.50

    Security

    • One critical and seven high-severity dependency advisories are cleared. dompurify 3.4.17 (GHSA-cg2g-xh64-v4q7, GHSA-mrv2-3pqr-j5jr) and undici 8.12.3 (GHSA-xjj6-f33q-929c, GHSA-4w7w-5xrc-9h26, GHSA-2m5v-pch6-74hx, GHSA-qrxm-fqhp-jwvm) arrive through in-range updates; new overrides floors for vite and zod close GHSA-587h-7wmj-h5pm and GHSA-mrhx-c7xc-m3w5.

    Build

    • Dependencies updated within their ranges. Astro 7.4.5, @astrojs/mdx 8.1.2, Pagefind 1.6.0, marked 18.1.3, satori 0.33.5, @astrojs/check 0.9.12, isomorphic-dompurify 4.6.0 and Prettier 3.9.10.
    • prettier-plugin-astro 1.1.2. Astro files are reformatted to its output; the built pages are unchanged.
    • The deploy workflow uses cloudflare/wrangler-action 4.1.3.

    Docs

    • CONTRIBUTING.md asks for feature claims to be checked against the app source, not its changelog.
    • Older changelog entries are shortened to what changed.
    Open on GitHub
  • v1.1.49

    Changed

    • The footer names the person behind LumaSync. The bottom line now ends with "Made by Samet Özkan", linking to the author's site with rel="author", next to the existing copyright line, which still reads voyvodka. humans.txt names the maintainer and links the same site.

    SEO

    • The Organization schema's founder is the author, not just a handle. founder now carries the author's name, voyvodka as alternateName, the site URL, LinkedIn beside GitHub in sameAs, and the same @id the author's site uses for its Person, so the two sites describe one person rather than two.

    Security

    • Three high-severity advisories in transitive dependencies are cleared. overrides floors for sharp, http-cache-semantics and source-map-js lift the copies pulled in through astro, @tailwindcss/vite and isomorphic-dompurify past GHSA-wq5f-xc86-pv6w, GHSA-ch52-4w7c-c8xp and GHSA-68fv-2mgg-jv7q, so the high-severity audit gate passes again.

    Build

    • Bun 1.4.3. packageManager moves from 1.4.2 to the current stable release; CI and deploy read it through bun-version-file, and the lockfile installs unchanged.
    Open on GitHub
  • v1.1.48 — a roadmap that promises no Wayland date, and Linux libraries named as measured

    Fixed

    • The homepage roadmap no longer promises Wayland capture for v1.6. It listed Wayland screen capture via xdg-desktop-portal under "v1.6 — queued". The shipped app's own source (v1.5.4) says Wayland hardening lands in v2.0, and the app's newest line deliberately names no release for it at all, because two of its own documents had promised different versions. The item now says no release is committed, the way the OpenRGB item already carries its own track. The Wayland descriptions on the screen-capture, install, multi-display and performance pages were checked against the pinned source and already matched it.
    • The screen-capture page names the libraries the Linux packages actually carry. It still said the AppImage, deb and rpm bundle libxcb, libxrandr, libpipewire and libdbus — the sentence v1.1.46 corrected on the install page after listing the v1.5.4 AppImage, left standing on its sibling page. It now says the AppImage bundles GTK 3, WebKitGTK 4.1, libudev and libdbus and uses the system libxcb, and points at the install page.

    Changed

    • Last-Modified reflects this release.
    Open on GitHub
  • v1.1.47 — structured-data dates that pass the Rich Results Test

    Fixed

    • Structured-data dates are full datetimes. Google's Rich Results Test flagged the homepage Article with four non-critical issues: datePublished and dateModified were invalid datetime values with no timezone. Both were bare YYYY-MM-DD, and the comparison pages emitted the same shape. The schema builders now pin a date-only input to UTC midnight (2026-08-10T00:00:00Z) and pass full timestamps through untouched, so every page is covered from one place.
    • The SoftwareApplication node's @id carries the trailing slash. It was /download#software on a site that canonicalises to /download/ — the JSON-LD surface of the trailing-slash rule.

    Changed

    • Last-Modified reflects this release.

    Not changed, deliberately

    • No aggregateRating. The Rich Results Test lists it as a missing optional field on SoftwareApplication. There are no user ratings to cite, and a self-authored rating is not something to put in markup.
    Open on GitHub
  • v1.1.46 — the ambient callout shows ambient mode, and the AppImage library list is measured

    Fixed

    • The ambient-mode callout shows ambient mode. Its image was a byte-identical copy of the full-mode screenshot — the app in Solid mode, no capture running — under a section headed "Real-time screen capture". It is now a crop of the edge-signal panel from the real hero screenshot: Ambilight active, the capture-to-strip preview with per-edge LED counts, the app's own Δ/Σ reading, and the smoothing, saturation and black-border controls. v1.1.45's move to responsive images surfaced the duplicate, because both files hashed to the same output.
    • No invented telemetry over the screenshot. A static Δ 12 ms · Σ 60 fps pill sat on top of that image as page markup. The panel underneath now carries the app's real reading, so the overlay went rather than contradict it.
    • The install page names the libraries the AppImage actually ships. It said the AppImage bundles libxcb, libxrandr, libpipewire and libdbus. Listing the v1.5.4 AppImage shows no libpipewire at all, and the binary links libxcb.so.1 from the system rather than a bundled copy; GTK 3, WebKitGTK 4.1, libudev and libdbus are bundled. The sentence now says exactly that.
    • Image alt text describes the image. The ambient and full-mode screenshots had alts naming things their images did not show.

    Changed

    • Last-Modified reflects this release.
    Open on GitHub
  • v1.1.45 — Wayland described as shipped, robots.txt that enforces its own training policy, responsive screenshots

    Fixed

    • Wayland is described the way the app actually behaves. Four surfaces — the screen-capture, multi-display and install docs and the homepage Linux card — said Wayland sessions capture through XWayland, and the screen-capture page presented the portal dialog as a defined fallback. The app's capture source says otherwise: xcap detects a Wayland session itself and falls through to PipeWire / xdg-desktop-portal, a path LumaSync neither blocks nor tests. The performance page already said so; the other four now agree with it — Wayland is not a supported capture path, use an X11 session.
    • llms.txt no longer names a config file the app does not write. Its config-reference entry still pointed at ~/.config/lumasync/app.json, the claim v1.1.40 withdrew from the docs but missed in the hand-written file answer engines read first. It now names shell-state.json, matching the reference page.
    • robots.txt enforces its own ai-train=no. ClaudeBot sat under the retrieval heading and was allowed, but Anthropic documents it as the crawler that collects content for training; citation in Claude runs through Claude-SearchBot and Claude-User. Applebot-Extended was allowed too, and Apple documents it as the opt-out from training its foundation models, one that leaves Apple search inclusion untouched. Both are now disallowed, Claude-SearchBot is allowed by name, and the retired anthropic-ai token — which looked like coverage and controlled nothing — is gone.
    • robots.txt passes Lighthouse's validity audit. The Content-Usage (IETF AIPREF) line was reported as an unknown directive, which failed the robots-txt audit and held the SEO category below 100 on both form factors. The drafts are unratified and no crawler is known to read the line, so it was costing a score for a declaration with no effect. Content-Signal passes the audit and stays.
    • /favicon.ico exists. It returned 404 to every browser and client that probes the conventional path, and left browsers without SVG favicon support (Safari before 26) on the PNG fallback at best. It is now packed at build time from the pixel-hinted 16/32/48 brand SVGs and linked alongside the SVG.
    • The search button's accessible name contains its visible label. Lighthouse's label-in-name audit flagged aria-label="Open search" against the visible ⌘K.

    Changed

    • Homepage screenshots are served at the size they are displayed. Every screenshot shipped as one 1850px file while rendering at 348–578px on desktop and the viewport width on mobile; Lighthouse counted 130 KiB (mobile) to 183 KiB (desktop) of avoidable bytes, the hero — the LCP element — among them. The sources moved to src/assets/ and render through astro:assets with 480–1600w WebP srcsets and PNG fallbacks. They land under /_astro/ with content-hashed names, so the existing immutable cache rule covers them and the /media/* rule went with the directory.
    • Descriptions fit the snippet. Five page descriptions and two docs-group ledes ran past 160 characters; each was trimmed without changing what it says.
    • mask-icon is gone — Safari's pinned-tab icon, undocumented by Apple for years.
    • Last-Modified reflects this release.

    Not changed, deliberately

    • Critical CSS is not inlined. Lighthouse lists the two stylesheets as render-blocking. Astro inlines by vite.build.assetsInlineLimit, and raising it far enough to cover the homepage stylesheet would also base64 the smaller font subsets into CSS and defeat their preloads.
    • Best Practices is held below 100 by a script this repository does not ship. Both deprecation warnings come from /cdn-cgi/challenge-platform/scripts/jsd/main.js, injected at the edge by Cloudflare's JavaScript Detections, which Bot Fight Mode enables and does not allow switching off. It is a zone setting, not code; a local build without it scores 100.
    Open on GitHub
  • v1.1.44 — Bun replaces pnpm, with an unchanged build and a stricter CVE gate

    Changed

    • Bun replaces pnpm as the package manager; the site it builds is unchanged. pnpm-lock.yaml is gone and bun.lock takes its place, generated by Bun 1.4.2 migrating the pnpm lockfile rather than re-resolving from scratch — so every installed version stayed where it was, security floors included. Bun does not read pnpm.overrides, so the floors moved to the top-level overrides key; fflate still resolves to 0.7.5, which matters because an unpinned fflate once turned every OG card into a placeholder without failing the build. Bun is the package manager only: Astro, Pagefind and Lighthouse CI still run on Node from .nvmrc. Evidence that the output did not move: the built dist/ has the same file list as the pnpm build, 40 of 40 OG cards render, and a sampled card is byte-identical to the one in production.
    • The CVE gate now covers dev dependencies too. pnpm audit --prod gated only the shipped tree; bun audit has no production-only mode, so a high-severity advisory in build tooling now fails CI as well. That is stricter, not looser. A dev-only advisory with no available fix is waived by its GHSA id with --ignore, not by dropping the gate. The licence gate keeps its production-only scope through bun pm licenses --prod, and Dependabot now tracks the bun ecosystem.
    • Last-Modified reflects this release.
    Open on GitHub
  • v1.1.43

    Fixed

    • The homepage has a title longer than its own brand name. <title> was LumaSync — eight characters, no category term, nothing for a non-brand query to match, and short enough to be a standing invitation for Google to write its own title instead. It now reads LumaSync — Ambilight for Philips Hue, WLED and WS2812B: 54 characters, brand first so the brand query still reads cleanly, then the category term the site already uses for itself throughout, then the three sinks the app drives. "Philips Hue" earns its place on measured demand rather than on taste — hue entertainment area and philips hue entertainment area are the site's highest-impression non-brand queries, and the homepage carried no text matching either. Nothing in the new title is a new claim. SEO.astro's suffix rule moved from a title === 'LumaSync' string test to a route check: that test was really asking "is this the homepage", which is why the homepage title could never be anything but the bare brand without doubling into … · LumaSync. A substring test would have been wrong — comparison pages carry "LumaSync" in their own titles and keep the suffix.
    • The homepage description fits the snippet. It was 201 characters against a display limit around 155–160, so Local-only, brand-agnostic, MIT-licensed — the positioning, and the part a reader most needs — was cut on every result. The rewritten 146-character version leads with it. Philips Hue Entertainment areas is kept in full rather than shortened: that exact phrase is a query the site already receives impressions for, and trading a keyword match for four characters is a bad trade.
    • /sitemap.xml answers instead of 404ing. Nothing was broken — Astro's sitemap integration names the index sitemap-index.xml, robots.txt points at it, and Search Console has it submitted and reading successfully. But crawlers and audit tools probe the conventional path by habit. It now forwards with a 301 from public/_redirects rather than duplicating the file, so there stays one sitemap with one generator.

    Changed

    • Last-Modified reflects this release.

    Not changed, deliberately

    • A GEO audit scores the site's AI-bot posture as three critical failures — GPTBot, CCBot and Bytespider blocked. All three are training crawlers, and the tooling's claim that blocking GPTBot costs ChatGPT search visibility is wrong per OpenAI's own bot documentation: that is OAI-SearchBot's job. The live robots.txt allows every retrieval crawler — OAI-SearchBot, ChatGPT-User, PerplexityBot, Claude-User — so citation visibility is intact and the score is low by choice. Recorded here so the next audit does not read it as a regression and "fix" it.
    Open on GitHub
  • v1.1.42

    Fixed

    • Legacy aliases resolve in one edge 301 instead of two hops. All thirteen entries in Astro's redirects map were taking two hops with a meta-refresh as the final step: Astro renders each entry as an HTML page carrying http-equiv="refresh", and trailingSlash: 'always' 308s the slashless request before that page is ever reached — /quick-start → 308 → /quick-start/ → meta-refresh → /docs/getting-started/first-setup/. The comment above the map claimed this was prevented and had been wrong for as long as it had been there; it addressed the redirect target's trailing slash, while the second hop comes from the source's missing one. Measured on all thirteen with a hop counter that follows meta-refresh, which curl -L does not. The rules move to public/_redirects, where this repo already resolves /security in a single hop, and where Cloudflare applies them "regardless of whether or not an asset matches the incoming request" — ahead of both the trailing-slash layer and the asset lookup. The stale comment describing an emission that no longer happens is gone, along with the "/led-calibration/" has no <html> element build warning those generated pages produced.
    • The six docs group hubs have OG cards instead of a 404. /docs/getting-started/, /docs/hue/, /docs/usb-leds/, /docs/ambilight/, /docs/advanced/ and /docs/reference/ each advertised an og:image that returned 404 — six of the forty URLs in the sitemap sharing a card that renders blank everywhere it is posted. SEO.astro's derivedOgPath() strips the slashes off the pathname, so /docs/hue/ asks for /og/docs/hue.png; the generator keyed every individual doc, every comparison page and both top-level hubs, but never the six group hubs in between, and a missing key produces a request-time 404 rather than a build error. The entries are now derived from DOC_GROUPS so a seventh group cannot reintroduce the gap, and GROUP_LEDE moved into src/lib/content.ts so the card and the page it fronts read from one source rather than two copies. dist/og/ goes from 34 cards to 40, matching the sitemap exactly.
    • X-Markdown-Tokens no longer reports 0 on a HEAD request. passThrough() computed the estimate from await response.text() unconditionally, and on a bodyless HEAD response that resolves to an empty string — so the header went out as a confident zero. That is the worst possible wrong value: an agent probes with HEAD precisely to size the fetch before making it, which is the only reason the header exists, and zero says the document is empty rather than "no estimate available". The GET path is untouched and its verified numbers do not move; only the bodyless case falls back to the declared Content-Length, and with neither a body nor a length it now sends no estimate at all.

    Changed

    • Last-Modified reflects this release. The middleware constant is bumped alongside the deploy, as the release checklist requires.
    Open on GitHub
  • v1.1.41

    Fixed

    • The site stopped claiming analytics it does not run. The privacy notice, the telemetry reference and llms.txt all described lumasync.app as collecting aggregate page metrics through self-hosted Umami at umami.lumasync.app — down to a field-by-field list of what was recorded per page view. None of it was running. The subdomain is NXDOMAIN, the Pages production environment sets neither PUBLIC_UMAMI_SITE_ID nor PUBLIC_UMAMI_SRC, so the layout's guard has never been true in production, and the served HTML carries no tracking script of any kind; the site's own CSP (script-src 'self', connect-src 'self') would have blocked the script from that origin regardless. All three surfaces now say the site collects nothing, name Cloudflare's edge traffic data as the only record of a visit, and describe the Umami wiring accurately — present in the source, dormant, gated on two build variables production does not set. effective: on the privacy notice is unchanged: the policy did not change, its description of the site was wrong.
    • Every external footer link carries rel="noopener noreferrer", not just the tracked ones. The attribute was gated on link.umamiTarget, so a link's reverse-tabnabbing and Referer-leak protection depended on whether someone had remembered to tag it for analytics. The condition now reads the URL itself.
    • fflate is floored at 0.7.5, closing GHSA-px8p-9vwx-vf98. Satori pulled 0.7.3 transitively — twice — into the shipped tree, where unzipSync can spin forever on a malformed ZIP64 archive. Rated moderate, so it sat under the CI audit gate's high threshold and never failed a build; pnpm audit --prod now reports no known vulnerabilities at all. The override is capped below 0.8.0 on purpose: an open-ended floor resolves to 0.8.3, which changes how @shuding/opentype.js decodes the bundled WOFF fonts and turns every OG image on the site into rows of tofu boxes — while the build exits 0, warns about nothing, and writes 28 valid 1200×630 PNGs. Caught by decoding the PNG pixel data and diffing it against a pre-change build.

    Changed

    • Dependencies moved to latest stable, with three deliberate exceptions. Astro 7.2.2 → 7.3.3, @astrojs/mdx 7.0.5 → 8.0.1, @astrojs/sitemap 3.7.3 → 3.7.4, Satori 0.29.0 → 0.33.4, marked 18.0.9 → 18.0.13, DOMPurify 3.4.13 → 3.4.15, isomorphic-dompurify 3.22.0 → 4.3.0, Prettier 3.9.6 → 3.9.8, and pnpm/action-setup 6.0.10 → 6.1.0 in both workflows. Held back: TypeScript stays on 6.x because astro check refuses to run against the 7.x native compiler, which does not yet expose the programmatic API the language server drives — upgrading turns a CI gate into a hard failure with no diagnostics. prettier-plugin-astro stays on 0.14.1 because 1.0.1 does not converge; formatting src/pages/index.astro four times in a row produces four different files, so prettier --check can never pass against it. @astrojs/language-server is pinned to 2.16.13 through pnpm.overrides because 2.17.0 mis-parses the multi-line set:html expression in Schema.astro and reports five phantom syntax errors on a file astro build compiles without complaint.
    • The build output was verified unchanged across the upgrade. Every emitted file is byte-identical to a pre-upgrade build except the three Pagefind core scripts, which stamp-pagefind.mjs rewrites on each build by design, and the sitemap's lastmod values, which derive from source-file mtimes.
    Open on GitHub
  • v1.1.40 — honest docs published, freshness metadata refreshed

    Fixed

    • The docs stop describing behaviour the app does not have. Three claims were false against the shipped code. WLED boards were presented as auto-discovered over mDNS by browsing _wled._tcp.local. in seven places, while discover_wled_devices is a single-IP /json/info probe and the only mDNS browser the app registers is Hue's — so the WLED service name was listed on the Telemetry page as a LAN request that is never made. The config-file reference named app.json on every platform and ~/.config on Linux, so the reset instructions told users to delete a file that does not exist; the real file is shell-state.json under the XDG data directory, and the wrong name had spread to eleven further pages including the privacy notice. That page's field table was fictional in shape as well, documenting nested hue.* / wled.* groups and hand-edit advice for keys absent from ShellState, two schema versions behind. And the performance page published measured-looking figures for a Wayland capture path that is neither implemented nor supported.
    • Privacy and telemetry now agree on where the Hue credential lives. One page had it in the JSON state file; it has been in the OS keychain since v1.5.0.
    • Last-Modified reflects this release. The middleware constant had been sitting at 10 August while the content underneath it changed, and updated: frontmatter on the thirteen corrected pages still claimed dates as old as April — so the JSON-LD dateModified that answer engines read was dating a rewritten page to before its rewrite.

    Changed

    • sanitizeUrl in the search component returns the parser's own output rather than validating one string and handing back another. An automated report claimed a javascript: bypass through control characters; it does not exist — the WHATWG URL parser strips tab, LF and CR before parsing, exactly as the HTML parser does, and a sweep of every C0 character against a simulation of the browser's href pipeline found no input the guard reads as http: that the DOM would execute. The shape was tightened anyway, because validate-one-value-return-another is what a real bypass would need.
    • The deploy contract is written down. deploy.yml has fired only on a published release for some time, but the project notes still documented a manual wrangler push as the deploy path, which is how this release's content fixes sat merged and unpublished for five days. Merging is now documented as not shipping, with the ad-hoc workflow_dispatch path and a verify-by-content step alongside it.
    • Dependencies: Astro 7.2.0 → 7.2.2.
    Open on GitHub
  • v1.1.39 — honest first-launch documentation

    Fixed

    • The install guide now describes the first launch that actually happens. LumaSync is not notarized by Apple, so macOS blocks the app on first open and — since Sequoia removed the Control-click override — the user has to go through System Settings → Privacy & Security → Open Anyway. The guide previously jumped straight to the Screen Recording prompt, a step nobody could reach, and any user who searched for help found the Control-click advice that no longer works. Both paths are now written out, and the Windows section documents the SmartScreen "unknown publisher" prompt along with the fact that Smart App Control blocks unsigned installers outright.
    • "Signed" no longer means two different things on the same page. The Windows section called the MSI signed while the only signature involved is minisign, which the updater uses to verify a download before replacing anything on disk. That is not an Authenticode signature and does not affect the SmartScreen prompt; the page now says so.
    • Inline links, code spans, and emphasis no longer swallow the space before them. In .astro, a newline between text and an inline tag is deleted rather than collapsed, so fifteen places across the landing, license, community, compare, docs and search surfaces rendered as "standardCode of Conduct", "stack),WLED", or "affiliation.Philips Hue". Verified against the built HTML across all pages rather than the source.
    • The /compare listing heading uses the sans-serif page title like every other listing page. global.css reserves the serif display face for editorial moments — the landing hero and the individual comparison pages — and the listing was quietly using it.

    Changed

    • System requirements read macOS 12.3, matching the app. tauri.conf.json sets minimumSystemVersion to 12.3 while the site said 13+, telling supported users they were unsupported. Corrected in the install guide, the USB controller driver notes, and the FAQ schema that search engines read.
    • The Flathub package is no longer promised. It is gated on Linux Wayland capture, which does not exist yet, and Flathub review would not favour an X11-only app requesting the broadest device permission available. The landing page roadmap now lists Wayland capture via xdg-desktop-portal in its place — the actual prerequisite, and something that can be honestly queued.
    Open on GitHub
  • v1.1.38 — LumaSync v1.5.4 documentation sync

    Site documentation synced to LumaSync v1.5.4. The vendor submodule pin moves to v1.5.4, so /changelog/ and every version-derived string on the site now quote the new release.

    Added

    • Hue Bridge Pro documented as a supported bridge — it serves its local API over HTTPS only, which the app's plain-HTTP CLIP v1 calls could not reach before v1.5.4.
    • New Bridge Pro pairing section on the Hue pairing page, with a symptom-first counterpart in Hue troubleshooting for the "Auth error / Credentials expired" report.
    • Bridge Pro named in the hardware checklist, install prerequisites, and the landing page's hardware FAQ answer.

    Changed

    • Pairing and troubleshooting pages record that a rejected link button no longer surfaces as an expired-credentials error.
    • Telemetry outbound-call table corrected — the bridge row claimed HTTPS while the app was calling HTTP; it now reads HTTPS with HTTP fallback.
    • Manual-IP guidance notes the v1.5.4 stream-readiness IPv4 guard, the Hue counterpart to the documented WLED_INVALID_IP check.
    • Room map editor notes extended for v1.5.4 — context-menu accessible names and single-pass drag traversal.

    Fixed

    • Landing page "Shipped" roadmap bullets rewritten. The heading interpolates the pinned version while the bullets are hand-written, so the submodule bump would have retitled v1.5.3 content as v1.5.4.
    Open on GitHub
  • v1.1.37 — fast-uri override floor raised to clear GHSA-7p8r-x3mc-p8w7

    Security

    • The fast-uri override no longer pins the toolchain to a vulnerable release. GHSA-7p8r-x3mc-p8w7 (host confusion via a backslash authority introducer) affects fast-uri below 3.1.5, and the override floor set in v1.1.35 was still ^3.1.2 — which the lockfile satisfied at 3.1.4. The floor moves to ^3.1.5 and the lockfile resolves accordingly.
    • The package is development-scoped only (@astrojs/check → @astrojs/language-server → volar-service-yaml → yaml-language-server → ajv), so it never reached the shipped bundle and the --prod audit gate stayed green throughout. pnpm audit --audit-level=high across the full tree, dev included, is now clean too.
    • Dependabot's security update for fast-uri can complete again. The caret override capped resolution below 4.x, so Dependabot's attempt to move to 4.1.2 failed with "the latest possible version that can be installed is 3.1.4" and the update job errored on every run. Raising the floor within the 3.x line resolves the advisory without taking the major.

    Full changelog: https://github.com/voyvodka/LumaSync-Site/compare/v1.1.36...v1.1.37

    Open on GitHub
  • v1.1.36 — CVE override floors, Last-Modified refresh, dependency bumps

    Security

    • Two high-severity CVEs in the shipped dependency tree are closed — js-yaml (GHSA-5p4m-2wfm-xmqj, quadratic CPU consumption resolving !!omap) and nanoid (GHSA-2v37-7h3g-55p8, custom generators can loop indefinitely when size is zero).
    • Neither is a direct dependency: js-yaml arrives via @astrojs/mdx → @astrojs/internal-helpers, nanoid via @tailwindcss/vite → vite → postcss. The refreshed lockfile resolves both to patched releases (4.3.1 and 3.3.18).
    • Transitive override floors raised to match the new advisories — js-yaml moves from ^4.3.0 (itself now vulnerable) to ^4.3.1, and nanoid joins pnpm.overrides at >=3.3.17. Both floors already match what the lockfile resolves, so there is no resolution churn.
    • The pnpm audit --prod --audit-level=high gate had been failing on main and passes again.

    Fixed

    • The site-wide Last-Modified freshness signal is current again. The edge middleware's LAST_MODIFIED constant had been left at 26 Jun 2026 across v1.1.34 and v1.1.35, so HTML and markdown responses Cloudflare doesn't already stamp were advertising two-month-old content to crawlers and AI answer engines — the exact staleness the constant exists to prevent.

    Dependencies

    • Minor/patch group bump across four packages — astro 7.1.5 → 7.2.0 (which also moves vite 8.1.5 → 8.2.1), marked 18.0.7 → 18.0.9, dompurify 3.4.12 → 3.4.13, isomorphic-dompurify 3.19.0 → 3.22.0. Manifest and lockfile only, no source change.

    CI

    • pnpm/action-setup pinned forward from v6.0.9 to v6.0.10 in both the CI and deploy workflows, commit-SHA pinned as before.

    Full changelog: https://github.com/voyvodka/LumaSync-Site/compare/v1.1.35...v1.1.36

    Open on GitHub
  • v1.1.35 — transitive CVE overrides, Astro 7, dependency refresh

    Security

    • Four high-severity CVEs closed in the shipped dependency tree — js-yaml (GHSA-52cp-r559-cp3m), svgo (GHSA-2p49-hgcm-8545), sharp (GHSA-f88m-g3jw-g9cj), postcss (GHSA-r28c-9q8g-f849).
    • All four arrive transitively through astro, @astrojs/mdx and @tailwindcss/vite; each is pinned to its patched range via pnpm.overrides.
    • The pnpm audit --prod --audit-level=high gate had been failing on main and passes again.

    Fixed

    • TV sizes in the hardware checklist now use U+2033 (double prime) instead of an ambiguous straight quote — the correct character for inches.
    • The USB controllers page heading's opening quote no longer renders as a closing quote.

    Dependencies

    • Astro 6.4.8 → 7.1.5 and @astrojs/mdx 6.0.3 → 7.0.5, which also moves vite 7 → 8.
    • Verified against a baseline build: identical output tree (272 files, 54 HTML pages, 34 byte-identical OG images), scoped-style hashes resolve.
    • Remaining deltas are the generator meta tag, regenerated data-astro-cid hashes, and tighter minification.
    • TypeScript held at 6.0.3 — the 7.x native compiler drops the programmatic Language Service API astro check needs (withastro/roadmap#1321).
    • Minor/patch group bump across 11 packages: satori, tailwindcss, @tailwindcss/vite, three @fontsource families, marked, isomorphic-dompurify, prettier, prettier-plugin-tailwindcss, @astrojs/check.

    CI

    • actions/setup-node v6 → v7 in the CI and deploy workflows.
    Open on GitHub
  • v1.1.34 — inline-link press states, dependency bumps

    Fixed

    • Press-state feedback on inline links now actually renders. The 404 page's .home-cta and the /download/ version pill both declared a prefers-reduced-motion-gated transform: scale(0.96) on :active, but both are anchors laid out as non-replaced inline boxes — where CSS transform does not apply. The press animation was silently dead CSS. Both now set display: inline-block, so the tactile :active treatment shipped for the version pill in v1.1.31 finally takes effect.

    Accessibility

    • The landing page's .inline-cta links press like the site's other CTAs — display: inline-block, a transform transition, and a prefers-reduced-motion-gated scale(0.96) on :active, matching the primary/secondary CTAs and compare cards.

    Dependencies

    • Minor/patch group bumps across two batches — tailwindcss and @tailwindcss/vite 4.3.0 → 4.3.2, marked 18.0.5 → 18.0.6, dompurify 3.4.11 → 3.4.12, prettier 3.9.1 → 3.9.5. Manifest + lockfile only; all CI gates pass unchanged.

    Full changelog: https://github.com/voyvodka/LumaSync-Site/compare/v1.1.33...v1.1.34

    Open on GitHub