/* @jsx React.createElement */ /* Method — 3-layer progress system (Level Journey + Skill Radar + Milestone Badges) */ const LEVELS = [ { id: 0, short: 'Pre', long: 'Pre-Beginner', weeks: '1–4', desc: 'Adaptasi dulu. Posisi tangan, posture, suara pertama.' }, { id: 1, short: 'B1', long: 'Beginner 1', weeks: '5–16', desc: 'Lagu asli mulai masuk. Chord, beat, melodi dasar.' }, { id: 2, short: 'B2', long: 'Beginner 2', weeks: '17–36',desc: 'Udah bisa main. Teknik makin tight, kuping makin tajem.' }, { id: 3, short: 'P1', long: 'Performance 1', weeks: '37–60',desc: 'Studio session pertama. Naik panggung beneran.' }, { id: 4, short: 'P2', long: 'Performance 2', weeks: '60+', desc: 'Punya karakter sendiri. Improvisasi, theory deep-dive.' }, { id: 5, short: 'P3', long: 'Performance 3', weeks: '∞', desc: 'Kamu ngajar sebanyak kamu belajar. Mentor track (optional).' }, ]; function MethodSection() { const [activeLevel, setActiveLevel] = React.useState(2); const lvl = LEVELS[activeLevel]; return (
Metode IMS · A + B + C

Tiga cara liat progress kamu yang beneran.

Sekolah lain biasanya cuma bilang "good job" terus selesai. Kita bikin progress kelihatan — tanpa bikin kayak ujian. Tiga lensa, satu arah.

A · Level B · Radar C · Badges
{/* A — Level Journey */} {/* B — Skill Radar */} {/* C — Milestone Badges */}
); } function Pill({ children }) { return ( {children} ); } function SectionLabel({ n, title, desc, style = {} }) { return (
{n}

{title}

{desc}

); } /* ─── A — Level Journey (interactive line) ─── */ function LevelJourney({ levels, active, onSelect, current }) { return (
{/* Rail */}
{/* Filled rail to active */}
{/* Nodes */}
{levels.map((l, i) => { const isActive = i === active; const isPast = i < active; return ( ); })}
{/* Active level description */}
Lagi di {current.long}

{current.desc}

Step {current.id + 1} / 6
); } /* ─── B — Skill Radar (animated chart) ─── */ const RADAR_DATA = { guitar: { skills: ['Chord', 'Rhythm', 'Melody', 'Technique', 'Ear', 'Theory'], start: [1, 1, 1, 1, 1, 1], now: [4, 3.5, 3, 3.2, 2.8, 2.5] }, piano: { skills: ['L.Hand', 'R.Hand', 'Coord.', 'Rhythm', 'Ear', 'Theory'], start: [1, 1, 1, 1, 1, 1], now: [3.2, 4, 3.5, 3.5, 3, 2.8] }, drum: { skills: ['Power', 'Rhythm', 'Coord.', 'Tempo', 'Dynamics', 'Fills'], start: [1, 1, 1, 1, 1, 1], now: [4, 3.5, 3, 4, 2.8, 3.2] }, bass: { skills: ['Finger', 'Rhythm', 'Groove', 'Tech.', 'Ear', 'Theory'], start: [1, 1, 1, 1, 1, 1], now: [3.8, 3.5, 4, 3, 3.2, 2.5] }, vocal: { skills: ['Pitch', 'Breath', 'Tone', 'Rhythm', 'Express', 'Ear'], start: [1, 1, 1, 1, 1, 1], now: [3.5, 3.8, 3.2, 3, 4, 3] }, }; function SkillRadarBlock() { const [inst, setInst] = React.useState('guitar'); const [showNow, setShowNow] = React.useState(false); const data = RADAR_DATA[inst]; React.useEffect(() => { setShowNow(false); const t = setTimeout(() => setShowNow(true), 200); return () => clearTimeout(t); }, [inst]); return (
{/* Radar chart */}
{Object.keys(RADAR_DATA).map(k => ( ))}
Minggu 1 Minggu 32
{/* Right: explanation */}
); } function RadarPoint({ n, title, desc }) { return (
{n}
{title}
{desc}
); } function RadarSVG({ skills, start, now }) { const size = 320; const cx = size / 2, cy = size / 2; const max = 5; const radius = 110; const n = skills.length; const pointFor = (val, i) => { const angle = (Math.PI * 2 * i) / n - Math.PI / 2; const r = (val / max) * radius; return [cx + Math.cos(angle) * r, cy + Math.sin(angle) * r]; }; const labelFor = (i) => { const angle = (Math.PI * 2 * i) / n - Math.PI / 2; const r = radius + 22; return [cx + Math.cos(angle) * r, cy + Math.sin(angle) * r]; }; const polygon = (data) => data.map((v, i) => pointFor(v, i).join(',')).join(' '); return ( {/* Concentric polygons */} {[1, 2, 3, 4, 5].map(level => { const pts = skills.map((_, i) => pointFor(level, i).join(',')).join(' '); return ; })} {/* Axes */} {skills.map((_, i) => { const [x, y] = pointFor(max, i); return ; })} {/* Start polygon */} {/* Now polygon — animated */} {/* Now points */} {now.map((v, i) => { const [x, y] = pointFor(v, i); return ; })} {/* Labels */} {skills.map((s, i) => { const [x, y] = labelFor(i); return ( {s} ); })} ); } /* ─── C — Milestone Badges (sample) ─── */ const SAMPLE_BADGES = [ { id: 'first-chord', title: 'Chord pertama yang clean', unlock: 'Beginner 1', earned: true }, { id: 'first-fill', title: 'Drum fill pertama', unlock: 'Beginner 1', earned: true }, { id: 'song-end-to-end',title:'Satu lagu full, tanpa berhenti',unlock: 'Beginner 2', earned: true }, { id: 'lock-in', title: 'Lock-in sama band', unlock: 'Beginner 2', earned: false, progress: 0.6 }, { id: 'first-stage', title: 'Live performance pertama', unlock: 'Performance 1', earned: false, progress: 0.3 }, { id: 'recording', title: 'Take rekaman studio', unlock: 'Performance 1', earned: false, progress: 0.1 }, { id: 'arrange', title: 'Aransemen lagu sendiri', unlock: 'Performance 2', earned: false }, { id: 'mentor', title: 'Mentor murid baru', unlock: 'Performance 3', earned: false }, ]; function BadgesBlock() { return (
{SAMPLE_BADGES.map(b => (
{b.earned ? ( ) : ( )}
{b.title}
{b.unlock}
{!b.earned && b.progress !== undefined && (
)}
))}
); } Object.assign(window, { MethodSection });