44 < meta charset ="UTF-8 ">
55 < meta name ="viewport " content ="width=device-width, initial-scale=1 ">
66 < title > CuePoint – Accurate metadata for Rekordbox</ title >
7- < link rel ="icon " href ="https://stuchain.github.io/CuePoint/logo.png " type ="image/svg+xml ">
8- < link rel ="shortcut icon " href ="https://stuchain.github.io/CuePoint/logo.png " type ="image/svg+xml ">
9- < link rel ="apple-touch-icon " href ="https://stuchain.github.io/CuePoint/logo.png ">
10- < link rel ="preconnect " href ="https://fonts.googleapis.com ">
11- < link rel ="preconnect " href ="https://fonts.gstatic.com " crossorigin >
12- < link href ="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700&display=swap " rel ="stylesheet ">
7+ < meta name ="description " content ="Match Rekordbox tracks to Beatport for key, BPM, label, genre, and release date. Desktop app for Windows and macOS with a full audit trail. ">
8+ < link rel ="canonical " href ="https://stuchain.github.io/CuePoint/ ">
9+ < meta property ="og:title " content ="CuePoint – Accurate metadata for Rekordbox ">
10+ < meta property ="og:description " content ="Match Rekordbox tracks to Beatport for key, BPM, label, genre, and release date. Desktop app for Windows and macOS with a full audit trail. ">
11+ < meta property ="og:url " content ="https://stuchain.github.io/CuePoint/ ">
12+ < meta property ="og:type " content ="website ">
13+ < meta property ="og:image " content ="https://stuchain.github.io/CuePoint/logo.png ">
14+ < meta name ="twitter:card " content ="summary ">
15+ < meta name ="twitter:title " content ="CuePoint – Accurate metadata for Rekordbox ">
16+ < meta name ="twitter:description " content ="Match Rekordbox tracks to Beatport for key, BPM, label, genre, and release date. Desktop app for Windows and macOS with a full audit trail. ">
17+ < meta name ="twitter:image " content ="https://stuchain.github.io/CuePoint/logo.png ">
18+ < link rel ="icon " href ="logo.png " type ="image/png ">
19+ < link rel ="shortcut icon " href ="logo.png " type ="image/png ">
20+ < link rel ="apple-touch-icon " href ="logo.png ">
1321 < style >
1422 : root {
1523 --bg : # 0d1117 ;
2432 --radius : 12px ;
2533 --radius-sm : 8px ;
2634 --transition : 0.25s ease;
35+ --font : -apple-system, BlinkMacSystemFont, "Segoe UI" , "Noto Sans" , Helvetica, Arial, sans-serif, "Apple Color Emoji" , "Segoe UI Emoji" ;
2736 }
2837 * { box-sizing : border-box; }
2938 html { scroll-behavior : smooth; }
39+ @media (prefers-reduced-motion : reduce) {
40+ html { scroll-behavior : auto; }
41+ }
3042 body {
31- font-family : 'DM Sans' , -apple-system , BlinkMacSystemFont , "Segoe UI" , sans-serif ;
43+ font-family : var ( --font ) ;
3244 line-height : 1.6 ;
3345 color : var (--text );
3446 background : var (--bg );
4355 section { padding : 4rem 0 ; }
4456 section .reveal { opacity : 0 ; transform : translateY (24px ); transition : opacity 0.6s ease, transform 0.6s ease; }
4557 section .reveal .visible { opacity : 1 ; transform : translateY (0 ); }
58+ @media (prefers-reduced-motion : reduce) {
59+ section .reveal { transform : translateY (8px ); transition : opacity 0.2s ease, transform 0.2s ease; }
60+ }
4661
4762 /* Hero */
4863 .hero {
6681 margin-bottom : 1.5rem ;
6782 animation : logoFloat 4s ease-in-out infinite;
6883 }
84+ @media (prefers-reduced-motion : reduce) {
85+ .hero .logo-wrap { animation : none; }
86+ }
6987 @keyframes logoFloat {
7088 0% , 100% { transform : translateY (0 ); }
7189 50% { transform : translateY (-6px ); }
108126 border : none;
109127 cursor : pointer;
110128 }
111- .btn : hover {
129+ .btn : hover : not ([ aria-disabled = "true" ]) {
112130 background : var (--accent-hover );
113131 transform : translateY (-1px );
114132 }
117135 color : var (--text ) !important ;
118136 border : 1px solid var (--border );
119137 }
120- .btn-secondary : hover {
138+ .btn-secondary : hover : not ([ aria-disabled = "true" ]) {
121139 background : # 21262d ;
122140 border-color : var (--muted );
123141 }
142+ a .btn [aria-disabled = "true" ] {
143+ opacity : 0.55 ;
144+ pointer-events : none;
145+ cursor : not-allowed;
146+ }
124147
125148 /* Intro */
126149 .intro .lead {
134157 text-align : center;
135158 color : var (--muted );
136159 font-size : 0.95rem ;
160+ margin : 0 0 1rem ;
161+ }
162+ .intro .tools-line {
163+ text-align : center;
164+ color : var (--muted );
165+ font-size : 0.95rem ;
166+ max-width : 560px ;
167+ margin : 0 auto;
168+ line-height : 1.55 ;
137169 }
170+ .intro .tools-line strong { color : var (--text ); font-weight : 600 ; }
138171
139172 /* Features */
140173 .features-grid {
152185 transform : translateY (12px );
153186 transition : opacity 0.4s ease, transform 0.4s ease, border-color var (--transition ), box-shadow var (--transition );
154187 }
188+ @media (prefers-reduced-motion : reduce) {
189+ .feature-card { transition : opacity 0.2s ease, transform 0.2s ease, border-color var (--transition ), box-shadow var (--transition ); }
190+ }
155191 section .visible .feature-card { opacity : 1 ; transform : translateY (0 ); }
156192 section .visible .feature-card : nth-child (1 ) { transition-delay : 0.05s ; }
157193 section .visible .feature-card : nth-child (2 ) { transition-delay : 0.15s ; }
185221 margin : 0 auto;
186222 }
187223
224+ /* How it works */
225+ .how-steps {
226+ list-style : none;
227+ padding : 0 ;
228+ margin : 2rem 0 0 ;
229+ display : grid;
230+ gap : 1rem ;
231+ max-width : 640px ;
232+ margin-left : auto;
233+ margin-right : auto;
234+ }
235+ .how-steps li {
236+ display : flex;
237+ gap : 1rem ;
238+ align-items : flex-start;
239+ background : var (--surface );
240+ border : 1px solid var (--border );
241+ border-radius : var (--radius-sm );
242+ padding : 1rem 1.25rem ;
243+ font-size : 0.95rem ;
244+ color : var (--muted );
245+ }
246+ .how-steps .step-num {
247+ flex-shrink : 0 ;
248+ width : 1.75rem ;
249+ height : 1.75rem ;
250+ border-radius : 50% ;
251+ background : var (--accent );
252+ color : # fff ;
253+ font-weight : 600 ;
254+ font-size : 0.85rem ;
255+ display : flex;
256+ align-items : center;
257+ justify-content : center;
258+ }
259+
188260 /* Download block */
189261 .download-section {
190262 background : var (--surface );
196268 .download-section h2 {
197269 font-size : 1.25rem ;
198270 font-weight : 600 ;
271+ margin : 0 0 0.35rem ;
272+ }
273+ .download-version {
274+ color : var (--muted );
275+ font-size : 0.9rem ;
276+ margin : 0 0 0.75rem ;
277+ min-height : 1.35em ;
278+ }
279+ .download-version : empty { margin : 0 ; min-height : 0 ; }
280+ .download-status {
281+ color : var (--muted );
282+ font-size : 0.9rem ;
199283 margin : 0 0 1rem ;
200284 }
285+ .download-status .is-hidden { display : none; }
201286 .downloads {
202287 display : flex;
203288 flex-direction : row;
234319 font-size : 0.9rem ;
235320 }
236321 footer a : hover { color : var (--link-hover ); text-decoration : underline; }
237- footer .links { display : flex; gap : 1.5rem ; justify-content : center; flex-wrap : wrap; }
322+ footer .links { display : flex; gap : 1.5rem ; justify-content : center; flex-wrap : wrap; margin-bottom : 1.25rem ; }
323+ .footer-disclaimer {
324+ font-size : 0.75rem ;
325+ color : var (--muted );
326+ max-width : 520px ;
327+ margin : 0 auto;
328+ line-height : 1.5 ;
329+ }
238330 </ style >
239331</ head >
240332< body >
@@ -246,86 +338,140 @@ <h1>CuePoint</h1>
246338 < p class ="tagline "> Accurate music metadata for Rekordbox libraries, from Beatport.</ p >
247339 < div class ="cta ">
248340 < a href ="#download " class ="btn "> Download</ a >
249- < a href ="https://github.com/stuchain/CuePoint#readme " class ="btn btn-secondary "> GitHub</ a >
341+ < a href ="https://github.com/stuchain/CuePoint#readme " class ="btn btn-secondary " target =" _blank " rel =" noopener noreferrer " > GitHub</ a >
250342 </ div >
251343 </ header >
252344
253- < section class ="intro reveal ">
254- < div class ="page ">
255- < p class ="lead "> Match your Rekordbox tracks to Beatport and get key, BPM, label, genre, and release date without manual lookup.</ p >
256- < p class ="sub "> Export from Rekordbox → run CuePoint → review or re-import. Full audit trail for every match.</ p >
257- </ div >
258- </ section >
345+ < main >
346+ < section class ="intro reveal ">
347+ < div class ="page ">
348+ < p class ="lead "> Match your Rekordbox tracks to Beatport and get key, BPM, label, genre, and release date without manual lookup.</ p >
349+ < p class ="sub "> Export from Rekordbox → run CuePoint → review or re-import. Full audit trail for every match.</ p >
350+ < p class ="tools-line "> CuePoint includes < strong > inKey</ strong > (Beatport metadata for Rekordbox playlists) and < strong > inCrate</ strong > (inventory, charts, new releases, and Beatport playlists from your collection).</ p >
351+ </ div >
352+ </ section >
259353
260- < section class ="reveal ">
261- < div class ="page ">
262- < h2 class ="section-title "> Why CuePoint</ h2 >
263- < p class ="section-desc "> Clean metadata, traceable decisions, and built to handle large libraries.</ p >
264- < div class ="features-grid ">
265- < div class ="feature-card ">
266- < h3 > Clean metadata</ h3 >
267- < p > Key, BPM, label, genre, release date: consistent and reviewable.</ p >
268- </ div >
269- < div class ="feature-card ">
270- < h3 > Auditable matches</ h3 >
271- < p > Every query and candidate is logged so you can verify decisions.</ p >
272- </ div >
273- < div class ="feature-card ">
274- < h3 > Built for scale</ h3 >
275- < p > Handles large libraries with parallel search and configurable time budgets.</ p >
354+ < section class ="reveal ">
355+ < div class ="page ">
356+ < h2 class ="section-title "> Why CuePoint</ h2 >
357+ < p class ="section-desc "> Clean metadata, traceable decisions, and built to handle large libraries.</ p >
358+ < div class ="features-grid ">
359+ < div class ="feature-card ">
360+ < h3 > Clean metadata</ h3 >
361+ < p > Key, BPM, label, genre, release date: consistent and reviewable.</ p >
362+ </ div >
363+ < div class ="feature-card ">
364+ < h3 > Auditable matches</ h3 >
365+ < p > Every query and candidate is logged so you can verify decisions.</ p >
366+ </ div >
367+ < div class ="feature-card ">
368+ < h3 > Built for scale</ h3 >
369+ < p > Handles large libraries with parallel search and configurable time budgets.</ p >
370+ </ div >
276371 </ div >
277372 </ div >
278- </ div >
279- </ section >
373+ </ section >
280374
281- < section id ="download " class ="reveal ">
282- < div class ="page ">
283- < div class ="download-section ">
284- < h2 > Download</ h2 >
285- < p class ="section-desc " style ="margin-bottom: 1rem; "> Windows and macOS. Pick your platform.</ p >
286- < div class ="downloads ">
287- < a class ="btn " id ="win-dl " href ="# "> Windows</ a >
288- < a class ="btn " id ="mac-dl " href ="# "> macOS</ a >
375+ < section class ="reveal " aria-labelledby ="how-heading ">
376+ < div class ="page ">
377+ < h2 id ="how-heading " class ="section-title "> How it works</ h2 >
378+ < p class ="section-desc "> Three steps from library export to updated metadata.</ p >
379+ < ul class ="how-steps ">
380+ < li > < span class ="step-num " aria-hidden ="true "> 1</ span > < span > Export playlists from Rekordbox as XML.</ span > </ li >
381+ < li > < span class ="step-num " aria-hidden ="true "> 2</ span > < span > Open them in CuePoint and match tracks to Beatport.</ span > </ li >
382+ < li > < span class ="step-num " aria-hidden ="true "> 3</ span > < span > Review results and re-import or apply metadata in Rekordbox.</ span > </ li >
383+ </ ul >
384+ </ div >
385+ </ section >
386+
387+ < section id ="download " class ="reveal ">
388+ < div class ="page ">
389+ < div class ="download-section ">
390+ < h2 > Download</ h2 >
391+ < p id ="dl-version " class ="download-version " aria-live ="polite "> </ p >
392+ < p class ="section-desc " style ="margin-bottom: 1rem; "> Windows and macOS. Pick your platform.</ p >
393+ < p id ="dl-status " class ="download-status "> Loading…</ p >
394+ < div class ="downloads ">
395+ < a class ="btn " id ="win-dl " href ="# " aria-disabled ="true "> Windows</ a >
396+ < a class ="btn " id ="mac-dl " href ="# " aria-disabled ="true "> macOS</ a >
397+ </ div >
398+ < a class ="releases " href ="https://github.com/stuchain/CuePoint/releases " target ="_blank " rel ="noopener noreferrer "> All releases</ a >
289399 </ div >
290- < a class ="releases " href ="https://github.com/stuchain/CuePoint/releases "> All releases</ a >
291400 </ div >
292- </ div >
293- </ section >
401+ </ section >
402+ </ main >
294403
295404 < footer class ="reveal ">
296405 < div class ="page ">
297406 < div class ="links ">
298- < a href ="https://github.com/stuchain/CuePoint "> GitHub</ a >
299- < a href ="https://github.com/stuchain/CuePoint/releases "> Releases</ a >
407+ < a href ="https://github.com/stuchain/CuePoint " target ="_blank " rel ="noopener noreferrer "> GitHub</ a >
408+ < a href ="https://github.com/stuchain/CuePoint/releases " target ="_blank " rel ="noopener noreferrer "> Releases</ a >
409+ < a href ="https://github.com/stuchain/CuePoint/issues " target ="_blank " rel ="noopener noreferrer "> Issues</ a >
410+ < a href ="https://github.com/stuchain/CuePoint/blob/main/docs/getting-started/quick-start.md " target ="_blank " rel ="noopener noreferrer "> Documentation</ a >
300411 </ div >
412+ < p class ="footer-disclaimer "> Not affiliated with third-party brands named on this page.</ p >
301413 </ div >
302414 </ footer >
303415
304416 < script >
305417 ( function ( ) {
418+ var LATEST = 'https://github.com/stuchain/CuePoint/releases/latest' ;
306419 var winEl = document . getElementById ( 'win-dl' ) ;
307420 var macEl = document . getElementById ( 'mac-dl' ) ;
308- // GitHub releases/latest returns the latest non-prerelease, non-draft release only.
421+ var statusEl = document . getElementById ( 'dl-status' ) ;
422+ var versionEl = document . getElementById ( 'dl-version' ) ;
423+
424+ function finishLoading ( ) {
425+ statusEl . classList . add ( 'is-hidden' ) ;
426+ winEl . removeAttribute ( 'aria-disabled' ) ;
427+ macEl . removeAttribute ( 'aria-disabled' ) ;
428+ }
429+
430+ function setFallback ( ) {
431+ winEl . href = macEl . href = LATEST ;
432+ }
433+
309434 fetch ( 'https://api.github.com/repos/stuchain/CuePoint/releases/latest' )
310- . then ( function ( r ) { return r . json ( ) ; } )
435+ . then ( function ( r ) {
436+ if ( ! r . ok ) throw new Error ( 'release fetch failed' ) ;
437+ return r . json ( ) ;
438+ } )
311439 . then ( function ( release ) {
312- if ( release . prerelease || ! release . assets || ! release . assets . length ) return ;
440+ if ( release . tag_name ) {
441+ versionEl . textContent = 'Latest release: ' + release . tag_name ;
442+ }
443+ if ( release . prerelease || ! release . assets || ! release . assets . length ) {
444+ setFallback ( ) ;
445+ finishLoading ( ) ;
446+ return ;
447+ }
448+ var winUrl = '' ;
449+ var macUrl = '' ;
313450 release . assets . forEach ( function ( asset ) {
314451 var name = asset . name . toLowerCase ( ) ;
315- if ( name . endsWith ( '.exe' ) ) winEl . href = asset . browser_download_url ;
316- else if ( name . includes ( 'macos' ) && name . endsWith ( '.dmg' ) ) macEl . href = asset . browser_download_url ;
452+ if ( name . endsWith ( '.exe' ) ) winUrl = asset . browser_download_url ;
453+ else if ( name . includes ( 'macos' ) && name . endsWith ( '.dmg' ) ) macUrl = asset . browser_download_url ;
317454 } ) ;
455+ if ( ! winUrl || ! macUrl ) {
456+ setFallback ( ) ;
457+ } else {
458+ winEl . href = winUrl ;
459+ macEl . href = macUrl ;
460+ }
461+ finishLoading ( ) ;
318462 } )
319463 . catch ( function ( ) {
320- winEl . href = macEl . href = 'https://github.com/stuchain/CuePoint/releases/latest' ;
464+ setFallback ( ) ;
465+ versionEl . textContent = '' ;
466+ finishLoading ( ) ;
321467 } ) ;
322468
323469 var observer = new IntersectionObserver ( function ( entries ) {
324470 entries . forEach ( function ( e ) {
325471 if ( e . isIntersecting ) e . target . classList . add ( 'visible' ) ;
326472 } ) ;
327473 } , { rootMargin : '0px 0px -60px 0px' , threshold : 0.1 } ) ;
328- document . querySelectorAll ( 'section.reveal' ) . forEach ( function ( el ) { observer . observe ( el ) ; } ) ;
474+ document . querySelectorAll ( 'section.reveal, footer.reveal ' ) . forEach ( function ( el ) { observer . observe ( el ) ; } ) ;
329475 } ) ( ) ;
330476 </ script >
331477</ body >
0 commit comments