1import type { RenderResponse } from '../worker/renderWorker';
3export default function DiagnosticsPanel({ result }: { result: RenderResponse }) {
4 const d = result.diag;
5 const modes = Array.from(result.modeF);
6 const shown = modes.slice(0, 10);
7 return (
8 <div className="diag">
9 <table>
10 <tbody>
11 <tr>
12 <th>Impacts</th>
13 <td>
14 {d.impactCount} · mean {d.meanV.toFixed(2)} m/s, max {d.maxV.toFixed(2)} m/s
15 </td>
16 </tr>
17 <tr>
18 <th>Contact time</th>
19 <td>{d.meanTauUs.toFixed(0)} µs mean (Hertz)</td>
20 </tr>
21 <tr>
22 <th>Shell modes</th>
23 <td className="partials">
24 {shown.map((f) => f.toFixed(0)).join(', ')}
25 {modes.length > shown.length ? `, … (${modes.length} total)` : ''} Hz
26 </td>
27 </tr>
28 <tr>
29 <th>Breathing</th>
30 <td>
31 {d.breathingHz.toFixed(0)} Hz (dry {d.breathingDryHz.toFixed(0)} Hz, cavity{' '}
32 {(d.breathingHz - d.breathingDryHz >= 0 ? '+' : '') +
33 (d.breathingHz - d.breathingDryHz).toFixed(0)}{' '}
34 Hz)
35 </td>
36 </tr>
37 <tr>
38 <th>Listener</th>
39 <td>{(d.listenerDistM * 100).toFixed(0)} cm from the shell centre</td>
40 </tr>
41 <tr>
42 <th>Peak pressure</th>
43 <td>
44 {d.peakPa.toFixed(3)} Pa ({d.peakSplDb.toFixed(1)} dB SPL)
45 </td>
46 </tr>
47 <tr>
48 <th>Length</th>
49 <td>
50 {d.durationS.toFixed(2)} s · {result.quality} · oversample {d.oversample}
51 </td>
52 </tr>
53 </tbody>
54 </table>
55 <div className="cachenote">
56 impacts: {d.solveCached ? 'cached' : `${(d.solveMs / 1000).toFixed(2)} s`} · radiation:{' '}
57 {d.radiateCached ? 'cached' : `${(d.radiateMs / 1000).toFixed(2)} s`}
58 </div>
59 {d.warnings.map((w, i) => (
60 <div key={i} className="warning">⚠ {w}</div>
61 ))}
62 </div>
63 );
64}