274: transect composition, spectrum outro, and lyric fixes it exposed #1

Merged
mikkeli merged 7 commits from song274/transect into song274/master 2026-09-17 01:36:54 +00:00
Owner

Merges the transect work for 274 into the song's master branch.

What this adds

Song274Transect — a Remotion composition (src/song-274/) that draws Route 274 in its true shape and plays it with the song:

  • Data (data.ts): reads song-274/route/ at load time — lyrics index, roster, route, and the west/east approach stubs. Nothing is copied into code; remotion.config.ts makes song-274/ the public dir.
  • Progress (progress.ts): a "covered so far" paint over the dimmed road, pinned to each sung object's km as its line starts, gliding on a monotone cubic. The west stub is always painted; the east stub is visible dim and painted after 東に続く (EAST_RUN_S).
  • Camera (camera.ts): close zoom during each narration part, following a Gaussian-smoothed head; pulls back to the covered road (plus some road ahead) in the breaks and to the full map after the lyric.
  • Nodes (nodeAnimation.ts): only sung objects are drawn; lightUp / switchOff looks, with long lines switching off after MAX_LIT_S. Nodes sharing exact coordinates are spread slightly along the road (layout.ts).
  • Spectrum outro (spectrum.ts): from SPECTRUM_START_S each node gets a seeded-shuffled log-spaced frequency band and sizes with its amplitude (@remotion/media-utils, windowed audio).
  • Palette (palette.ts): every colour a named token; dark palette retuned, light palette alongside.

Deliverables fixed along the way: building the transect exposed problems in the lyric (紅葉山橋 is on R452, 下福山橋/オロロップ橋 at the wrong km, lines mistimed). Fixed upstream in the wiki (ncmr-songs 7af0f48); 274.lrc, 274.srt and 274.ass here follow, and BOM.md records the 274_release2.wav master.

Checks

  • eslint src && tsc clean on every commit's tree.
  • ASS events and SRT cues match the LRC's order, text and timestamps; every sung node joins the roster at matching km.
  • Stills checked across narration parts, breaks, the ending and the spectrum outro.

Rendering note

Render video with --muted and add audio with ffmpeg (AAC 320k, -c:v copy): Remotion's own AAC comes out 42.75 ms late.

🤖 Generated with Claude Code

Merges the transect work for 274 into the song's master branch. ## What this adds **Song274Transect** — a Remotion composition (`src/song-274/`) that draws Route 274 in its true shape and plays it with the song: - **Data** (`data.ts`): reads `song-274/route/` at load time — lyrics index, roster, route, and the west/east approach stubs. Nothing is copied into code; `remotion.config.ts` makes `song-274/` the public dir. - **Progress** (`progress.ts`): a "covered so far" paint over the dimmed road, pinned to each sung object's km as its line starts, gliding on a monotone cubic. The west stub is always painted; the east stub is visible dim and painted after 東に続く (`EAST_RUN_S`). - **Camera** (`camera.ts`): close zoom during each narration part, following a Gaussian-smoothed head; pulls back to the covered road (plus some road ahead) in the breaks and to the full map after the lyric. - **Nodes** (`nodeAnimation.ts`): only sung objects are drawn; `lightUp` / `switchOff` looks, with long lines switching off after `MAX_LIT_S`. Nodes sharing exact coordinates are spread slightly along the road (`layout.ts`). - **Spectrum outro** (`spectrum.ts`): from `SPECTRUM_START_S` each node gets a seeded-shuffled log-spaced frequency band and sizes with its amplitude (`@remotion/media-utils`, windowed audio). - **Palette** (`palette.ts`): every colour a named token; dark palette retuned, light palette alongside. **Deliverables fixed along the way**: building the transect exposed problems in the lyric (紅葉山橋 is on R452, 下福山橋/オロロップ橋 at the wrong km, lines mistimed). Fixed upstream in the wiki (ncmr-songs `7af0f48`); `274.lrc`, `274.srt` and `274.ass` here follow, and `BOM.md` records the `274_release2.wav` master. ## Checks - `eslint src && tsc` clean on every commit's tree. - ASS events and SRT cues match the LRC's order, text and timestamps; every sung node joins the roster at matching km. - Stills checked across narration parts, breaks, the ending and the spectrum outro. ## Rendering note Render video with `--muted` and add audio with ffmpeg (AAC 320k, `-c:v copy`): Remotion's own AAC comes out 42.75 ms late. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
mikkeli added 7 commits 2026-09-17 01:32:42 +00:00
Song274Transect draws Route 274 in its true shape (the "Ground" view of
song-274/route/274-transect.html) and plays it along with the song.

- data.ts: reads song-274/route/ at load time (lyrics index, roster, route and
  the optional east/west stubs); nothing is copied into the code. Only sung
  nodes are shown; districts and 東に続く light nothing.
- progress.ts: a "covered so far" paint over the dimmed road. Its head is pinned
  to each sung object's km as that line starts and glides between pins on a
  monotone cubic, so it never runs backwards. After 東に続く it runs out along
  the east stub; the west stub is always painted.
- camera.ts: fixed close zoom during each narration part (lines under 20 s
  apart), following a Gaussian-smoothed head; pull back to frame the covered
  road plus some road ahead during breaks, and to the full map after the lyric.
- nodeAnimation.ts: lightUp / switchOff as reusable functions over a NodeLook,
  with long lines switching off after MAX_LIT_S.
- palette.ts: every colour as a named token (dark default, light alongside),
  including shrine and railway families.

remotion.config.ts sets song-274/ as the public dir so staticFile() reaches the
song's audio/ and route/ in place.

Verified: eslint + tsc clean; stills checked across parts, breaks and the ending.
Render with --muted and add audio with ffmpeg: Remotion's own AAC lands 42.75 ms
late.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PLt25nCVMsoroKALYUBu6u
274_release2.wav (2026-09-17) supersedes 274_release1.wav and is the master
used by the white/lyrics renders and Song274Transect. Same length, 10:19.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Building the transect visualisation (Song274Transect) is what exposed problems
in the lyric and its index: syncing nodes to the lyric showed 紅葉山橋 lighting
up although it is not on this road (it is on R452), 下福山橋 and オロロップ橋
sitting at the wrong km, and lines timed against the wrong stretch. They were
fixed upstream in the wiki (ncmr-songs 7af0f48, "274: drop 紅葉山橋, fix
オロロップ橋 and 下福山橋, re-timed lyric"), and the lyric deliverables here
follow.

274.lrc — byte-identical copy of the wiki LRC at 7af0f48: 紅葉山橋 removed;
  紅楓橋 through 楓信号場 re-timed (1:35.24–1:55.54) with 夕張市楓 at 1:45.77;
  登川トンネル at 2:05.23 and its section end at 2:06.62; 稲里トンネル's section
  end at 4:25.27. 下福山橋 and オロロップ橋 keep their timing; their km were
  corrected in the roster and index.
274.srt — regenerated with scripts/lrc2srt.py, 116 cues.
274.ass — events follow the LRC: district headers as transparent_title spanning
  their section, 東に続く as transparent_lyrics_jp, spacers as empty events, the
  final line held 5 s. The Aegisub header and all 17 styles are untouched.
  117 events -> 116.

route/ — copied from novoyuuparosk-wiki/ncmr-songs wip/274, where it is
generated; read-only here, and its README says so. src/song-274/data.ts loads
274-route.json, 274-lookup.csv and 274-lyrics-index.csv, plus the two approach
stubs: 274-route-west.json (always drawn as covered) and 274-route-east.json
(painted after 東に続く). Also carries the district bands, the GeoJSON and the
reference page. The route shapes are single clean polylines: no
second-carriageway points in the divided sections, km strictly increasing.

Verified: all 116 ASS events and SRT cues match the LRC's order, text and
timestamps; every sung node in the index joins to the roster at matching km.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PLt25nCVMsoroKALYUBu6u
- Transect.tsx: the dimmed "road ahead" now includes the east continuation
  (274-route-east.json), so it is visible all along instead of appearing only
  once the paint reaches it after 東に続く.
- progress.ts: EAST_RUN_S 4 -> 75. The paint used to dash along the east stub
  (5.25 km in 4 s, about 1.3 km/s, after 0.55 km/s for the leg before it); it now
  takes 75 s from 東に続く, well into the outro.

Verified: eslint + tsc clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PLt25nCVMsoroKALYUBu6u
From SPECTRUM_START_S the nodes stop following the lyric and behave as a
spectrum analyser: every sung node is given one log-spaced frequency band
(40 Hz–12 kHz), dealt out in a seeded shuffle, and sizes up and down with that
band's amplitude.

- spectrum.ts: band maths and every tunable. Levels come from
  @remotion/media-utils visualizeAudio on audio loaded by
  useWindowedAudioData (10 s windows, so the 227 MB WAV is never decoded
  whole; before the outro the window stays parked at its start). Bands average
  the FFT bins they span, or interpolate for bands narrower than a bin, so
  neighbouring bass nodes never move in lockstep. Level =
  (raw × GAIN × (f/40 Hz)^TREBLE_TILT)^CURVE with a release that looks back
  RELEASE_FRAMES frames at RELEASE_DECAY per frame. Defaults were calibrated
  on the release2 outro (nodes pinned at full size 0.6% of the time). The
  node→band mapping uses Remotion's seeded random() (BAND_SEED), not
  Math.random(), so render tabs and the Studio agree.
- nodeAnimation.ts: SPECTRUM_PEAK and spectrumLook(level), alongside lightUp
  and switchOff, plus a levelExponential shaping curve.
- Transect.tsx: hands each node over from its lyric look to its spectrum look
  over SPECTRUM_FADE_S.
- package.json: declare @remotion/media-utils 4.0.522 (already installed as a
  dependency of the CLI; now pinned alongside the other Remotion packages).

Verified: eslint + tsc clean on this commit's tree; outro stills show nodes
sized by band level, so the windowed audio loads during renders.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PLt25nCVMsoroKALYUBu6u
Three pairs of sung nodes have identical roster coordinates, so one circle fully
eclipsed the other: 草木橋 / 滝の上こ線橋, ポン久留喜橋 / 久留喜橋, and
モトツ橋 / モトツシェルター (a bridge roofed by a shelter). Editing the lyrics
index's lat/lon could not fix it: the video takes positions from the roster
(274-lookup.csv), joined on object.

- layout.ts: nodePositions() groups nodes by exact coordinate and spreads each
  group COINCIDENT_SPREAD (1.5 map units, about 35 m) apart along the road's
  direction there, in road order, centred on the shared point. All such pairs
  are on-road structures, so they stay on the road (within 0.06 units) and
  read as a doubled dot; partial overlap is intended, full eclipse is not.
  Along rather than across the road, and small: at 6 units モトツシェルター
  landed on 福山トンネル, 90 m further on.
- data.ts: RosterItem carries the roster's km, for road order and direction.
- Transect.tsx: draws nodes at those positions.

Verified: eslint + tsc clean on this commit's tree; close-ups at モトツ, resting
and lit, show both nodes on the road in order after モトツトンネル.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PLt25nCVMsoroKALYUBu6u
Colour choices for the dark palette, made while previewing in the Studio:
- roadCovered #9dcde4 -> #fdb021 (the covered road now reads amber)
- bridge #79d1c5 -> #9be9de
- place / railway #129252 -> #68ad7f
- shrine #b32c2c -> #a05050
- other #ff9900 -> #a7b7d6

The light palette is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PLt25nCVMsoroKALYUBu6u
mikkeli added 4 commits 2026-09-17 01:32:43 +00:00
- Transect.tsx: the dimmed "road ahead" now includes the east continuation
  (274-route-east.json), so it is visible all along instead of appearing only
  once the paint reaches it after 東に続く.
- progress.ts: EAST_RUN_S 4 -> 75. The paint used to dash along the east stub
  (5.25 km in 4 s, about 1.3 km/s, after 0.55 km/s for the leg before it); it now
  takes 75 s from 東に続く, well into the outro.

Verified: eslint + tsc clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PLt25nCVMsoroKALYUBu6u
From SPECTRUM_START_S the nodes stop following the lyric and behave as a
spectrum analyser: every sung node is given one log-spaced frequency band
(40 Hz–12 kHz), dealt out in a seeded shuffle, and sizes up and down with that
band's amplitude.

- spectrum.ts: band maths and every tunable. Levels come from
  @remotion/media-utils visualizeAudio on audio loaded by
  useWindowedAudioData (10 s windows, so the 227 MB WAV is never decoded
  whole; before the outro the window stays parked at its start). Bands average
  the FFT bins they span, or interpolate for bands narrower than a bin, so
  neighbouring bass nodes never move in lockstep. Level =
  (raw × GAIN × (f/40 Hz)^TREBLE_TILT)^CURVE with a release that looks back
  RELEASE_FRAMES frames at RELEASE_DECAY per frame. Defaults were calibrated
  on the release2 outro (nodes pinned at full size 0.6% of the time). The
  node→band mapping uses Remotion's seeded random() (BAND_SEED), not
  Math.random(), so render tabs and the Studio agree.
- nodeAnimation.ts: SPECTRUM_PEAK and spectrumLook(level), alongside lightUp
  and switchOff, plus a levelExponential shaping curve.
- Transect.tsx: hands each node over from its lyric look to its spectrum look
  over SPECTRUM_FADE_S.
- package.json: declare @remotion/media-utils 4.0.522 (already installed as a
  dependency of the CLI; now pinned alongside the other Remotion packages).

Verified: eslint + tsc clean on this commit's tree; outro stills show nodes
sized by band level, so the windowed audio loads during renders.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PLt25nCVMsoroKALYUBu6u
Three pairs of sung nodes have identical roster coordinates, so one circle fully
eclipsed the other: 草木橋 / 滝の上こ線橋, ポン久留喜橋 / 久留喜橋, and
モトツ橋 / モトツシェルター (a bridge roofed by a shelter). Editing the lyrics
index's lat/lon could not fix it: the video takes positions from the roster
(274-lookup.csv), joined on object.

- layout.ts: nodePositions() groups nodes by exact coordinate and spreads each
  group COINCIDENT_SPREAD (1.5 map units, about 35 m) apart along the road's
  direction there, in road order, centred on the shared point. All such pairs
  are on-road structures, so they stay on the road (within 0.06 units) and
  read as a doubled dot; partial overlap is intended, full eclipse is not.
  Along rather than across the road, and small: at 6 units モトツシェルター
  landed on 福山トンネル, 90 m further on.
- data.ts: RosterItem carries the roster's km, for road order and direction.
- Transect.tsx: draws nodes at those positions.

Verified: eslint + tsc clean on this commit's tree; close-ups at モトツ, resting
and lit, show both nodes on the road in order after モトツトンネル.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PLt25nCVMsoroKALYUBu6u
Colour choices for the dark palette, made while previewing in the Studio:
- roadCovered #9dcde4 -> #fdb021 (the covered road now reads amber)
- bridge #79d1c5 -> #9be9de
- place / railway #129252 -> #68ad7f
- shrine #b32c2c -> #a05050
- other #ff9900 -> #a7b7d6

The light palette is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PLt25nCVMsoroKALYUBu6u
mikkeli merged commit 2731d9d332 into song274/master 2026-09-17 01:36:54 +00:00
mikkeli deleted branch song274/transect 2026-09-17 01:38:27 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mikkeli/ncmr-songs-videos#1