<?phpnamespace App\Scene;use App\Audio\Scale;use App\Render\Gfx;use JumPHP\Renderer\Renderer;/** * A spiral of dots that turns: the arms seem to flow outwards (or inwards) while the dots only circle, their size ripples along the arms and the * colours run round. Each arm that goes past the top or the bottom plays a note of a whole-tone scale (dreamy, no resolution). One turn * every 4 seconds, so the film loops with no seam. */final class SpiralScene extends VideoScene{ public const SECONDS = 24.0; protected const LOOPS = true; public const PERIOD = 4.0; public const ARMS = 8; private const DOTS = 24; private int $lastTick = -1; private float $glowTop = 0.0; protected function melodyNotes(): string { return 'C4'; } protected function headingText(): string { return 'WATCH THE CENTRE'; } protected function hookText(): string { return 'ARE THE ARMS MOVING OUT?'; } protected function captionText(): string { return $this->t('TURNS {n}', ['n' => (int)floor($this->time / self::PERIOD)]); } protected function build(): void { $this->lastTick = -1; $this->glowTop = 0.0; } protected function tick(float $dt): void { // an arm is at the top (or the bottom) every PERIOD / (2 ARMS) seconds $n = (int)floor($this->time / self::PERIOD * self::ARMS * 2); if ($n > $this->lastTick) { $this->lastTick = $n; $this->glowTop = 1.0; $this->play(Scale::freq(Scale::WHOLE_TONE, 2 + [0, 3, 1, 4, 2, 5, 3, 6][$n % 8] + ($n % 2) * 6, 60), 'bell', 0.9, 0.22, 0.0); $this->pulse = 0.8; $this->tint = Gfx::hsv($n * 0.05); } $this->glowTop = max(0.0, $this->glowTop - $dt * 3); } protected function drawWorld(Renderer $r): void { $cx = 135.0; $cy = 262.0; $turn = $this->time / self::PERIOD; for ($arm = 0; $arm < self::ARMS; $arm++) { for ($j = 0; $j < self::DOTS; $j++) { $u = ($j + 1) / self::DOTS; // 0..1 along the arm $rad = 8 + 128 * $u ** 0.9; $a = $turn * 2 * M_PI + $arm * 2 * M_PI / self::ARMS + $u * 4.4; $size = 1.1 + 4.6 * $u * (0.55 + 0.45 * sin(2 * M_PI * (3 * $u - 2 * $turn))); $hue = $arm / self::ARMS + $u * 0.35 + $turn * 0.25; $x = $cx + cos($a) * $rad; $y = $cy + sin($a) * $rad; Gfx::disc($r, $x, $y, $size, Gfx::hsv($hue, 0.55, 0.65 + 0.35 * $u)); } } Gfx::glow($r, $cx, $cy, 5 + 4 * $this->glowTop, [255, 255, 255], 0.9); Gfx::disc($r, $cx, $cy, 3.4, [255, 255, 255]); }}