-
+
+ Est. 2016
- {versionTag} Available Now
-
-
Nuclear is a
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/website/src/components/Typewriter.tsx b/packages/website/src/components/Typewriter.tsx
index c5775c48cf..e457bfe8b1 100644
--- a/packages/website/src/components/Typewriter.tsx
+++ b/packages/website/src/components/Typewriter.tsx
@@ -6,19 +6,33 @@ const TYPE_SPEED = 70;
const DELETE_SPEED = 40;
const PAUSE_AFTER_TYPE = 2000;
const PAUSE_AFTER_DELETE = 400;
+const INITIAL_TEXT = "that's free and open-source";
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
export const Typewriter = () => {
- const [text, setText] = useState('');
+ const [text, setText] = useState(INITIAL_TEXT);
useEffect(() => {
let cancelled = false;
const loop = async () => {
- let index = 0;
+ await sleep(PAUSE_AFTER_TYPE);
+ for (let i = INITIAL_TEXT.length; i >= 0 && !cancelled; i--) {
+ setText(INITIAL_TEXT.slice(0, i));
+ await sleep(DELETE_SPEED);
+ }
+ await sleep(PAUSE_AFTER_DELETE);
+
+ let lastIndex = -1;
while (!cancelled) {
- const phrase = taglines[index % taglines.length];
+ let nextIndex: number;
+ do {
+ nextIndex = Math.floor(Math.random() * taglines.length);
+ } while (nextIndex === lastIndex && taglines.length > 1);
+ lastIndex = nextIndex;
+
+ const phrase = taglines[nextIndex];
for (let i = 0; i <= phrase.length && !cancelled; i++) {
setText(phrase.slice(0, i));
@@ -31,8 +45,6 @@ export const Typewriter = () => {
await sleep(DELETE_SPEED);
}
await sleep(PAUSE_AFTER_DELETE);
-
- index++;
}
};
diff --git a/packages/website/src/data/taglines.ts b/packages/website/src/data/taglines.ts
index ef0ea23623..7e889ddb1f 100644
--- a/packages/website/src/data/taglines.ts
+++ b/packages/website/src/data/taglines.ts
@@ -5,5 +5,11 @@ export const taglines = [
'for Linux',
'for Mac',
'for Windows',
- "that's free as in freedom",
+ "that's free and open source",
+ 'for AI agents',
+ 'with a built-in MCP',
+ 'for music discovery',
+ 'with themes',
+ 'with a ton of plugins',
+ 'with a built-in log viewer',
];
diff --git a/packages/website/src/data/version.ts b/packages/website/src/data/version.ts
index 22b47589bb..f0fc53cced 100644
--- a/packages/website/src/data/version.ts
+++ b/packages/website/src/data/version.ts
@@ -1,4 +1,4 @@
-export const version = '1.33.0';
+export const version = '1.35.0';
export const versionTag = `v${version}`;
export const releaseTag = `player@${version}`;
export const releaseUrl = (filename: string) =>
diff --git a/packages/website/src/layouts/BaseLayout.astro b/packages/website/src/layouts/BaseLayout.astro
index 83714be129..40f0e443e5 100644
--- a/packages/website/src/layouts/BaseLayout.astro
+++ b/packages/website/src/layouts/BaseLayout.astro
@@ -10,28 +10,64 @@ type Props = {
const { title, description } = Astro.props;
const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
const ogImageUrl = new URL('/images/social-banner.png', Astro.site);
+const siteUrl = Astro.site?.toString() ?? 'https://nuclearplayer.com/';
+const logoUrl = new URL('/images/logo-full-outlined.svg', Astro.site).toString();
+
+const organizationId = `${siteUrl}#organization`;
+const websiteId = `${siteUrl}#website`;
+const softwareId = `${siteUrl}#software`;
const jsonLd = {
'@context': 'https://schema.org',
- '@type': 'SoftwareApplication',
- name: 'Nuclear',
- description,
- url: Astro.site?.toString(),
- applicationCategory: 'MultimediaApplication',
- operatingSystem: 'Windows, macOS, Linux',
- offers: {
- '@type': 'Offer',
- price: '0',
- priceCurrency: 'USD',
- },
- license: 'https://www.gnu.org/licenses/agpl-3.0.html',
- image: ogImageUrl.toString(),
- screenshot: new URL('/images/social-banner.png', Astro.site).toString(),
+ '@graph': [
+ {
+ '@type': 'Organization',
+ '@id': organizationId,
+ name: 'Nuclear',
+ url: siteUrl,
+ logo: logoUrl,
+ sameAs: [
+ 'https://github.com/nukeop/nuclear',
+ 'https://fosstodon.org/@nuclearplayer',
+ 'https://twitter.com/nuclear_player',
+ 'https://discord.gg/JqPjKxE',
+ ],
+ },
+ {
+ '@type': 'WebSite',
+ '@id': websiteId,
+ url: siteUrl,
+ name: 'Nuclear Music Player',
+ description,
+ publisher: { '@id': organizationId },
+ inLanguage: 'en',
+ },
+ {
+ '@type': 'SoftwareApplication',
+ '@id': softwareId,
+ name: 'Nuclear',
+ description,
+ url: siteUrl,
+ applicationCategory: 'MultimediaApplication',
+ operatingSystem: 'Windows, macOS, Linux',
+ offers: {
+ '@type': 'Offer',
+ price: '0',
+ priceCurrency: 'USD',
+ },
+ license: 'https://www.gnu.org/licenses/agpl-3.0.html',
+ downloadUrl: 'https://github.com/nukeop/nuclear/releases',
+ image: ogImageUrl.toString(),
+ screenshot: ogImageUrl.toString(),
+ author: { '@id': organizationId },
+ publisher: { '@id': organizationId },
+ },
+ ],
};
---
-
+
@@ -41,8 +77,16 @@ const jsonLd = {
-
-
+
+
@@ -64,14 +108,7 @@ const jsonLd = {
-
-
-
-
-
+
diff --git a/packages/website/src/pages/index.astro b/packages/website/src/pages/index.astro
index 6abff0791c..43de73cb70 100644
--- a/packages/website/src/pages/index.astro
+++ b/packages/website/src/pages/index.astro
@@ -1,7 +1,8 @@
---
-import Downloads from '../components/Downloads.astro';
+import FAQ from '../components/FAQ.astro';
+import Features from '../components/Features.astro';
import Hero from '../components/Hero.astro';
-import Screenshots from '../components/Screenshots.astro';
+import { McpShowcase } from '../components/McpShowcase';
import Testimonials from '../components/Testimonials.astro';
import BaseLayout from '../layouts/BaseLayout.astro';
@@ -13,24 +14,30 @@ const description =
---
-
-
+
+
-
+
+
+
diff --git a/packages/website/src/styles/global.css b/packages/website/src/styles/global.css
index f3991ca801..685931185f 100644
--- a/packages/website/src/styles/global.css
+++ b/packages/website/src/styles/global.css
@@ -1,15 +1,16 @@
+@import '@fontsource-variable/dm-sans';
+@import '@fontsource-variable/dm-sans/wght-italic.css';
+@import '@fontsource-variable/bricolage-grotesque';
@import '@nuclearplayer/tailwind-config';
@source '../components';
@source '../layouts';
@source '../pages';
-@custom-variant prefers-dark (@media (prefers-color-scheme: dark));
-
:root {
--page-bg: oklch(100% 0 0);
- --background: oklch(100% 0 0);
+ --primary: oklch(0.8 0.12 4.56);
+ --background: oklch(0.9163 0.0361 7.16);
--background-secondary: oklch(100% 0 0);
- --color-badge: oklch(0.9135 0.0475 1.69);
--color-heading-accent: var(--primary);
--color-heading-shadow: var(--foreground);
--color-star: var(--foreground);
@@ -18,48 +19,6 @@
--border-width: 2px;
}
-@media (prefers-color-scheme: dark) {
- .dark-mode-hidden {
- display: none;
- }
- .dark-mode-block {
- display: block;
- }
-
- :root {
- --page-bg: oklch(0.22 0.03 5);
- --background: oklch(0.22 0.03 5);
- --background-secondary: oklch(0.27 0.035 5);
- --background-input: oklch(0.15 0.02 5);
- --foreground: oklch(0.9 0.008 5);
- --foreground-secondary: oklch(0.78 0.1 5);
- --foreground-input: oklch(0.93 0 0);
- --primary: oklch(0.5 0.1 5);
- --border: oklch(0.48 0.04 5);
- --shadow-x: 0px;
- --shadow-y: 0px;
- --color-badge: oklch(0.35 0.1 5);
- --color-heading-accent: oklch(0.5 0.1 5);
- --color-heading-shadow: none;
- --color-star: oklch(0.9553 0.134 112.76);
- --color-star-bg: oklch(0.27 0.035 5);
- --color-discord: oklch(0.45 0.13 273.85);
- --border-width: 1px;
- }
-
- .bg-grid-pattern {
- opacity: 0.06;
- }
-
- .btn-interactive:hover {
- filter: brightness(1.3);
- }
-
- .btn-interactive:active {
- filter: brightness(0.9);
- }
-}
-
.themed-border {
border-width: var(--border-width);
border-style: solid;
@@ -92,6 +51,7 @@
from {
transform: translateX(0);
}
+
to {
transform: translateX(-50%);
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4afa5d108c..4e24d9edb5 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -32,9 +32,12 @@ importers:
lint-staged:
specifier: ^16.1.4
version: 16.4.0
+ prettier-plugin-astro:
+ specifier: ^0.14.1
+ version: 0.14.1
prettier-plugin-tailwindcss:
specifier: ^0.8.0
- version: 0.8.0(@ianvs/prettier-plugin-sort-imports@4.7.1(prettier@3.8.3))(prettier@3.8.3)
+ version: 0.8.0(@ianvs/prettier-plugin-sort-imports@4.7.1(prettier@3.8.3))(prettier-plugin-astro@0.14.1)(prettier@3.8.3)
tailwindcss:
specifier: ^4.1.11
version: 4.2.4
@@ -106,7 +109,7 @@ importers:
version: 2.6.1
prettier-plugin-tailwindcss:
specifier: ^0.8.0
- version: 0.8.0(@ianvs/prettier-plugin-sort-imports@4.7.1(prettier@3.8.3))(prettier@3.8.3)
+ version: 0.8.0(@ianvs/prettier-plugin-sort-imports@4.7.1(prettier@3.8.3))(prettier-plugin-astro@0.14.1)(prettier@3.8.3)
tailwind-csstree:
specifier: ^0.3.0
version: 0.3.1(@eslint/css@1.1.0)
@@ -794,18 +797,27 @@ importers:
'@astrojs/sitemap':
specifier: ^3.7.0
version: 3.7.2
+ '@fontsource-variable/bricolage-grotesque':
+ specifier: ^5.2.10
+ version: 5.2.10
+ '@fontsource-variable/dm-sans':
+ specifier: ^5.2.8
+ version: 5.2.8
'@iconify-json/simple-icons':
specifier: ^1.2.67
version: 1.2.80
- '@lucide/astro':
- specifier: ^0.563.0
- version: 0.563.0(astro@6.2.1(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))
astro:
specifier: ^6.0.0
version: 6.2.1(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)
astro-icon:
specifier: ^1.1.5
version: 1.1.5
+ clsx:
+ specifier: ^2.1.1
+ version: 2.1.1
+ lucide-react:
+ specifier: ^0.542.0
+ version: 0.542.0(react@18.3.1)
react:
specifier: ^18.3.1
version: 18.3.1
@@ -815,7 +827,7 @@ importers:
devDependencies:
'@astrojs/check':
specifier: ^0.9.6
- version: 0.9.9(prettier@3.8.3)(typescript@5.9.3)
+ version: 0.9.9(prettier-plugin-astro@0.14.1)(prettier@3.8.3)(typescript@5.9.3)
'@nuclearplayer/eslint-config':
specifier: workspace:*
version: link:../eslint-config
@@ -1375,6 +1387,12 @@ packages:
'@floating-ui/utils@0.2.11':
resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==}
+ '@fontsource-variable/bricolage-grotesque@5.2.10':
+ resolution: {integrity: sha512-5EDsCqgGpKVcJWE4sg9ydli+t5WM97mISYw5lla/Ev4z71FwXh1oN0YUU8xjkRW9+wBCGD9R+ntAvI8G4bUFJg==}
+
+ '@fontsource-variable/dm-sans@5.2.8':
+ resolution: {integrity: sha512-AxkvMTvNWgfrmlyjiV05vlHYJa+nRQCf1EfvIrQAPBpFJW0O9VTz7oAFr9S3lvbWdmnFoBk7yFqQL86u64nl2g==}
+
'@fontsource/bricolage-grotesque@5.2.10':
resolution: {integrity: sha512-V2xS+1P7C8IrSypXLUx/bLtX/LsTlYtV2k2CsU+S/0t8qepZ2hvKSlyJIx7Ub/iY8Bbnj+IjAuUF9nvFz+BbIg==}
@@ -1620,11 +1638,6 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
- '@lucide/astro@0.563.0':
- resolution: {integrity: sha512-X9fNJvRR6pLJfkIEAFQkizWaNVvcduunJoFyR3fwPu30Y6jOu5S9k4k7HTSk3ZrEfqK2eFEqrBqqWH4fwSNKCg==}
- peerDependencies:
- astro: ^4 || ^5
-
'@mdx-js/react@3.1.1':
resolution: {integrity: sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==}
peerDependencies:
@@ -4946,6 +4959,10 @@ packages:
resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==}
engines: {node: '>=6.0.0'}
+ prettier-plugin-astro@0.14.1:
+ resolution: {integrity: sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==}
+ engines: {node: ^14.15.0 || >=16.0.0}
+
prettier-plugin-tailwindcss@0.8.0:
resolution: {integrity: sha512-V8ITGH87yuBDF6JpEZTOVlUz/saAwqb8f3HRgUj8Lh+tGCcrmorhsLpYqzygwFwK0PE2Ib6Mv3M7T/uE2tZV1g==}
engines: {node: '>=20.19'}
@@ -5269,6 +5286,9 @@ packages:
resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==}
engines: {node: '>=18'}
+ s.color@0.0.15:
+ resolution: {integrity: sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA==}
+
safe-array-concat@1.1.3:
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
engines: {node: '>=0.4'}
@@ -5284,6 +5304,9 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ sass-formatter@0.7.9:
+ resolution: {integrity: sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==}
+
sax@1.6.0:
resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==}
engines: {node: '>=11.0.0'}
@@ -5512,6 +5535,9 @@ packages:
resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==}
engines: {node: '>=12'}
+ suf-log@2.5.3:
+ resolution: {integrity: sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==}
+
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
@@ -6325,9 +6351,9 @@ snapshots:
'@csstools/css-tokenizer': 3.0.4
lru-cache: 10.4.3
- '@astrojs/check@0.9.9(prettier@3.8.3)(typescript@5.9.3)':
+ '@astrojs/check@0.9.9(prettier-plugin-astro@0.14.1)(prettier@3.8.3)(typescript@5.9.3)':
dependencies:
- '@astrojs/language-server': 2.16.7(prettier@3.8.3)(typescript@5.9.3)
+ '@astrojs/language-server': 2.16.7(prettier-plugin-astro@0.14.1)(prettier@3.8.3)(typescript@5.9.3)
chokidar: 4.0.3
kleur: 4.1.5
typescript: 5.9.3
@@ -6344,7 +6370,7 @@ snapshots:
dependencies:
picomatch: 4.0.4
- '@astrojs/language-server@2.16.7(prettier@3.8.3)(typescript@5.9.3)':
+ '@astrojs/language-server@2.16.7(prettier-plugin-astro@0.14.1)(prettier@3.8.3)(typescript@5.9.3)':
dependencies:
'@astrojs/compiler': 2.13.1
'@astrojs/yaml2ts': 0.2.3
@@ -6366,6 +6392,7 @@ snapshots:
vscode-uri: 3.1.0
optionalDependencies:
prettier: 3.8.3
+ prettier-plugin-astro: 0.14.1
transitivePeerDependencies:
- typescript
@@ -6864,6 +6891,10 @@ snapshots:
'@floating-ui/utils@0.2.11': {}
+ '@fontsource-variable/bricolage-grotesque@5.2.10': {}
+
+ '@fontsource-variable/dm-sans@5.2.8': {}
+
'@fontsource/bricolage-grotesque@5.2.10': {}
'@fontsource/dm-sans@5.2.8': {}
@@ -7081,10 +7112,6 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
- '@lucide/astro@0.563.0(astro@6.2.1(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3))':
- dependencies:
- astro: 6.2.1(@types/node@25.6.0)(jiti@2.6.1)(lightningcss@1.32.0)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)
-
'@mdx-js/react@3.1.1(@types/react@18.3.28)(react@18.3.1)':
dependencies:
'@types/mdx': 2.0.13
@@ -10984,11 +11011,18 @@ snapshots:
dependencies:
fast-diff: 1.3.0
- prettier-plugin-tailwindcss@0.8.0(@ianvs/prettier-plugin-sort-imports@4.7.1(prettier@3.8.3))(prettier@3.8.3):
+ prettier-plugin-astro@0.14.1:
+ dependencies:
+ '@astrojs/compiler': 2.13.1
+ prettier: 3.8.3
+ sass-formatter: 0.7.9
+
+ prettier-plugin-tailwindcss@0.8.0(@ianvs/prettier-plugin-sort-imports@4.7.1(prettier@3.8.3))(prettier-plugin-astro@0.14.1)(prettier@3.8.3):
dependencies:
prettier: 3.8.3
optionalDependencies:
'@ianvs/prettier-plugin-sort-imports': 4.7.1(prettier@3.8.3)
+ prettier-plugin-astro: 0.14.1
prettier@3.8.3: {}
@@ -11345,6 +11379,8 @@ snapshots:
run-applescript@7.1.0: {}
+ s.color@0.0.15: {}
+
safe-array-concat@1.1.3:
dependencies:
call-bind: 1.0.8
@@ -11366,6 +11402,10 @@ snapshots:
safer-buffer@2.1.2: {}
+ sass-formatter@0.7.9:
+ dependencies:
+ suf-log: 2.5.3
+
sax@1.6.0: {}
saxes@6.0.0:
@@ -11688,6 +11728,10 @@ snapshots:
strip-indent@4.1.1: {}
+ suf-log@2.5.3:
+ dependencies:
+ s.color: 0.0.15
+
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
diff --git a/prettier.config.js b/prettier.config.js
index 54d92d4e41..128833634f 100644
--- a/prettier.config.js
+++ b/prettier.config.js
@@ -18,7 +18,16 @@ export default {
importOrderParserPlugins: ['typescript', 'jsx'],
plugins: [
'@ianvs/prettier-plugin-sort-imports',
+ 'prettier-plugin-astro',
'prettier-plugin-tailwindcss',
],
+ overrides: [
+ {
+ files: '*.astro',
+ options: {
+ parser: 'astro',
+ },
+ },
+ ],
tailwindFunctions: ['clsx', 'cn', 'cva'],
};