Flutter Sheet Music Practice Card with Staff Notation
A music practice card that renders a real treble staff: five ruled lines, a clef, a 4/4 time signature, and eight note heads with stems placed at true pitch positions, with the current note highlighted. Built with Wind utility classes over WDynamic, so the whole score is absolutely positioned divs, no canvas and no image assets.
main.dart
WDiv(
className: 'flex flex-col w-[340px] rounded-3xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 p-5',
children: [
WDiv(
className: 'flex flex-row items-center w-full',
children: [
WDiv(
className: 'flex flex-row items-center justify-center w-[38px] h-[38px] rounded-2xl bg-indigo-500 dark:bg-indigo-600',
child: WIcon(
Icons.headphones,
className: 'text-xl text-white dark:text-white'
),
),
WDiv(
className: 'flex flex-col ml-3',
children: [
WText(
'Ode to Joy',
className: 'text-base font-bold text-gray-900 dark:text-white'
),
WText(
'Beethoven, Symphony No. 9',
className: 'text-[11px] text-gray-500 dark:text-gray-400'
),
],
),
WDiv(
className: 'flex flex-row items-center ml-6 rounded-full bg-emerald-100 dark:bg-emerald-900 px-2 py-1',
child: WText(
'GRADE 2',
className: 'text-[9px] font-bold tracking-wide text-emerald-700 dark:text-emerald-300'
),
),
],
),
WDiv(
className: 'flex flex-row items-center justify-between w-full mt-5',
children: [
WText(
'SHEET MUSIC',
className: 'text-[9px] font-bold tracking-widest text-gray-400 dark:text-gray-500'
),
WText(
'4/4, KEY OF C',
className: 'text-[9px] font-bold tracking-widest text-gray-400 dark:text-gray-500'
),
],
),
WDiv(
className: 'relative w-[300px] h-[96px] mt-2',
children: [
WDiv(
className: 'absolute left-[0px] top-[20px] w-[300px] h-[1px] bg-gray-800 dark:bg-gray-300'
),
WDiv(
className: 'absolute left-[0px] top-[30px] w-[300px] h-[1px] bg-gray-800 dark:bg-gray-300'
),
WDiv(
className: 'absolute left-[0px] top-[40px] w-[300px] h-[1px] bg-gray-800 dark:bg-gray-300'
),
WDiv(
className: 'absolute left-[0px] top-[50px] w-[300px] h-[1px] bg-gray-800 dark:bg-gray-300'
),
WDiv(
className: 'absolute left-[0px] top-[60px] w-[300px] h-[1px] bg-gray-800 dark:bg-gray-300'
),
WDiv(
className: 'absolute left-[169px] top-[2px] w-[26px] h-[26px] rounded-full bg-indigo-500/15 dark:bg-indigo-400/20'
),
WText(
'𝄞',
className: 'absolute left-[2px] top-[8px] text-[47px] text-gray-900 dark:text-gray-100'
),
WText(
'4',
className: 'absolute left-[42px] top-[18px] text-[19px] font-bold text-gray-900 dark:text-gray-100'
),
WText(
'4',
className: 'absolute left-[42px] top-[38px] text-[19px] font-bold text-gray-900 dark:text-gray-100'
),
WDiv(
className: 'absolute left-[62px] top-[21px] w-[12px] h-[8px] rounded-full bg-gray-900 dark:bg-gray-100'
),
WDiv(
className: 'absolute left-[62px] top-[25px] w-[2px] h-[34px] bg-gray-900 dark:bg-gray-100'
),
WDiv(
className: 'absolute left-[90px] top-[21px] w-[12px] h-[8px] rounded-full bg-gray-900 dark:bg-gray-100'
),
WDiv(
className: 'absolute left-[90px] top-[25px] w-[2px] h-[34px] bg-gray-900 dark:bg-gray-100'
),
WDiv(
className: 'absolute left-[118px] top-[16px] w-[12px] h-[8px] rounded-full bg-gray-900 dark:bg-gray-100'
),
WDiv(
className: 'absolute left-[118px] top-[20px] w-[2px] h-[34px] bg-gray-900 dark:bg-gray-100'
),
WDiv(
className: 'absolute left-[146px] top-[11px] w-[12px] h-[8px] rounded-full bg-gray-900 dark:bg-gray-100'
),
WDiv(
className: 'absolute left-[146px] top-[15px] w-[2px] h-[34px] bg-gray-900 dark:bg-gray-100'
),
WDiv(
className: 'absolute left-[176px] top-[11px] w-[12px] h-[8px] rounded-full bg-indigo-600 dark:bg-indigo-400'
),
WDiv(
className: 'absolute left-[176px] top-[15px] w-[2px] h-[34px] bg-indigo-600 dark:bg-indigo-400'
),
WDiv(
className: 'absolute left-[204px] top-[16px] w-[12px] h-[8px] rounded-full bg-gray-400 dark:bg-gray-500'
),
WDiv(
className: 'absolute left-[204px] top-[20px] w-[2px] h-[34px] bg-gray-400 dark:bg-gray-500'
),
WDiv(
className: 'absolute left-[232px] top-[21px] w-[12px] h-[8px] rounded-full bg-gray-400 dark:bg-gray-500'
),
WDiv(
className: 'absolute left-[232px] top-[25px] w-[2px] h-[34px] bg-gray-400 dark:bg-gray-500'
),
WDiv(
className: 'absolute left-[260px] top-[26px] w-[12px] h-[8px] rounded-full bg-gray-400 dark:bg-gray-500'
),
WDiv(
className: 'absolute left-[260px] top-[30px] w-[2px] h-[34px] bg-gray-400 dark:bg-gray-500'
),
WDiv(
className: 'absolute left-[166px] top-[20px] w-[1px] h-[41px] bg-gray-800 dark:bg-gray-300'
),
WDiv(
className: 'absolute left-[288px] top-[20px] w-[2px] h-[41px] bg-gray-900 dark:bg-gray-100'
),
WDiv(
className: 'absolute left-[294px] top-[20px] w-[5px] h-[41px] bg-gray-900 dark:bg-gray-100'
),
WText(
'BAR 9',
className: 'absolute left-[62px] top-[76px] text-[9px] font-bold tracking-widest text-gray-400 dark:text-gray-500'
),
WText(
'BAR 10',
className: 'absolute left-[176px] top-[76px] text-[9px] font-bold tracking-widest text-indigo-500 dark:text-indigo-400'
),
],
),
WDiv(
className: 'flex flex-row items-center justify-between w-full mt-4 rounded-2xl bg-indigo-50 dark:bg-indigo-950 px-3 py-3',
children: [
WDiv(
className: 'flex flex-col',
children: [
WText(
'Right hand, bars 9 to 16',
className: 'text-xs font-semibold text-gray-900 dark:text-white'
),
WText(
'Metronome on, no pedal',
className: 'text-[10px] text-gray-500 dark:text-gray-400'
),
],
),
WDiv(
className: 'flex flex-row items-center rounded-full bg-indigo-500 dark:bg-indigo-600 px-2 py-1',
child: WText(
'96 BPM',
className: 'text-[9px] font-bold tracking-wide text-white dark:text-white'
),
),
],
),
WDiv(
className: 'flex flex-row items-center justify-between w-full mt-4',
children: [
WDiv(
className: 'flex flex-col items-center w-[92px] rounded-2xl bg-gray-50 dark:bg-gray-800 py-3',
children: [
WText(
'94%',
className: 'text-lg font-bold text-gray-900 dark:text-white'
),
WText(
'ACCURACY',
className: 'text-[9px] font-bold tracking-wide text-gray-400 dark:text-gray-500'
),
],
),
WDiv(
className: 'flex flex-col items-center w-[92px] rounded-2xl bg-gray-50 dark:bg-gray-800 py-3',
children: [
WText(
'18',
className: 'text-lg font-bold text-gray-900 dark:text-white'
),
WText(
'RUNS',
className: 'text-[9px] font-bold tracking-wide text-gray-400 dark:text-gray-500'
),
],
),
WDiv(
className: 'flex flex-col items-center w-[92px] rounded-2xl bg-gray-50 dark:bg-gray-800 py-3',
children: [
WText(
'12',
className: 'text-lg font-bold text-gray-900 dark:text-white'
),
WText(
'STREAK',
className: 'text-[9px] font-bold tracking-wide text-gray-400 dark:text-gray-500'
),
],
),
],
),
WDiv(
className: 'flex flex-row items-center w-full mt-4',
children: [
WIcon(
Icons.emoji_events,
className: 'text-base text-amber-500 dark:text-amber-400'
),
WText(
'Two clean runs left to unlock Grade 3.',
className: 'text-[11px] text-gray-600 dark:text-gray-300 ml-2'
),
],
),
WDiv(
className: 'w-full mt-4',
child: WButton(
className: 'flex flex-row items-center justify-center w-full rounded-2xl bg-gray-900 dark:bg-white py-3',
child: WText(
'Start slow practice',
className: 'text-sm font-semibold text-white dark:text-gray-900'
),
),
),
],
)
Stats
- Views
- 145
- Stars
- 0
- Revisions
- 1
- Size
- 8,841 chars
- Created
- Sep 16, 2026