/*
* Clone of ui.html for systems without chromium.
*
* /usr/bin/osascript -l JavaScript update-panel.js
*
* Must remain here, next to posix.sh.
* The desktop spawns this directory as-is (see resolvePosixScriptHandoff) and the script references it via
* its own path.
*/
ObjC.import('AppKit')
ObjC.import('QuartzCore') // CACurrentMediaTime
// ── Fourier Flow — constants and math ported verbatim from ui.html ──────────
// Keep in sync with ui.html / apps/desktop/src/components/ui/loader.tsx:
// durationMs 2200, particleCount 92, pulseDurationMs 2000, strokeWidth 4.2,
// trailSpan 0.31, PATH_STEPS 240, viewBox 0 0 100 100 (center 50,50).
const TWO_PI = Math.PI * 2
const CURVE = {
durationMs: 2200,
particleCount: 92,
pulseDurationMs: 2000,
strokeWidth: 4.2,
trailSpan: 0.31,
point(progress, detailScale) {
const t = progress * TWO_PI
const mix = 1 + detailScale * 0.16
const x = 17 * Math.cos(t) + 7.5 * Math.cos(3 * t + 0.6 * mix) + 3.2 * Math.sin(5 * t - 0.4)
const y = 15 * Math.sin(t) + 8.2 * Math.sin(2 * t + 0.25) - 4.2 * Math.cos(4 * t - 0.5 * mix)
return { x: 50 + x, y: 50 + y }
}
}
const PATH_STEPS = 240
const norm = progress => ((progress % 1) + 1) % 1
function detailScaleFor (time, phaseOffset) {
const p = ((time + phaseOffset * CURVE.pulseDurationMs) % CURVE.pulseDurationMs) / CURVE.pulseDurationMs
return 0.52 + ((Math.sin(p * TWO_PI + 0.55) + 1) / 2) * 0.48
}
function particleFor (index, progress, detailScale) {
const tail = index / (CURVE.particleCount - 1)
const { x, y } = CURVE.point(norm(progress - tail * CURVE.trailSpan), detailScale)
const fade = (1 - tail) ** 0.56
return { x, y, opacity: 0.04 + fade * 0.96, radius: 0.9 + fade * 2.7 }
}
// Render one animation frame into an 80x80 NSImage (the JS analog of the
// page's