-
Everything within reach.
-
-
Focused playback Seek, skip, loop, change speed, and save frames.
-
Floating mini-player Keep the video visible while you work.
-
Audio & subtitles Choose tracks or load subtitles.
-
Desktop integration Open files from your desktop and set LinuxPlayer as default.
-
Responsive feedback Subtle cues confirm every action.
-
Personal controls Shortcuts, canvas ratios, and your system accent.
-
+
+
The viewing experience
Only the video,when you want it.
+
+
01 Controls on demand. They disappear as playback begins.
02 Stay in the picture. Lock the interface to show only video.
03 Every action feels clear. Subtle feedback for play, pause, and seeking.
-
Watch while you work.
-
Files
Project notes Media Downloads
+
Mini-player Your video comes along. Keep watching in a compact window while you work.
+
Files
Project notes Media Downloads
-
Preview any shape.
-
+
Canvas preview One video.Every frame. Try a new canvas ratio without changing the file.
+
Source video 16:9 · unchanged
Canvas ratio 16:9 9:16 1:1 4:5 2:1
-
Preview only. Your video stays untouched. Feature guide
+
Your video stays untouched. Feature guide
-
See the player. Playback Controls Video only Mini-player
+
A closer look
See it in action. Playback Controls Video only Mini-player
Install LinuxPlayer. 64-bit x86 .deb package
Terminal install Copy command
curl -fsSLo /tmp/linuxplayer-install.sh \
https://github.com/teamkrope/linuxplayer/releases/latest/download/install.sh
bash /tmp/linuxplayer-install.sh
diff --git a/web/motion.js b/web/motion.js
index 4a65dd8..67dfbc8 100644
--- a/web/motion.js
+++ b/web/motion.js
@@ -8,11 +8,10 @@
if (!('IntersectionObserver' in window) || window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
const targets = document.querySelectorAll([
- 'main .hero-copy', 'main .hero-shot', 'main .section-head',
- 'main .feature-shot', 'main .feature-list article',
- 'main .pip-copy', 'main .workspace-figure', 'main .ratio-demo',
- 'main .gallery', 'main .download-grid > *', 'main .source-grid > *',
- 'main .faq-grid > *', 'main .package-card', 'main .download-help-grid > *'
+ 'main [data-reveal]', 'main .packages-section .section-head',
+ 'main .download-grid > *', 'main .source-grid > *',
+ 'main .faq-grid > *', 'main .package-card',
+ 'main .download-help-grid > *'
].join(', '));
targets.forEach(target => {
@@ -21,7 +20,7 @@
if (target.getBoundingClientRect().top < window.innerHeight * 0.94) {
target.classList.add('is-visible');
}
- if (target.matches('.feature-list article')) {
+ if (target.matches('.focus-points article')) {
const index = [...target.parentElement.children].indexOf(target);
target.style.setProperty('--reveal-delay', `${Math.min(index, 5) * 55}ms`);
}
@@ -36,4 +35,25 @@
});
}, { threshold: 0.08, rootMargin: '0px 0px -6% 0px' });
targets.forEach(target => observer.observe(target));
+
+ const scenes = [...document.querySelectorAll('[data-scroll-scene]')];
+ if (!scenes.length) return;
+ let scheduled = false;
+ const updateScenes = () => {
+ const viewport = window.innerHeight;
+ scenes.forEach(scene => {
+ const rect = scene.getBoundingClientRect();
+ const progress = Math.max(0, Math.min(1, (viewport - rect.top) / (viewport + rect.height)));
+ scene.style.setProperty('--scene-shift', `${(-18 * progress).toFixed(1)}px`);
+ });
+ scheduled = false;
+ };
+ const scheduleScenes = () => {
+ if (scheduled) return;
+ scheduled = true;
+ requestAnimationFrame(updateScenes);
+ };
+ window.addEventListener('scroll', scheduleScenes, { passive: true });
+ window.addEventListener('resize', scheduleScenes);
+ scheduleScenes();
})();
diff --git a/web/scripts/build.mjs b/web/scripts/build.mjs
index 0de8228..4ed85a6 100644
--- a/web/scripts/build.mjs
+++ b/web/scripts/build.mjs
@@ -19,6 +19,7 @@ await rm(output, { recursive: true, force: true });
await mkdir(output, { recursive: true });
await cp(path.join(root, 'assets'), path.join(output, 'assets'), { recursive: true });
await cp(path.join(root, 'styles.css'), path.join(output, 'styles.css'));
+await cp(path.join(root, 'showcase.css'), path.join(output, 'showcase.css'));
await cp(path.join(root, 'script.js'), path.join(output, 'script.js'));
await cp(path.join(root, 'motion.js'), path.join(output, 'motion.js'));
await cp(path.join(root, 'download.js'), path.join(output, 'download.js'));
diff --git a/web/scripts/check.mjs b/web/scripts/check.mjs
index 082a677..d2cfed3 100644
--- a/web/scripts/check.mjs
+++ b/web/scripts/check.mjs
@@ -10,13 +10,15 @@ if ([html, download].some(page => page.includes('Download for Linux'))) throw ne
if (!html.includes('playback-v1-coast.png') || !script.includes('options-v1-coast.png')) throw new Error('Current screenshots are not linked from the site');
if (html.includes('Start screen') || script.includes('empty-v1-coast.png')) throw new Error('Removed gallery tab is still present');
if (![html, download].every(page => page.includes('motion.js') && page.includes('footer-line'))) throw new Error('Shared motion or compact footer missing');
+if (!html.includes('showcase.css') || !html.includes('class="hero-shot"') || !html.includes('data-scroll-scene')) throw new Error('Product showcase is missing');
+if (!(html.indexOf('class="hero-copy"') < html.indexOf('class="hero-shot"') && html.indexOf('class="hero-shot"') < html.indexOf('class="hero-actions"'))) throw new Error('Hero must show title, product image, then actions');
for (const text of ['LinuxPlayer', 'id="download"', 'id="features"', 'id="preview"', 'id="open-source"', 'application/ld+json', 'releases/latest/download/install.sh']) {
if (!html.includes(text)) throw new Error(`Missing required site content: ${text}`);
}
for (const asset of ['linuxplayer_amd64.deb', 'linuxplayer_arm64.deb']) {
if (!download.includes(`/releases/latest/download/${asset}`)) throw new Error(`Missing latest direct download: ${asset}`);
}
-for (const file of ['styles.css', 'motion.js', 'script.js', 'download.js', 'robots.txt', 'LICENSE', 'assets/linuxplayer-bird.png', 'assets/external-link.svg', 'assets/ratio-source.webp', 'assets/screenshots/playback-v1-coast.png', 'assets/screenshots/options-v1-coast.png', 'assets/screenshots/hidden-v1-coast.png', 'assets/screenshots/mini-player-v1-coast.png']) {
+for (const file of ['styles.css', 'showcase.css', 'motion.js', 'script.js', 'download.js', 'robots.txt', 'LICENSE', 'assets/linuxplayer-bird.png', 'assets/external-link.svg', 'assets/ratio-source.webp', 'assets/screenshots/playback-v1-coast.png', 'assets/screenshots/options-v1-coast.png', 'assets/screenshots/hidden-v1-coast.png', 'assets/screenshots/mini-player-v1-coast.png']) {
if (!(await stat(path.join(root, file))).isFile()) throw new Error(`Missing asset: ${file}`);
}
console.log('Site content and required assets verified.');
diff --git a/web/showcase.css b/web/showcase.css
new file mode 100644
index 0000000..285bd56
--- /dev/null
+++ b/web/showcase.css
@@ -0,0 +1,151 @@
+/* Homepage presentation. The shared styles and download page live in styles.css. */
+:root { --showcase-ease: cubic-bezier(.22, 1, .36, 1); }
+
+.site-header { background: rgba(8, 18, 27, .82); border-color: rgba(225, 248, 245, .1); }
+.nav-links a { color: #becbca; }
+.header-download { border-radius: 999px; padding-inline: 19px; }
+.section-kicker { display: block; color: var(--accent); font-size: 12px; font-weight: 750; letter-spacing: .16em; text-transform: uppercase; }
+.hero h1 em, .focus-intro h2 em, .canvas-head h2 em { font-style: normal; color: var(--accent); }
+
+.hero { position: relative; overflow: hidden; padding: 116px 0 126px; background: radial-gradient(ellipse 55% 35% at 50% 50%, rgba(62, 171, 160, .15), transparent 90%), #07131d; }
+.hero-inner { display: flex; flex-direction: column; align-items: center; gap: 0; }
+.hero-copy { padding: 0; text-align: center; max-width: 1050px; position: relative; z-index: 1; }
+.hero-copy h1 { font-size: clamp(62px, 8.1vw, 120px); line-height: .99; letter-spacing: -.078em; max-width: none; margin: 24px 0 24px; font-weight: 650; }
+.hero-copy p { max-width: none; color: #adc1c3; font-size: clamp(17px, 2vw, 21px); }
+.hero-shot { width: min(100%, 1160px); margin: 76px auto 0; position: relative; isolation: isolate; }
+.hero-shot::before { content: ""; position: absolute; inset: 12% 4% -8%; z-index: -1; border-radius: 45%; background: #48c6b2; filter: blur(95px); opacity: .17; }
+.hero .shot-frame { padding: 9px; border: 1px solid #547b7b; border-radius: 23px; background: #0e202c; box-shadow: 0 48px 100px #0009, 0 0 0 1px #ffffff0d inset; overflow: hidden; }
+.hero .shot-frame img { width: 100%; border-radius: 14px; transform: translateY(var(--scene-shift, 0px)) scale(1.025); will-change: transform; }
+.hero-actions { justify-content: center; margin: 46px 0 0; gap: 14px; }
+.hero-actions .button { min-height: 54px; padding: 15px 26px; border-radius: 999px; font-size: 14px; }
+.hero-actions .button-secondary { background: rgba(25, 49, 61, .7); border-color: #496a6b; }
+
+.section { padding-block: clamp(112px, 12vw, 190px); }
+.features-section { background: #0a1923; }
+.focus-layout { display: grid; justify-items: center; }
+.focus-intro { max-width: 920px; text-align: center; margin-bottom: 65px; }
+.focus-intro h2 { font-size: clamp(53px, 7.1vw, 104px); line-height: 1.03; letter-spacing: -.07em; margin: 23px 0 0; }
+.focus-visual { width: 100%; max-width: 1130px; overflow: hidden; position: relative; border: 1px solid #56716c; border-radius: 23px; box-shadow: 0 40px 95px #0008; background: #080f16; }
+.focus-visual img { width: 100%; transform: translateY(var(--scene-shift, 0px)) scale(1.035); will-change: transform; }
+.focus-points { display: grid; grid-template-columns: repeat(3, 1fr); gap: 42px; width: 100%; max-width: 1130px; margin-top: 66px; }
+.focus-points article { padding-top: 24px; border-top: 1px solid #4f6668; }
+.focus-points span { display: block; color: var(--accent); font-size: 11px; font-weight: 750; letter-spacing: .14em; margin-bottom: 19px; }
+.focus-points h3 { font-size: clamp(20px, 2vw, 26px); letter-spacing: -.035em; line-height: 1.2; margin-bottom: 9px; }
+.focus-points p { font-size: 14px; line-height: 1.55; }
+
+.pip-section { background: #10242e; border: 0; }
+.pip-grid { grid-template-columns: .7fr 1.3fr; gap: clamp(36px, 6vw, 95px); }
+.pip-copy h2 { font-size: clamp(55px, 6.4vw, 96px); line-height: 1.02; letter-spacing: -.068em; margin: 22px 0 25px; }
+.pip-copy p { font-size: 17px; line-height: 1.55; }
+.workspace-stage { height: 560px; border-radius: 24px; border-color: #5a7880; background: radial-gradient(circle at 70% 20%, #305467, #142b3b 48%, #0d1d2c); box-shadow: 0 36px 85px #0006; }
+.pip-capture { transform: translateY(var(--scene-shift, 0px)) rotate(-2deg); width: min(62%, 470px); border-radius: 8px; box-shadow: 0 28px 70px #000d; will-change: transform; }
+
+.canvas-section { background: #0b1721; }
+.canvas-head { text-align: center; max-width: 900px; margin: 0 auto 62px; }
+.canvas-head h2 { font-size: clamp(55px, 7vw, 100px); line-height: 1.02; margin: 22px 0 20px; }
+.canvas-head p { margin: auto; font-size: 17px; }
+.ratio-demo { border-radius: 23px; border-color: #527174; background: #122733; box-shadow: 0 30px 85px #0006; }
+.demo-source, .demo-preview { padding: 32px; }
+.source-frame, .ratio-stage { border-radius: 12px; border-color: #405c66; height: 390px; }
+.demo-controls { padding: 25px 32px; }
+.demo-note { text-align: center; margin-top: 25px; }
+
+.preview-section { background: #10222d; }
+.preview-section .section-head { max-width: none; text-align: center; margin-bottom: 57px; }
+.preview-section .section-head h2 { font-size: clamp(55px, 7vw, 100px); margin: 21px 0 0; }
+.gallery { border-radius: 23px; border-color: #506b70; box-shadow: 0 30px 85px #0007; }
+.gallery-tabs { background: #142b39; padding: 17px; gap: 8px; }
+.gallery-tabs button { padding: 10px 19px; border-radius: 999px; font-size: 13px; }
+.gallery-tabs button.active { background: var(--accent); color: #10201b; }
+.gallery-image-wrap { height: min(58vw, 655px); padding: 36px; background: #07131d; }
+.gallery-image-wrap img { border-radius: 9px; border-color: #465e63; box-shadow: 0 20px 65px #0008; }
+
+.download-section { background: radial-gradient(circle at 50% 10%, #2a5d61, #15343f 48%, #0f2631 100%); border-block-color: #4d7775; }
+.download-grid { display: flex; flex-direction: column; align-items: center; gap: 58px; }
+.download-grid > div:first-child { text-align: center; }
+.download-grid h2 { font-size: clamp(62px, 7.6vw, 108px); letter-spacing: -.07em; line-height: 1.02; margin-bottom: 22px; }
+.download-grid p { max-width: none; font-size: 16px; }
+.download-actions { justify-content: center; margin-top: 32px; }
+.download-actions .button { min-height: 52px; padding: 14px 25px; border-radius: 999px; }
+.download-grid .install-card { width: min(100%, 850px); background: rgba(7, 24, 34, .82); border-color: #6b9290; border-radius: 16px; box-shadow: 0 25px 60px #0004; }
+.download-grid .install-card pre { padding-block: 30px; }
+
+.source-section { background: #0b1923; }
+.source-grid { grid-template-columns: .9fr 1.1fr; gap: clamp(45px, 8vw, 140px); }
+.source-grid h2 { font-size: clamp(55px, 6.5vw, 95px); letter-spacing: -.067em; }
+.source-actions .button { border-radius: 999px; }
+.repo-links a { padding-block: 26px; }
+.faq-section { background: #0e202b; }
+.faq-grid { grid-template-columns: .8fr 1.2fr; }
+.faq-grid h2 { font-size: clamp(55px, 6vw, 86px); }
+
+.motion-ready [data-reveal] { opacity: 0; filter: blur(16px); transform: translate3d(0, 30px, 0); transition: opacity .8s var(--showcase-ease), filter 1s var(--showcase-ease), transform 1s var(--showcase-ease); transition-delay: var(--reveal-delay, 0ms); }
+.motion-ready [data-reveal="visual"] { transform: translate3d(0, 48px, 0) scale(.94); }
+.motion-ready [data-reveal].is-visible { opacity: 1; filter: blur(0); transform: translate3d(0, 0, 0) scale(1); }
+.motion-ready .hero [data-reveal].is-visible { animation: hero-arrive 1.1s var(--showcase-ease) both; }
+.motion-ready .hero .hero-shot.is-visible { animation-delay: .12s; }
+.motion-ready .hero .hero-actions.is-visible { animation-delay: .22s; }
+@keyframes hero-arrive { from { opacity: 0; filter: blur(18px); transform: translate3d(0, 34px, 0) scale(.98); } to { opacity: 1; filter: blur(0); transform: translate3d(0, 0, 0) scale(1); } }
+
+@media (max-width: 1050px) {
+ .hero { padding-top: 95px; }
+ .hero-inner { gap: 0; }
+ .pip-grid { gap: 45px; }
+ .workspace-stage { height: 470px; }
+}
+@media (max-width: 760px) {
+ .hero { padding: 90px 0 105px; }
+ .hero-copy h1 { font-size: clamp(54px, 11vw, 78px); }
+ .hero-shot { margin-top: 55px; }
+ .hero .shot-frame { border-radius: 15px; padding: 5px; }
+ .hero .shot-frame img { border-radius: 10px; }
+ .hero-actions { margin-top: 35px; }
+ .section { padding-block: 105px; }
+ .focus-intro { margin-bottom: 42px; }
+ .focus-intro h2, .canvas-head h2, .preview-section .section-head h2 { font-size: clamp(51px, 9vw, 72px); }
+ .focus-visual { border-radius: 15px; }
+ .focus-points { gap: 20px; margin-top: 48px; }
+ .focus-points h3 { font-size: 20px; }
+ .pip-grid { grid-template-columns: 1fr; }
+ .pip-copy h2 { font-size: 65px; }
+ .workspace-stage { height: 420px; }
+ .source-frame, .ratio-stage { height: 310px; }
+ .gallery-image-wrap { padding: 16px; }
+ .download-grid h2 { font-size: 65px; }
+ .source-grid { grid-template-columns: 1fr; }
+}
+@media (max-width: 560px) {
+ .hero { padding-top: 81px; }
+ .hero-copy h1 { font-size: clamp(47px, 12.5vw, 64px); }
+ .hero-copy p { font-size: 16px; }
+ .hero-shot { width: calc(100% + 16px); max-width: none; margin-top: 48px; }
+ .hero-actions { width: 100%; display: grid; grid-template-columns: 1fr; gap: 11px; }
+ .hero-actions .button { width: 100%; }
+ .section { padding-block: 88px; }
+ .focus-intro h2, .canvas-head h2, .preview-section .section-head h2 { font-size: 49px; }
+ .focus-points { grid-template-columns: 1fr; gap: 25px; }
+ .focus-points article { padding-top: 18px; }
+ .focus-points span { margin-bottom: 8px; }
+ .focus-points p { font-size: 13px; }
+ .pip-copy h2 { font-size: 57px; }
+ .pip-copy p { font-size: 16px; }
+ .workspace-stage { height: 315px; border-radius: 16px; }
+ .pip-capture { width: 66%; }
+ .canvas-head { margin-bottom: 36px; }
+ .demo-source, .demo-preview { padding: 17px; }
+ .source-frame, .ratio-stage { height: 260px; }
+ .demo-controls { padding: 20px 17px; }
+ .gallery { border-radius: 14px; }
+ .gallery-tabs { justify-content: center; gap: 4px; padding: 9px 7px; }
+ .gallery-tabs button { padding: 8px; font-size: 11px; }
+ .gallery-image-wrap { min-height: 240px; }
+ .download-grid { gap: 36px; }
+ .download-grid h2 { font-size: 54px; }
+ .download-actions { display: grid; gap: 14px; justify-items: center; }
+ .download-actions .button { min-width: 180px; }
+ .download-grid .install-card pre { padding: 19px 15px; }
+}
+@media (prefers-reduced-motion: reduce) {
+ .motion-ready [data-reveal], .motion-ready [data-reveal="visual"], .motion-ready [data-reveal].is-visible { opacity: 1; filter: none; transform: none; animation: none; }
+ .hero .shot-frame img, .focus-visual img, .pip-capture { transform: none; }
+}