diff --git a/README.md b/README.md index 35846d6..c5c1c40 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ npm run start ``` src/data/exercises.json # the free-tier bundle (400 exercises), imported as a module -public/images/flat/*.webp # 745 flat webp (start/peak pairs + single-pose "main") +public/images/flat/*.webp # 741 flat webp (start/peak pairs + single-pose "main") public/images/muscles/*.webp # 27 muscle icons public/images/equipment/*.webp # 46 equipment icons public/images/samples/*.webp # 1 paid-tier looping animation (Standard-tier preview) diff --git a/public/images/flat/ab-wheel-rollout-peak.webp b/public/images/flat/ab-wheel-rollout-peak.webp index 1810b0e..08c319a 100644 Binary files a/public/images/flat/ab-wheel-rollout-peak.webp and b/public/images/flat/ab-wheel-rollout-peak.webp differ diff --git a/public/images/flat/ab-wheel-rollout-start.webp b/public/images/flat/ab-wheel-rollout-start.webp index c171e11..888ae52 100644 Binary files a/public/images/flat/ab-wheel-rollout-start.webp and b/public/images/flat/ab-wheel-rollout-start.webp differ diff --git a/public/images/flat/bench-leg-pull-in-peak.webp b/public/images/flat/bench-leg-pull-in-peak.webp index 7d2d6d5..7c7dd91 100644 Binary files a/public/images/flat/bench-leg-pull-in-peak.webp and b/public/images/flat/bench-leg-pull-in-peak.webp differ diff --git a/public/images/flat/bench-leg-pull-in-start.webp b/public/images/flat/bench-leg-pull-in-start.webp index 82ac3b7..6da401e 100644 Binary files a/public/images/flat/bench-leg-pull-in-start.webp and b/public/images/flat/bench-leg-pull-in-start.webp differ diff --git a/public/images/flat/ez-bar-romanian-deadlift-peak.webp b/public/images/flat/ez-bar-romanian-deadlift-peak.webp deleted file mode 100644 index c3e0dce..0000000 Binary files a/public/images/flat/ez-bar-romanian-deadlift-peak.webp and /dev/null differ diff --git a/public/images/flat/ez-bar-romanian-deadlift-start.webp b/public/images/flat/ez-bar-romanian-deadlift-start.webp deleted file mode 100644 index f27c93f..0000000 Binary files a/public/images/flat/ez-bar-romanian-deadlift-start.webp and /dev/null differ diff --git a/public/images/flat/pull-up-peak.webp b/public/images/flat/pull-up-peak.webp index 0e5e335..29b67a4 100644 Binary files a/public/images/flat/pull-up-peak.webp and b/public/images/flat/pull-up-peak.webp differ diff --git a/public/images/flat/pull-up-start.webp b/public/images/flat/pull-up-start.webp index 652f0db..5529bd8 100644 Binary files a/public/images/flat/pull-up-start.webp and b/public/images/flat/pull-up-start.webp differ diff --git a/public/images/flat/standing-calf-raise-peak.webp b/public/images/flat/standing-calf-raise-peak.webp deleted file mode 100644 index 612559c..0000000 Binary files a/public/images/flat/standing-calf-raise-peak.webp and /dev/null differ diff --git a/public/images/flat/standing-calf-raise-start.webp b/public/images/flat/standing-calf-raise-start.webp deleted file mode 100644 index f93502d..0000000 Binary files a/public/images/flat/standing-calf-raise-start.webp and /dev/null differ diff --git a/public/images/samples/README.md b/public/images/samples/README.md new file mode 100644 index 0000000..02a4474 --- /dev/null +++ b/public/images/samples/README.md @@ -0,0 +1,7 @@ +# premium-samples/ + +A Standard-tier exercise — bent-over-db-row — at full paid-tier quality: +classic start/peak stills plus the looping transparent-background animation, +the same clip shown on https://repdb.co. The Standard tier adds animations +like this for most exercises. Current tiers and pricing: +https://repdb.co/pricing diff --git a/public/images/samples/bent-over-db-row-peak.webp b/public/images/samples/bent-over-db-row-peak.webp new file mode 100644 index 0000000..ba2f1d1 Binary files /dev/null and b/public/images/samples/bent-over-db-row-peak.webp differ diff --git a/public/images/samples/bent-over-db-row-start.webp b/public/images/samples/bent-over-db-row-start.webp new file mode 100644 index 0000000..74b3e15 Binary files /dev/null and b/public/images/samples/bent-over-db-row-start.webp differ diff --git a/src/app/page.tsx b/src/app/page.tsx index 99f4fbb..a11a0ee 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -46,6 +46,8 @@ export default async function Home({ searchParams }: PageProps) { + + )} - - ); } diff --git a/src/components/ExerciseCard.tsx b/src/components/ExerciseCard.tsx index 08a378d..5e33dde 100644 --- a/src/components/ExerciseCard.tsx +++ b/src/components/ExerciseCard.tsx @@ -1,5 +1,4 @@ import Link from 'next/link'; -import Image from 'next/image'; import { type Exercise, type Locale, @@ -18,7 +17,9 @@ export function ExerciseCard({ exercise, locale }: { exercise: Exercise; locale: >
{thumb ? ( - {name} = { start: 'Start', @@ -33,7 +33,7 @@ export function ExerciseFrames({ ))} diff --git a/src/data/exercises.json b/src/data/exercises.json index b93a51c..3c1df2b 100644 --- a/src/data/exercises.json +++ b/src/data/exercises.json @@ -1,6 +1,6 @@ { "schema_version": 3, - "generated_at": "2026-07-16T19:41:37Z", + "generated_at": "2026-07-27T13:53:50Z", "locales": [ "de", "en", @@ -12294,7 +12294,7 @@ "dumbbell pistol squat" ], "instructions_en": [ - "Stand tall, holding a dumbbell in front of your chest with both hands or in one hand on the same side as the working leg.", + "Stand tall, holding a dumbbell in each hand with your arms hanging at your sides.", "Lift one leg straight out in front of you, keeping it extended throughout the movement.", "Lower your body by bending the knee of your standing leg, keeping your chest up and back straight.", "Descend until your glutes are close to your heel or your thigh is parallel to the floor, maintaining balance.", @@ -12302,8 +12302,8 @@ "Complete all reps on one side, then switch legs and repeat for the other side per set." ], "tips_en": [ - "Start with bodyweight pistol squats to master the movement pattern before adding a dumbbell.", - "Use a counterweight (dumbbell) held out in front to help maintain balance during the descent.", + "Start with bodyweight pistol squats to master the movement pattern before adding dumbbells.", + "Let the dumbbells hang straight down at your sides and keep your chest up to stay balanced over the working foot.", "Focus on controlling the eccentric (lowering) phase to improve stability and strength.", "Elevate your heel slightly on a small plate if ankle mobility is a limiting factor." ], @@ -12318,7 +12318,7 @@ "name_de": "Kurzhantel-Pistol-Squat", "description_de": "Der Kurzhantel-Pistol-Squat ist eine fortgeschrittene einbeinige Kniebeugen-Variante, die erhebliche Unterkörperkraft, Gleichgewicht und Beweglichkeit aufbaut, hauptsächlich für Quadrizeps und Gesäßmuskulatur.", "instructions_de": [ - "Stehe aufrecht und halte eine Kurzhantel mit beiden Händen vor der Brust oder in einer Hand auf der Seite des Arbeitsbeins.", + "Stehe aufrecht und halte in jeder Hand eine Kurzhantel, die Arme hängen seitlich am Körper.", "Hebe ein Bein gerade nach vorne an und halte es während der gesamten Bewegung gestreckt.", "Senke deinen Körper, indem du das Knie deines Standbeins beugst, Brust oben und Rücken gerade halten.", "Gehe so tief, bis dein Gesäß nahe an deiner Ferse ist oder dein Oberschenkel parallel zum Boden ist, und halte das Gleichgewicht.", @@ -12326,15 +12326,15 @@ "Absolviere alle Wiederholungen auf einer Seite, wechsle dann das Bein und wiederhole pro Satz für die andere Seite." ], "tips_de": [ - "Beginne mit Pistol-Squats ohne Gewicht, um das Bewegungsmuster zu meistern, bevor du eine Kurzhantel hinzufügst.", - "Nutze ein Gegengewicht (Kurzhantel), das du nach vorne hältst, um das Gleichgewicht während der Abwärtsbewegung zu halten.", - "Konzentriere dich auf die Kontrolle der exzentrischen (senkenden) Phase, um Stabilität und Kraft zu verbessern.", - "Erhöhe deine Ferse leicht auf einer kleinen Platte, wenn die Sprunggelenksbeweglichkeit ein limitierender Faktor ist." + "Beginne mit Pistol Squats ohne Gewicht, um das Bewegungsmuster zu beherrschen, bevor du Kurzhanteln hinzunimmst.", + "Lass die Kurzhanteln seitlich gerade nach unten hängen und halte die Brust aufrecht, um über dem Arbeitsfuß im Gleichgewicht zu bleiben.", + "Konzentriere dich auf die kontrollierte exzentrische (absenkende) Phase, um Stabilität und Kraft zu verbessern.", + "Erhöhe die Ferse leicht auf einer kleinen Scheibe, falls die Sprunggelenksbeweglichkeit ein limitierender Faktor ist." ], "name_es": "Sentadilla Pistola con Mancuerna", "description_es": "La Sentadilla Pistola con Mancuerna es una variación avanzada de sentadilla a una pierna que desarrolla fuerza significativa en la parte inferior del cuerpo, equilibrio y movilidad, apuntando principalmente a los cuádriceps y glúteos.", "instructions_es": [ - "Ponte de pie, sosteniendo una mancuerna frente a tu pecho con ambas manos o en una mano del mismo lado que la pierna que trabaja.", + "Ponte de pie, sosteniendo una mancuerna en cada mano con los brazos colgando a los lados.", "Levanta una pierna recta hacia adelante, manteniéndola extendida durante todo el movimiento.", "Baja tu cuerpo doblando la rodilla de tu pierna de apoyo, manteniendo el pecho erguido y la espalda recta.", "Desciende hasta que tus glúteos estén cerca de tu talón o tu muslo esté paralelo al suelo, manteniendo el equilibrio.", @@ -12342,10 +12342,10 @@ "Completa todas las repeticiones de un lado, luego cambia de pierna y repite para el otro lado por serie." ], "tips_es": [ - "Comienza con sentadillas pistola sin peso corporal para dominar el patrón de movimiento antes de añadir una mancuerna.", - "Usa un contrapeso (mancuerna) sostenido al frente para ayudar a mantener el equilibrio durante el descenso.", - "Concéntrate en controlar la fase excéntrica (bajada) para mejorar la estabilidad y la fuerza.", - "Eleva ligeramente tu talón sobre un pequeño disco si la movilidad del tobillo es un factor limitante." + "Empieza con sentadillas pistola sin peso para dominar el patrón de movimiento antes de añadir mancuernas.", + "Deja que las mancuernas cuelguen rectas a los lados y mantén el pecho erguido para conservar el equilibrio sobre el pie que trabaja.", + "Concéntrate en controlar la fase excéntrica (de descenso) para mejorar la estabilidad y la fuerza.", + "Eleva ligeramente el talón sobre un disco pequeño si la movilidad del tobillo es un factor limitante." ], "images": { "flat": [ @@ -13782,6 +13782,7 @@ "forearm_flexors", "trapezius" ], + "image_alias": "romanian-deadlift", "name_de": "SZ-Stange Romanian Deadlift", "description_de": "Ein Romanian Deadlift mit der SZ-Stange. Der angewinkelte Griff schont die Handgelenke und eignet sich für leichtere Hinge-Arbeit oder handgelenkempfindliche Athleten.", "instructions_de": [ @@ -28517,6 +28518,7 @@ "secondary_muscles": [ "soleus" ], + "image_alias": "machine-calf-raise", "name_de": "Stehende Wadenhebeübung", "description_de": "Eine im Stand ausgeführte Wadenübung, die den Gastrocnemius durch einen vollen Bewegungsumfang kräftigt.", "instructions_de": [ diff --git a/src/lib/bundle.ts b/src/lib/bundle.ts index 1d7a524..090b297 100644 --- a/src/lib/bundle.ts +++ b/src/lib/bundle.ts @@ -34,6 +34,7 @@ export interface TaxonomyEntry { export interface Bundle { schema_version: number; + generated_at?: string; locales: Locale[]; exercises: Exercise[]; muscles?: Record; @@ -46,6 +47,12 @@ export const EXERCISES = BUNDLE.exercises; export const LOCALES: Locale[] = BUNDLE.locales; export const MUSCLES = BUNDLE.muscles ?? {}; export const EQUIPMENT = BUNDLE.equipment ?? {}; +export const ASSET_VERSION = BUNDLE.generated_at ?? 'dev'; + +/** Bust browser/Next caches when a newly generated bundle replaces vendored assets. */ +export function assetUrl(path: string): string { + return `${path}?v=${encodeURIComponent(ASSET_VERSION)}`; +} /** Base slug for image files — aliased exercises borrow another slug's renders. */ export function imageBase(ex: Exercise): string { @@ -62,7 +69,7 @@ export function exerciseThumb(ex: Exercise): string | null { const variants = flatVariants(ex); const pick = variants.find((v) => v === 'peak') ?? variants.find((v) => v === 'main') ?? variants[0]; - return pick ? `/images/flat/${imageBase(ex)}-${pick}.webp` : null; + return pick ? assetUrl(`/images/flat/${imageBase(ex)}-${pick}.webp`) : null; } function localized(entry: TaxonomyEntry | undefined, locale: Locale, fallback: string): string { @@ -78,7 +85,7 @@ export function muscleLabel(key: string, locale: Locale): string { export function muscleIcon(key: string): string | null { const img = MUSCLES[key]?.image; - return img ? `/images/muscles/${img}` : null; + return img ? assetUrl(`/images/muscles/${img}`) : null; } export function equipmentLabel(key: string, locale: Locale): string { @@ -87,7 +94,7 @@ export function equipmentLabel(key: string, locale: Locale): string { export function equipmentIcon(key: string): string | null { const img = EQUIPMENT[key]?.image; - return img ? `/images/equipment/${img}` : null; + return img ? assetUrl(`/images/equipment/${img}`) : null; } export function exerciseName(ex: Exercise, locale: Locale): string { diff --git a/src/lib/samples.ts b/src/lib/samples.ts index 2ad3b7e..37d4c7e 100644 --- a/src/lib/samples.ts +++ b/src/lib/samples.ts @@ -1,5 +1,6 @@ import fs from 'node:fs'; import path from 'node:path'; +import { assetUrl } from '@/lib/bundle'; /** * Paid-tier preview animations. @@ -22,11 +23,15 @@ function readSampleAnimations(): SampleAnimation[] { try { return fs .readdirSync(SAMPLES_DIR) - .filter((file) => file.endsWith('.webp')) + .filter( + (file) => + file.endsWith('.webp') && + !/-(start|peak|main)\.webp$/.test(file), + ) .sort() .map((file) => ({ slug: file.replace(/\.webp$/, ''), - src: `/images/samples/${file}`, + src: assetUrl(`/images/samples/${file}`), })); } catch { return [];