James Li

Violinist

James Li, professional violinist

Royal College of Music | Mozarteum University

About

James Li, also known as Zi Jun Li, is a Hong Kong-born violinist based in the United Kingdom, active as a soloist, recitalist and chamber musician. From September 2026, he will undertake the Artist Diploma in Performance at the Royal College of Music, London, following a Master of Arts in Violin Performance with Distinction and a Bachelor of Arts (Hons) in Violin Performance with First-Class Honours from Mozarteum University Salzburg, Austria.Recent honours include the Absolute First Prize and Special Prizes at the International Competition Music Academy FORTE in Belgium, First Prize at the International Competition Giovani Musicisti – Città di Treviso, and Second Prize at the Concorso Internazionale Musicale “Città di Cervignano” in Italy. He has performed as a soloist, recitalist and chamber musician across Europe, Asia and North America.James’s principal conservatoire teachers include Adrian Levine, Wonji Kim-Ozim and Pierre Amoyal. His earlier musical development was guided by Wing Shun Lee, Kiann Chow and Vivian Leung, whose teaching laid an important foundation for his later studies.James performs on a violin made by Enrico Marchetti in Turin in 1902.

Media

J. S. Bach — Partita No. 3 in E major, BWV 1006
James Li, violin
Select a movement
(() => { const container = document.getElementById('jl-bach-recording'); if ( !container || container.dataset.initialised === 'yes' ) { return; } container.dataset.initialised = 'yes'; const audio = container.querySelector('.jl-bach-audio'); const movementButtons = container.querySelectorAll('.jl-movement'); const completeButton = container.querySelector('.jl-complete-button'); const completeLabel = container.querySelector('.jl-complete-label'); let playbackMode = null; let selectedEnd = null; let activeMovement = null; let actionNumber = 0; function wait(milliseconds) { return new Promise(resolve => { window.setTimeout(resolve, milliseconds); }); } function pauseOtherRecordings() { document.querySelectorAll('audio').forEach(item => { if ( item !== audio && !item.paused ) { item.pause(); } }); } function anotherRecordingIsPlaying() { return Array.from( document.querySelectorAll('audio') ).some(item => { return ( item !== audio && !item.paused ); }); } function waitForMetadata() { if ( audio.readyState >= 1 && Number.isFinite(audio.duration) ) { return Promise.resolve(); } return new Promise((resolve, reject) => { const loaded = () => { cleanup(); resolve(); }; const failed = () => { cleanup(); reject( audio.error || new Error( 'The Bach recording could not be loaded.' ) ); }; const cleanup = () => { audio.removeEventListener( 'loadedmetadata', loaded ); audio.removeEventListener( 'error', failed ); }; audio.addEventListener( 'loadedmetadata', loaded, { once: true } ); audio.addEventListener( 'error', failed, { once: true } ); audio.load(); }); } async function seekTo(timeInSeconds) { await waitForMetadata(); const maximumTime = Number.isFinite(audio.duration) ? Math.max(0, audio.duration - 0.1) : timeInSeconds; const targetTime = Math.max( 0, Math.min( timeInSeconds, maximumTime ) ); if ( Math.abs( audio.currentTime - targetTime ) < 0.05 ) { return; } await new Promise((resolve, reject) => { let timeout; const seekCompleted = () => { cleanup(); resolve(); }; const seekFailed = () => { cleanup(); reject( audio.error || new Error( 'The recording could not be positioned.' ) ); }; const cleanup = () => { window.clearTimeout(timeout); audio.removeEventListener( 'seeked', seekCompleted ); audio.removeEventListener( 'error', seekFailed ); }; audio.addEventListener( 'seeked', seekCompleted, { once: true } ); audio.addEventListener( 'error', seekFailed, { once: true } ); try { audio.currentTime = targetTime; } catch (error) { cleanup(); reject(error); return; } timeout = window.setTimeout(() => { cleanup(); resolve(); }, 1800); }); } function clearMovementSelection() { movementButtons.forEach(button => { button.classList.remove('is-active'); }); activeMovement = null; } function showCompletePlay() { completeLabel.textContent = 'Listen to complete recording'; completeButton.setAttribute( 'aria-label', 'Play complete Bach Partita' ); completeButton.setAttribute( 'aria-pressed', 'false' ); } function showCompletePause() { completeLabel.textContent = 'Pause complete recording'; completeButton.setAttribute( 'aria-label', 'Pause complete Bach Partita' ); completeButton.setAttribute( 'aria-pressed', 'true' ); } movementButtons.forEach(button => { button.addEventListener( 'click', async () => { const start = Number(button.dataset.start); const end = Number(button.dataset.end); const delay = Number(button.dataset.delay || 0); /* * Clicking the currently selected movement * pauses or resumes it. */ if ( playbackMode === 'movement' && activeMovement === button ) { if (audio.paused) { pauseOtherRecordings(); try { await audio.play(); } catch (error) { console.error( 'Bach playback failed:', error ); } } else { audio.pause(); } return; } actionNumber += 1; const thisAction = actionNumber; audio.pause(); pauseOtherRecordings(); clearMovementSelection(); playbackMode = 'movement'; selectedEnd = end; activeMovement = button; button.classList.add('is-active'); showCompletePlay(); try { await seekTo(start); /* * Preludio requires a small artificial pause, * since the MP3 begins very close to its first note. */ if (delay > 0) { await wait(delay); } if ( thisAction !== actionNumber || anotherRecordingIsPlaying() ) { return; } await audio.play(); } catch (error) { console.error( 'Bach movement playback failed:', error ); clearMovementSelection(); playbackMode = null; selectedEnd = null; } } ); }); completeButton.addEventListener( 'click', async () => { if (playbackMode === 'complete') { if (audio.paused) { pauseOtherRecordings(); try { await audio.play(); } catch (error) { console.error( 'Bach playback failed:', error ); } } else { audio.pause(); } return; } actionNumber += 1; const thisAction = actionNumber; audio.pause(); pauseOtherRecordings(); clearMovementSelection(); playbackMode = 'complete'; selectedEnd = null; try { await seekTo(0); /* * Adds a gentle pause before the opening * of the complete recording. */ await wait(900); if ( thisAction !== actionNumber || anotherRecordingIsPlaying() ) { return; } await audio.play(); } catch (error) { console.error( 'Complete Bach playback failed:', error ); playbackMode = null; showCompletePlay(); } } ); audio.addEventListener( 'playing', () => { if (playbackMode === 'complete') { showCompletePause(); } } ); audio.addEventListener( 'pause', () => { if ( playbackMode === 'complete' && !audio.ended ) { showCompletePlay(); } } ); audio.addEventListener( 'timeupdate', () => { if ( playbackMode === 'movement' && selectedEnd !== null && audio.currentTime >= selectedEnd - 0.15 ) { actionNumber += 1; audio.pause(); clearMovementSelection(); playbackMode = null; selectedEnd = null; } } ); audio.addEventListener( 'ended', () => { actionNumber += 1; clearMovementSelection(); playbackMode = null; selectedEnd = null; showCompletePlay(); } ); })();
N. Paganini — Caprice No. 24 in A minor, Op. 1
James Li, violin
(() => { const container = document.getElementById('jl-paganini-recording'); if ( !container || container.dataset.initialised === 'yes' ) { return; } container.dataset.initialised = 'yes'; const audio = container.querySelector('.jl-paganini-audio'); const button = container.querySelector('.jl-listen-button'); const label = container.querySelector('.jl-button-label'); function pauseOtherRecordings() { document.querySelectorAll('audio').forEach(item => { if ( item !== audio && !item.paused ) { item.pause(); } }); } button.addEventListener( 'click', async () => { if (!audio.paused) { audio.pause(); return; } pauseOtherRecordings(); label.textContent = 'Loading recording…'; try { await audio.play(); } catch (error) { console.error( 'Paganini playback failed:', error ); label.textContent = 'Playback unavailable'; } } ); audio.addEventListener( 'playing', () => { label.textContent = 'Pause recording'; button.setAttribute( 'aria-label', 'Pause Paganini Caprice No. 24' ); button.setAttribute( 'aria-pressed', 'true' ); } ); audio.addEventListener( 'pause', () => { if (!audio.ended) { label.textContent = 'Listen to recording'; button.setAttribute( 'aria-label', 'Play Paganini Caprice No. 24' ); button.setAttribute( 'aria-pressed', 'false' ); } } ); audio.addEventListener( 'ended', () => { audio.currentTime = 0; label.textContent = 'Listen to recording'; button.setAttribute( 'aria-label', 'Play Paganini Caprice No. 24' ); button.setAttribute( 'aria-pressed', 'false' ); } ); })();
J. S. Bach — Sonata No. 2 in A minor, BWV 1003: III. Andante
James Li, violin
(() => { const container = document.getElementById( 'jl-bach-andante-recording' ); if ( !container || container.dataset.initialised === 'yes' ) { return; } container.dataset.initialised = 'yes'; const audio = container.querySelector( '.jl-bach-andante-audio' ); const button = container.querySelector( '.jl-listen-button' ); const label = container.querySelector( '.jl-button-label' ); function pauseOtherRecordings() { document .querySelectorAll('audio') .forEach(otherAudio => { if ( otherAudio !== audio && !otherAudio.paused ) { otherAudio.pause(); } }); } function showPlayState() { label.textContent = 'Listen to recording'; button.setAttribute( 'aria-label', 'Play Bach Andante' ); button.setAttribute( 'aria-pressed', 'false' ); } function showPauseState() { label.textContent = 'Pause recording'; button.setAttribute( 'aria-label', 'Pause Bach Andante' ); button.setAttribute( 'aria-pressed', 'true' ); } button.addEventListener( 'click', async () => { if (!audio.paused) { audio.pause(); return; } pauseOtherRecordings(); label.textContent = 'Loading recording…'; try { await audio.play(); } catch (error) { console.error( 'Bach Andante playback failed:', error ); label.textContent = 'Playback unavailable'; button.setAttribute( 'aria-pressed', 'false' ); } } ); audio.addEventListener( 'playing', showPauseState ); audio.addEventListener( 'pause', () => { if (!audio.ended) { showPlayState(); } } ); audio.addEventListener( 'ended', () => { audio.currentTime = 0; showPlayState(); } ); })();

Performances

Recent performance highlights include recitals and chamber appearances in Salzburg, Brussels, Cervignano, Bristol, Cheltenham and Bad Reichenhall. As a soloist, James has performed Sibelius’s Violin Concerto, Vaughan Williams’s The Lark Ascending and Mozart’s Violin Concerto No. 1. His recital repertoire includes sonatas by Debussy and Brahms, Lutosławski’s Subito and Elgar’s Salut d’Amour, alongside major works for solo violin by Bach, Ysaÿe and Paganini.

Forthcoming

December 2026 · Salzburg
Recital with pianist Patrick Leung · Schlosskirche
Spring 2027 · Cheltenham
Recital of French Music · St Philip & St James Church
2027 · Romania
Concert appearances · Presented by TYM Festival & Competition
June 2027 · London
Recital · Royal College of Music

Past Performances

28 July 2026 · Cervignano
Concert · Teatro Pasolini
3 July 2026 · Brussels
Concert · City Hall of Woluwe-Saint-Lambert
2 June 2026 · Salzburg
Recital · Stiftung Mozarteum – Wiener Saal
13 May 2026 · Salzburg
Recital · Universität Mozarteum Salzburg – Kleines Studio
14 November 2025 · Bad Reichenhall
Concert · Konzertsaal des Alten Feuerhauses
26 July 2025 · Cheltenham
Recital · St. Philip & St. James Church
8 July 2025 · Bristol
Recital · Bristol Cathedral
7 June 2025 · North Woodchester
Concert · St. Mary's Church
29 March 2025 · Tewkesbury
Concert · Tewkesbury Abbey
17 November 2024 · Cheltenham
Concert · The Big Classical
8 July 2024 · Cheltenham
Recital · St. Gregory's Church

Teaching

Alongside his performing career, James offers a small number of private violin lessons in Cheltenham for motivated students with previous playing experience. His teaching emphasises secure technique, musical understanding and expressive communication.

Contact

For performance enquiries, collaborations and other professional matters, please use the form below.

For private violin lesson enquiries in Cheltenham, please visit the dedicated teaching page.

Information submitted through this form will only be used to respond to your enquiry.

YOUTUBE · FACEBOOK . SOUNDCLOUD

Privacy Policy · Cookie Policy

© 2026 James Li. All rights reserved.

{ "@context": "https://schema.org", "@type": "ProfilePage", "@id": "https://jamesliviolin.com/#profile", "url": "https://jamesliviolin.com/", "mainEntity": { "@type": "Person", "@id": "https://jamesliviolin.com/#james-li", "name": "James Li", "jobTitle": "Violinist", "description": "Hong Kong-born, UK-based violinist.", "url": "https://jamesliviolin.com/" } }

Privacy Policy

Last updated: July 2026This website is operated by James Li.When you use the contact form, I may collect your name, email address, message, and any information you choose to include about performance enquiries, collaborations, or violin lessons.This information is used only to respond to your enquiry, communicate with you, and, where relevant, discuss lesson arrangements or professional engagements.I do not sell personal information. Information may be processed through the website platform, email provider, or other services used to operate this website and respond to enquiries.Personal information is kept only for as long as reasonably necessary for the purpose of responding to and managing enquiries, unless a longer period is required for legitimate professional or legal reasons.You may contact me to ask about the personal information held about you, or to request correction or deletion where appropriate.Information submitted through this website will only be used to respond to your enquiry.

Cookie Policy

This website may use essential cookies or similar technologies needed for the website and contact form to function properly.Embedded content, such as YouTube videos, may use cookies or similar technologies provided by third-party services. These services may collect information when you view or interact with embedded media.This website does not intentionally use advertising cookies or tracking cookies set directly by James Li.You can control or delete cookies through your browser settings.

C. Debussy — Sonata for Violin and Piano in G minor, L. 140
James Li, violin | Craig White, piano
Select a movement
(() => { const container = document.getElementById('jl-debussy-recording'); if ( !container || container.dataset.initialised === 'yes' ) { return; } container.dataset.initialised = 'yes'; const audio = container.querySelector('.jl-debussy-audio'); const movementButtons = container.querySelectorAll('.jl-movement'); const completeButton = container.querySelector('.jl-complete-button'); const completeLabel = container.querySelector('.jl-complete-label'); if ( !audio || !completeButton || !completeLabel ) { return; } let playbackMode = null; let selectedEnd = null; let activeMovement = null; let actionNumber = 0; function wait(milliseconds) { return new Promise(resolve => { window.setTimeout(resolve, milliseconds); }); } function pauseOtherRecordings() { document.querySelectorAll('audio').forEach(item => { if ( item !== audio && !item.paused ) { item.pause(); } }); } function anotherRecordingIsPlaying() { return Array.from( document.querySelectorAll('audio') ).some(item => { return ( item !== audio && !item.paused ); }); } function waitForMetadata() { if ( audio.readyState >= 1 && Number.isFinite(audio.duration) ) { return Promise.resolve(); } return new Promise((resolve, reject) => { const loaded = () => { cleanup(); resolve(); }; const failed = () => { cleanup(); reject( audio.error || new Error( 'The Debussy recording could not be loaded.' ) ); }; const cleanup = () => { audio.removeEventListener( 'loadedmetadata', loaded ); audio.removeEventListener( 'error', failed ); }; audio.addEventListener( 'loadedmetadata', loaded, { once: true } ); audio.addEventListener( 'error', failed, { once: true } ); audio.load(); }); } async function seekTo(timeInSeconds) { await waitForMetadata(); const maximumTime = Number.isFinite(audio.duration) ? Math.max(0, audio.duration - 0.1) : timeInSeconds; const targetTime = Math.max( 0, Math.min( timeInSeconds, maximumTime ) ); if ( Math.abs( audio.currentTime - targetTime ) < 0.05 ) { return; } await new Promise((resolve, reject) => { let timeout; const seekCompleted = () => { cleanup(); resolve(); }; const seekFailed = () => { cleanup(); reject( audio.error || new Error( 'The recording could not be positioned.' ) ); }; const cleanup = () => { window.clearTimeout(timeout); audio.removeEventListener( 'seeked', seekCompleted ); audio.removeEventListener( 'error', seekFailed ); }; audio.addEventListener( 'seeked', seekCompleted, { once: true } ); audio.addEventListener( 'error', seekFailed, { once: true } ); try { audio.currentTime = targetTime; } catch (error) { cleanup(); reject(error); return; } timeout = window.setTimeout(() => { cleanup(); resolve(); }, 1800); }); } function clearMovementSelection() { movementButtons.forEach(button => { button.classList.remove('is-active'); button.setAttribute( 'aria-pressed', 'false' ); }); activeMovement = null; } function showCompletePlay() { completeLabel.textContent = 'Listen to complete recording'; completeButton.setAttribute( 'aria-label', 'Play complete Debussy Sonata' ); completeButton.setAttribute( 'aria-pressed', 'false' ); } function showCompletePause() { completeLabel.textContent = 'Pause complete recording'; completeButton.setAttribute( 'aria-label', 'Pause complete Debussy Sonata' ); completeButton.setAttribute( 'aria-pressed', 'true' ); } movementButtons.forEach(button => { button.setAttribute( 'aria-pressed', 'false' ); button.addEventListener( 'click', async () => { const start = Number(button.dataset.start); const endValue = button.dataset.end; const end = endValue === '' ? null : Number(endValue); const delay = Number(button.dataset.delay || 0); if ( playbackMode === 'movement' && activeMovement === button ) { if (audio.paused) { pauseOtherRecordings(); try { await audio.play(); } catch (error) { console.error( 'Debussy playback failed:', error ); } } else { audio.pause(); } return; } actionNumber += 1; const thisAction = actionNumber; audio.pause(); pauseOtherRecordings(); clearMovementSelection(); playbackMode = 'movement'; selectedEnd = end; activeMovement = button; button.classList.add('is-active'); button.setAttribute( 'aria-pressed', 'true' ); showCompletePlay(); try { await seekTo(start); if (delay > 0) { await wait(delay); } if ( thisAction !== actionNumber || anotherRecordingIsPlaying() ) { return; } await audio.play(); } catch (error) { console.error( 'Debussy movement playback failed:', error ); clearMovementSelection(); playbackMode = null; selectedEnd = null; } } ); }); completeButton.addEventListener( 'click', async () => { if (playbackMode === 'complete') { if (audio.paused) { pauseOtherRecordings(); try { await audio.play(); } catch (error) { console.error( 'Debussy playback failed:', error ); } } else { audio.pause(); } return; } actionNumber += 1; const thisAction = actionNumber; audio.pause(); pauseOtherRecordings(); clearMovementSelection(); playbackMode = 'complete'; selectedEnd = null; try { await seekTo(0); await wait(900); if ( thisAction !== actionNumber || anotherRecordingIsPlaying() ) { return; } await audio.play(); } catch (error) { console.error( 'Complete Debussy playback failed:', error ); playbackMode = null; showCompletePlay(); } } ); audio.addEventListener( 'playing', () => { if (playbackMode === 'complete') { showCompletePause(); } } ); audio.addEventListener( 'pause', () => { if ( playbackMode === 'complete' && !audio.ended ) { showCompletePlay(); } } ); audio.addEventListener( 'timeupdate', () => { if ( playbackMode === 'movement' && selectedEnd !== null && audio.currentTime >= selectedEnd - 0.15 ) { actionNumber += 1; audio.pause(); clearMovementSelection(); playbackMode = null; selectedEnd = null; } } ); audio.addEventListener( 'ended', () => { actionNumber += 1; clearMovementSelection(); playbackMode = null; selectedEnd = null; showCompletePlay(); } ); audio.addEventListener( 'error', () => { actionNumber += 1; clearMovementSelection(); playbackMode = null; selectedEnd = null; completeLabel.textContent = 'Playback unavailable'; completeButton.setAttribute( 'aria-label', 'Debussy recording unavailable' ); completeButton.setAttribute( 'aria-pressed', 'false' ); } ); })();