Commit Graph

1186 Commits

Author SHA1 Message Date
Mudskipper
a5f3c278b7 feat(manual): add "On this page" sidebar with scrollspy
Adds a sticky right rail on manual pages (xl+ viewports) that lists h2/h3
headings as anchor links, with an IntersectionObserver highlighting the
heading currently in view. Heading scroll-margin offsets anchored jumps
so they clear the sticky site header.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 20:25:10 +10:00
Mudskipper
7b4ae1b2b9 feat(about): two-track Multiselect + slide-in Drop and trim showcases
Make the editing-experience cards feel like real Audacity snapshots.

Multiselect:
- Switch from Track to TrackNew so clip headers render as real React
  components (proper "..." menu buttons, hover states)
- Two stacked tracks (vocals arrangement above, drum loops below)
  with selection state synchronized between them
- ResizeObserver-driven sizing fills the card's 4:3 area on both
  axes — no internal padding, no centered dead space
- Animation cycles through specific multi-select patterns instead of
  sweeping all clips: nothing → contiguous pair on both tracks →
  non-contiguous pair on vocals only → drum-only triple → single pair
  on both → repeat. Covers shift-click and cmd-click cases.

Drop and trim (new DropAndTrimShowcase):
- Three-phase loop: long host vocal take → Bridge clip slides in
  from off-frame on the right (cubic-bezier ease-out-expo) → host
  splits into left + Bridge + right with Bridge selected
- Floating ghost clip lifted to zIndex 20 so it sits above the host
  during the slide
- Drum loops below for project context, untouched across phases

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 17:04:27 +10:00
Mudskipper
beef63727f feat(about): full Audacity-shell workspace previews with per-tab variants
Replace the Workspaces section's placeholder stage with a faithful
Audacity 4 UI built from the @dilsonspickles/components 0.2.3
playbook. Each tab (Classic, Music, Modern, Custom) renders the same
WorkspaceCanvas driven by a per-workspace config (track list, toolbar
flags, playhead) so the workspace selector visibly reshapes the app:

- ApplicationHeader (File/Edit/…/Help), ProjectToolbar with centered
  Audio setup/Share audio/Get effects (GhostButton) and right-side
  Workspace dropdown + undo/redo
- Transport row composed from Toolbar primitives: transport group,
  envelope/multi-clip/wave tools, 5-button zoom, conditional
  trim/silence, beats:bars TimeCode, NumberStepper BPM, time-signature
  Dropdown, Snap Checkbox + Bar Dropdown, mic + MasterMeter, gear in
  rightContent
- TrackControlSidePanel (carrying the "+ Add new" button) on the left,
  TimelineRuler + TrackNew rows on the right, PlayheadCursor overlay
- SelectionToolbar status bar at the bottom
- Stage clipped to top 25% (aspect-[64/9]) so the chrome differences
  per workspace are what reads on the marketing page
- Fade transition on tab switch (180ms) so the swap isn't jarring

Also bumps the design system to 0.2.3 (Track DPR fix, AGENTS.md
playbook bundled, workspace primitives polished).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 16:07:54 +10:00
Mudskipper
bc3ede2aaa fix(about): bundle gsap for SSR so Node 18 doesn't choke on its ESM entry
Netlify's Node 18 SSR pipeline loads gsap/index.js as CJS but the file
uses ESM imports, throwing SyntaxError during static route generation
for /about. Adding gsap to vite.ssr.noExternal makes Vite bundle it
during SSR and handle the interop, instead of leaving resolution to
Node.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 14:11:35 +10:00
Mudskipper
5031627af9 fix(about): drop unused gsap ScrollTrigger import in Hero
The named import from "gsap/ScrollTrigger" trips Node 18's stricter
CommonJS interop on Netlify ("Named export 'ScrollTrigger' not found")
and the plugin is never referenced — Hero only uses gsap.timeline /
gsap.to / gsap.fromTo, no scroll-bound animations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 14:07:58 +10:00
Mudskipper
c240e69142 feat(about): scaffold /about page with hero, editing, tools, workspaces
Adds a new /about page introducing Audacity 4. Sections so far:
- Hero with GSAP-animated product video and entrance for title + CTA
- Editing experience: 2x2 card grid; Multiselect card renders a live
  Track canvas with three clips cycling through a selection animation,
  remaining three use single Clip showcases
- Tool improvements: sticky stage with selectable tool list on the left
- Workspaces: tab-style picker with preview stage (placeholders)

Wires /about into the main nav (replaces FAQ/Plugins/Blog/Forum), bumps
@dilsonspickles/components to 0.2.1 (Track DPR fix), and adds Vite
React dedupe + design-system SSR config so hooks resolve to a single
React instance across the app and the design system.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 13:59:57 +10:00
Mudskipper
2605ee6609 merge: bring nav redesign into release/audacity-4
# Conflicts:
#	src/components/navigation/NavigationReact.jsx
2026-06-02 12:04:12 +10:00
Mudskipper
7af99f07ce feat(nav): update to dark navbar, new logo, restructured links
- Swap AudacityIconSVG to the 2025 logo (paths drop hardcoded fills so
  the existing fill-accent class on consumers continues to recolor it).
- Move the navbar onto the dark background, left-align logo + links,
  drop the "by muse group" subtext.
- Update link list to: Downloads, Features, FAQ, Plugins, Blog, Help,
  Forum (drops Merch, adds Plugins + Blog, reorders Features).
- "Audacity Cloud saving" -> "Try Audacity Cloud" (same /cloud-saving
  destination).
- SignUpButton becomes a 36px outlined pill (white border, transparent
  fill, inverts on hover).
- Keeps the 56px nav height.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 12:00:54 +10:00
Mudskipper
a0a48bee6c merge: bring new-branding into release/audacity-4
# Conflicts:
#	package-lock.json
#	src/components/button/DownloadButton.jsx
#	src/components/button/DownloadMuseHubButton.jsx
#	src/components/card/FeatureCard.jsx
#	src/components/footer/Footer.astro
#	src/components/homepage/Audiodotcom.astro
#	src/components/homepage/FeatureCards.astro
#	src/components/homepage/HeroBanner.astro
#	src/components/homepage/ReleaseVideo.astro
#	src/components/navigation/NavigationReact.jsx
#	src/pages/download.astro
#	src/styles/input.css
#	tailwind.config.cjs
2026-06-02 10:49:10 +10:00
Mudskipper
b79ef3c8b4 merge: bring help-hub work into release/audacity-4 2026-06-02 10:29:32 +10:00
Mudskipper
5f0ab75c21 feat: add /help, /learn, /tutorials hub pages and rewire nav
Splits navigation around three new top-level routes:

- /help — hub linking to guides, the manual, FAQ, and community channels.
- /learn — eight-step Getting Started path for new users.
- /tutorials — six-category How-to hub (Recording, Editing, Effects,
  Mixing & mastering, Exporting, Converting). Category sub-routes are
  placeholders awaiting content.

Top nav drops FAQ (now reachable from /help) and replaces the external
"Help" link to support.audacityteam.org with an internal /help link.
Footer's "Help" link now points at /help; the legacy
manual.audacityteam.org "Manual" entry stays as /manual.

Also drops the per-section uppercase headers in the manual sidebar and
removes the H2/H3 that landed inside the parent-page child-card list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 10:26:09 +10:00
Teetow
332a0aabef feat: add delay, echo, paste, and copy feature pages 2026-06-02 00:20:01 +02:00
Teetow
51733f7037 feat: add compressor and speed changer feature pages 2026-06-01 20:10:43 +02:00
Mudskipper
2f4913ea5d feat(manual): wire toolbar demo buttons to their manual pages
Each TransportButton / ToolButton in the manual hub's toolbar demo now
navigates to its corresponding /manual/manual-index/toolbar/<slug>
stub page on click. Uses window.location for plain full-page nav since
the rest of the manual links work the same way.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 22:21:14 +10:00
Mudskipper
b6a127fbca Merge branch 'dilsons-pickles/design-system-package' into dilsons-pickles/manual
# Conflicts:
#	package.json
2026-06-01 21:52:09 +10:00
Mudskipper
f39263d27e chore: bump @dilsonspickles/components to 0.2.0 (optional providers)
The design system 0.2.0 makes ThemeProvider and AccessibilityProfileProvider
optional — components now fall back to sensible defaults when neither
provider is in the tree. Drops the wrapper ceremony from the smoke test
so it reflects the real consumption pattern: import, render, done.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 21:49:31 +10:00
Mudskipper
ffd2bc2ac3 feat(manual): scaffold 216 manual-index stubs and hierarchical sidebar
Stubs every page from the existing GitBook manual index under
src/content/manual/manual-index/, mirroring the URL paths so future
content migrations drop into the right files. Each page has frontmatter
(title, section, sectionOrder, order, draft) and a placeholder body.

Sections are derived from the top-level branch (Track Control Panel,
Timeline, Header, etc.), with sectionOrder 10..150 in steps of 10.

Sidebar now renders entries as a tree based on slug nesting:

- ManualSidebarTree.astro: recursive renderer with active/ancestor
  highlight and a chevron toggle next to parent nodes.
- ManualSidebar.astro: builds the tree by attaching each entry to the
  longest ancestor slug that exists in the set.
- The current page's ancestor chain is rendered pre-expanded; everything
  else is collapsed. A small inline script persists user toggles in
  localStorage so manual expansions survive navigation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:52:29 +10:00
Mudskipper
9d177d0cca chore: install @dilsonspickles/components and add smoke test
Wires up GitHub Packages auth via .npmrc + GITHUB_TOKEN env var and
installs @dilsonspickles/components@0.1.0. Adds a noindex smoke-test
page at /dev/design-system-smoke-test that renders a Toolbar with
TransportButton + ToolButton, wrapped in ThemeProvider and
AccessibilityProfileProvider.

Parked here pending @dilsonspickles/components 0.2.0 which should make
both providers optional so static consumers (marketing site, manual)
can use components without app-shell ceremony.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 18:53:20 +10:00
Mudskipper
b630811303 content(manual): convert new-in-audacity-4 pages to .mdx
Renames the three .md pages to .mdx so they can host the manual
components (Callout, Notes, BestPractices, etc.), plus minor edits to
the alpha-1 release notes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 18:25:05 +10:00
Teetow
dd77e1364d feat: add agent skills and ship-feature-pages workflow
- Cherry-pick workflow skills from chore/confluence-promo-workflow-cleanup:
  implement-landing-page, confluence-web-promo-workflow, local-site-testing
- Add ship-feature-pages skill: fetches Confluence SEO backlog, builds
  prioritized queue, drives implement-landing-page for each item
- Add CONFLUENCE_FEATURE_BACKLOG_URL and CONFLUENCE_URL to .env (gitignored)
2026-06-01 09:59:15 +02:00
Mudskipper
77d0fbe048 feat(manual): port real content + add docs container components
Brings real manual content over from the existing audacity-support
gitbook export (basics, audio-editing, new-in-audacity-4, special-uses)
and adds the components that pages reach for:

- Notes (blue header, notepad badge) — general-purpose "Notes" panel
- BestPractices (emerald header, tick badge) — recommended approaches
- Pitfalls (red header, X badge) — things to avoid
- TipsAndTricks (indigo header, lightbulb badge) — handy hints
- Tabs / Tab (per-OS or per-variant tabbed content with OS auto-select)
- Icon, Toolbar, TransportButton, ToolButton — ported from
  clip-envelope-prototype (theme + tab-group hook stripped) for the
  manual hub toolbar demo
- ManualPagination — prev/next nav at the bottom of each page
- Last-updated stamp driven by git log (falls back to mtime)
- Manual hub UI map points at the new Manual-UI.webp; "Home" link in
  the sidebar nav; hotspots reset for the new image

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 16:19:39 +10:00
Mudskipper
9e55d5d519 feat: add back-to-manual link in sidebar and float search results
- Sidebar shows a "← Back to manual" link on every sub-page (hidden on
  the hub itself).
- Search results render as an absolutely-positioned dropdown over the
  page content instead of pushing it down. Wider than the sidebar so the
  panel reads comfortably, with a max-height + scroll for long lists.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 22:28:28 +10:00
Mudskipper
99be106792 fix: revert search to Pagefind Default UI
The Component UI markup leaked the modal contents into the page (the
"duplicate" search bar) because the JS isn't taking over the
<pagefind-modal> reliably without more glue. Default UI is documented,
single-element, and works with a straightforward window.PagefindUI
init. Keeps it in the sidebar with light CSS overrides so it sits well
alongside the manual nav. A modal/launcher pattern can come back later
once we understand the Component UI hydration better.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 22:22:48 +10:00
Mudskipper
15516a1c02 fix: stop nesting pagefind elements inside pagefind-config
Pagefind's component-ui CSS sets pagefind-config { display: none }, which
hides not just the config element but everything nested inside it. The
trigger button and modal were inside the config element and therefore
invisible (and not picked up by the DOM inspector either). The config is
a sibling that carries settings, not a wrapper. Hoists trigger and modal
to siblings of the config element.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 22:19:53 +10:00
Mudskipper
5181134ae9 fix: inline display fallbacks for Pagefind custom elements
Without the Pagefind component-ui CSS loaded, the pagefind-* custom
elements default to display: inline (browser default for unknown
elements). This collapses the trigger button container to zero size,
making search appear "not there at all" even though the markup ships.
Adds an inline <style is:global> block that ensures block layout for the
trigger and config elements, and keeps the modal hidden until open.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 22:14:41 +10:00
Mudskipper
3b37f09095 feat: switch manual search to Pagefind Component UI with modal trigger
Replaces the inline Default UI with the modal-style Component UI Pagefind
recommends. Sidebar now hosts a "Search the manual…" trigger button
(with a / keyboard shortcut hint) that opens a full search modal with
input, summary, results, and keyboard hints. Search is now reachable
from every manual page, not just the hub.

- ManualSearch: rewritten to use pagefind-config + modal-trigger + modal
  composition. Adds "/" global shortcut to open the modal.
- ManualSidebar: includes ManualSearch at the top so it's always
  available alongside navigation.
- pages/manual/index.astro: dedicated search section dropped (now in
  sidebar).
- UIMap.jsx: JSDoc typedef so TS infers prop types correctly when used
  from .astro pages.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 22:04:26 +10:00
Mudskipper
c42d806a29 ci: pin Netlify build command and publish dir
Without this, a build command set in the Netlify dashboard can override
the one in package.json, which is why the pagefind step wasn't running
on the branch deploy. Source-controlling it here makes it
self-documenting and removes the silent failure mode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 21:50:33 +10:00
Mudskipper
3740a357d2 fix: use static script tag and DOM-ready init for Pagefind UI
Switches to the documented Pagefind pattern: static <script src> loaded
inline (via is:inline so Astro doesn't bundle it), DOMContentLoaded
init, and console.error surfaces any initialization failure visibly.
Drops the baseUrl option which was prefixing result paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 21:48:07 +10:00
Mudskipper
57bd1d499e fix: load Pagefind UI via script tag instead of dynamic import
pagefind-ui.js is a UMD bundle that sets window.PagefindUI, not an ES
module. The previous dynamic-import + destructure approach got an empty
namespace, threw on new PagefindUI(), and silently fell back. Switching
to a <script src> with onload handler picks up the global correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 21:44:15 +10:00
Mudskipper
b5d511b69c feat: scaffold Audacity manual at /manual with MDX and Pagefind search
Adds a "manual" content collection, dynamic routes, sidebar navigation,
and a hub landing page combining Pagefind search with an interactive UI
map for visual drill-down. Wires up MDX so manual pages can embed
interactive components (AudacityButton, Shortcut, Callout, UIMap) inline.
Pagefind runs as a postbuild step (`pagefind --site dist`) and scopes
indexing to the manual via data-pagefind-body.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 21:12:40 +10:00
Teetow
3520b39286 Merge: dependency security hygiene (38 -> 6 advisories) 2026-05-27 22:59:27 +02:00
Teetow
be78a5fd73 chore(deps): cut security advisories 38 -> 6
Non-breaking dependency hygiene on a static site (all flagged packages are
build/dev-time tooling):

- bun update for in-range bumps (astro 5.17 -> 5.18, @astrojs/check, sitemap,
  prettier, lint-staged, etc.).
- overrides pinning patched, same-major versions of transitive deps:
  defu, devalue, fast-uri, h3, mdast-util-to-hast, postcss, rollup, smol-toml,
  svgo, tar, undici, vite, yaml.

Clears every high-severity advisory that had a clean in-major fix. Verified
with astro build, the unit suite, and the Playwright E2E suite (all green).

Remaining 6 are non-exploitable here and need the Astro 6 / Tailwind 4 major
migration (deferred): picomatch (build-time glob ReDoS, trusted patterns) and
two Astro advisories that don't apply (define:vars uses static config; no
server islands; static output).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 22:59:23 +02:00
Teetow
973136ec27 Merge: Confluence campaign promos + critical-path E2E suite
Make the Confluence promo calendar the single source of truth for partner
campaign promos (bun run pull-campaigns -> campaigns.ts), keep site-owned
promos in firstParty.ts, and add a lean Playwright E2E suite covering the
front page, downloads, and the promo banner date-window logic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 19:01:16 +02:00
Teetow
7ac0c48493 test: add lean critical-path E2E suite (Playwright)
Cover the three flows that must never silently break:

- front page: hero + real Windows installer link, release video, nav.
- downloads: /download OS targets, and real Windows/macOS installer links on
  the per-OS pages.
- promo banner: fake the browser clock to prove the date-window logic holds —
  an active campaign banner renders inside its window and disappears the day
  after it ends. Data-driven from campaigns.ts so it survives future pulls.

Setup: playwright.config.ts runs against `bun run dev`; `bun test` is scoped to
src/scripts so it ignores the .spec.ts files; e2e artifacts gitignored (and the
stale tracked test-results/ untracked).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 18:56:39 +02:00
Teetow
44c93868cc feat: pull campaign promos from Confluence
Make the Confluence "Promo Calendar" page the single source of truth for
MuseHub partner campaign promos, and reshape the promo data layer around a
clear superset/subset split:

- promos (umbrella) = campaigns (Confluence-sourced, time-boxed) + first-party
  (hand-authored, evergreen).
- `bun run pull-campaigns` (scripts/pull-campaigns.ts) fetches the page,
  deterministically extracts the calendar table (URLs preserved verbatim),
  resolves year-less date ranges, keeps only active/upcoming promos, maps them
  to typed PromoData, validates every emitted URL traces back to source, and
  writes src/assets/data/promos/campaigns.ts. Opt-in --clean-copy runs an LLM
  pass that may only tidy copy text. Never commits or pushes.
- Site-owned promos (audio.com exit popup, Audacity 4 alpha/video, survey) move
  to src/assets/data/promos/firstParty.ts.
- Delete legacy banners.ts / videos.ts / popups.ts; promotions.ts now merges
  firstParty + campaign promos only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 17:24:03 +02:00
Teetow
67dd7efba6 fix: disable musehub-badge experiment 2026-05-26 08:07:24 +02:00
Teetow
00800b2e97 fix: update survey link in redirects 2026-05-25 16:08:28 +02:00
DilsonsPickles
99059cca6f Merge pull request #78 from audacity/au4-beta-page
copy: tighten deprecated features copy
2026-05-20 17:32:35 +10:00
Mudskipper
a9752d0efa copy: clarify plugin format platform support
AudioUnits are macOS-only; Nyquist and VST3 are the cross-platform formats.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 17:31:46 +10:00
Mudskipper
1407a88393 copy: tighten deprecated features copy
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 17:27:26 +10:00
DilsonsPickles
2b8ab375ca Merge pull request #77 from audacity/au4-beta-page
Audacity 4 beta page at /next. Chocks away!
2026-05-20 16:10:48 +10:00
Mudskipper
3a0d310582 chore: remove duplicate beta screenshots from public
These now live in src/assets/img/beta and ship via astro:assets, so the
copies in public/ are unused.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 14:45:23 +10:00
Mudskipper
1b9c8cc13c refactor: use astro:assets Image for beta page screenshots
Moves the five beta screenshots into src/assets/img/beta and renders
them with Astro's Image component so they get optimized output, baked
dimensions, and async decoding instead of plain <img> from /public.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 14:44:25 +10:00
Mudskipper
61c0c27446 chore: remove unused lead-in screenshot
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 14:36:16 +10:00
Mudskipper
6206c9697c feat: refresh Audacity 4 beta page with real imagery and copy
Adds webp screenshots for the four hero feature cards (envelope, label
tracks, spectral editing, cloud projects) and the page hero. Drops the
old placeholder png. Reworks the secondary feature list with new icons
and copy, restructures sections, and adds the "How we're building
Audacity 4" video under "While you wait".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 14:35:22 +10:00
Teetow
c36ccd7261 feat: remove experiment tracking from MuseHub download button 2026-05-19 19:04:37 +02:00
Teetow
a3346c51ed feat: implement binary download tracking for download buttons and update event tracking 2026-05-19 18:11:06 +02:00
Mudskipper
edac41483a feat: draft Audacity 4 beta page at /next
Activates the beta pre-release entry with no binaries yet so /next shows a
"coming soon" page. Rewrites BetaDetails with new copy, hero image, and
sections for what's new, what's not coming over, and a while-you-wait link
to the Alpha 2 release.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 22:30:35 +10:00
Teetow
94b5aad28f feat: enhance download buttons with OS-specific links and experiment variants 2026-05-19 12:38:11 +02:00
Teetow
0c77697379 feat: add musehub-badge A/B/C experiment
Test two MuseHub badge designs against the existing yellow CTA. Linux
stays on the control button since MuseHub doesn't ship on Linux. Adds
?ab= query-string override to force a variant for QA.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 07:24:52 +02:00