274: transect composition, spectrum outro, and lyric fixes it exposed #1
@@ -6,6 +6,7 @@
|
|||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@remotion/cli": "4.0.522",
|
"@remotion/cli": "4.0.522",
|
||||||
|
"@remotion/media-utils": "4.0.522",
|
||||||
"@remotion/tailwind-v4": "4.0.522",
|
"@remotion/tailwind-v4": "4.0.522",
|
||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
"react-dom": "19.2.3",
|
"react-dom": "19.2.3",
|
||||||
|
|||||||
@@ -12,3 +12,6 @@ Config.setRspack(true);
|
|||||||
Config.setVideoImageFormat("jpeg");
|
Config.setVideoImageFormat("jpeg");
|
||||||
Config.setOverwriteOutput(true);
|
Config.setOverwriteOutput(true);
|
||||||
Config.overrideBundlerConfig(enableTailwind);
|
Config.overrideBundlerConfig(enableTailwind);
|
||||||
|
// Song branch: staticFile() paths resolve inside the song folder, so compositions
|
||||||
|
// read audio/, fonts/ and route/ where they already live instead of a copy.
|
||||||
|
Config.setPublicDir("song-274");
|
||||||
|
|||||||
+21
-22
@@ -62,7 +62,7 @@ Dialogue: 0,0:00:59.95,0:01:03.47,transparent_lyrics_en,,0,0,0,,滝の上発電
|
|||||||
Dialogue: 0,0:01:03.47,0:01:06.94,transparent_lyrics_en,,0,0,0,,滝ノ上信号場
|
Dialogue: 0,0:01:03.47,0:01:06.94,transparent_lyrics_en,,0,0,0,,滝ノ上信号場
|
||||||
Dialogue: 0,0:01:06.94,0:01:08.78,transparent_lyrics_en,,0,0,0,,滝ノ上神社
|
Dialogue: 0,0:01:06.94,0:01:08.78,transparent_lyrics_en,,0,0,0,,滝ノ上神社
|
||||||
Dialogue: 0,0:01:08.78,0:01:10.50,transparent_lyrics_en,,0,0,0,,
|
Dialogue: 0,0:01:08.78,0:01:10.50,transparent_lyrics_en,,0,0,0,,
|
||||||
Dialogue: 0,0:01:10.50,0:01:46.47,transparent_title,,0,0,0,,夕張市紅葉山
|
Dialogue: 0,0:01:10.50,0:01:45.03,transparent_title,,0,0,0,,夕張市紅葉山
|
||||||
Dialogue: 0,0:01:12.05,0:01:13.86,transparent_lyrics_en,,0,0,0,,十三里信号場
|
Dialogue: 0,0:01:12.05,0:01:13.86,transparent_lyrics_en,,0,0,0,,十三里信号場
|
||||||
Dialogue: 0,0:01:13.86,0:01:16.44,transparent_lyrics_en,,0,0,0,,十三里橋
|
Dialogue: 0,0:01:13.86,0:01:16.44,transparent_lyrics_en,,0,0,0,,十三里橋
|
||||||
Dialogue: 0,0:01:16.44,0:01:18.78,transparent_lyrics_en,,0,0,0,,紅葉山駐車帯
|
Dialogue: 0,0:01:16.44,0:01:18.78,transparent_lyrics_en,,0,0,0,,紅葉山駐車帯
|
||||||
@@ -71,27 +71,26 @@ Dialogue: 0,0:01:21.06,0:01:24.44,transparent_lyrics_en,,0,0,0,,セブンイレ
|
|||||||
Dialogue: 0,0:01:24.44,0:01:27.06,transparent_lyrics_en,,0,0,0,,新夕張駅
|
Dialogue: 0,0:01:24.44,0:01:27.06,transparent_lyrics_en,,0,0,0,,新夕張駅
|
||||||
Dialogue: 0,0:01:27.06,0:01:30.02,transparent_lyrics_en,,0,0,0,,紅葉山郵便局
|
Dialogue: 0,0:01:27.06,0:01:30.02,transparent_lyrics_en,,0,0,0,,紅葉山郵便局
|
||||||
Dialogue: 0,0:01:30.02,0:01:32.30,transparent_lyrics_en,,0,0,0,,紅葉山神社
|
Dialogue: 0,0:01:30.02,0:01:32.30,transparent_lyrics_en,,0,0,0,,紅葉山神社
|
||||||
Dialogue: 0,0:01:32.30,0:01:35.42,transparent_lyrics_en,,0,0,0,,セイコーマートもみじやま店
|
Dialogue: 0,0:01:32.30,0:01:35.24,transparent_lyrics_en,,0,0,0,,セイコーマートもみじやま店
|
||||||
Dialogue: 0,0:01:35.42,0:01:37.92,transparent_lyrics_en,,0,0,0,,紅葉山橋
|
Dialogue: 0,0:01:35.24,0:01:38.48,transparent_lyrics_en,,0,0,0,,紅楓橋
|
||||||
Dialogue: 0,0:01:37.92,0:01:39.46,transparent_lyrics_en,,0,0,0,,紅楓橋
|
Dialogue: 0,0:01:38.48,0:01:40.25,transparent_lyrics_en,,0,0,0,,ポン久留喜橋
|
||||||
Dialogue: 0,0:01:39.46,0:01:41.54,transparent_lyrics_en,,0,0,0,,ポン久留喜橋
|
Dialogue: 0,0:01:40.25,0:01:42.44,transparent_lyrics_en,,0,0,0,,久留喜橋
|
||||||
Dialogue: 0,0:01:41.54,0:01:43.84,transparent_lyrics_en,,0,0,0,,久留喜橋
|
Dialogue: 0,0:01:42.44,0:01:43.79,transparent_lyrics_en,,0,0,0,,楓橋
|
||||||
Dialogue: 0,0:01:43.84,0:01:45.05,transparent_lyrics_en,,0,0,0,,楓橋
|
Dialogue: 0,0:01:43.79,0:01:45.03,transparent_lyrics_en,,0,0,0,,桂橋
|
||||||
Dialogue: 0,0:01:45.05,0:01:46.47,transparent_lyrics_en,,0,0,0,,桂橋
|
Dialogue: 0,0:01:45.03,0:01:45.77,transparent_lyrics_en,,0,0,0,,
|
||||||
Dialogue: 0,0:01:46.47,0:01:46.84,transparent_lyrics_en,,0,0,0,,
|
Dialogue: 0,0:01:45.77,0:02:00.74,transparent_title,,0,0,0,,夕張市楓
|
||||||
Dialogue: 0,0:01:46.84,0:02:00.74,transparent_title,,0,0,0,,夕張市楓
|
Dialogue: 0,0:01:49.12,0:01:50.76,transparent_lyrics_en,,0,0,0,,千紫橋
|
||||||
Dialogue: 0,0:01:48.90,0:01:50.84,transparent_lyrics_en,,0,0,0,,千紫橋
|
Dialogue: 0,0:01:50.76,0:01:52.51,transparent_lyrics_en,,0,0,0,,楓駐車帯
|
||||||
Dialogue: 0,0:01:50.84,0:01:52.07,transparent_lyrics_en,,0,0,0,,楓駐車帯
|
Dialogue: 0,0:01:52.51,0:01:53.80,transparent_lyrics_en,,0,0,0,,万紅橋
|
||||||
Dialogue: 0,0:01:52.07,0:01:53.93,transparent_lyrics_en,,0,0,0,,万紅橋
|
Dialogue: 0,0:01:53.80,0:01:55.54,transparent_lyrics_en,,0,0,0,,登川神社
|
||||||
Dialogue: 0,0:01:53.93,0:01:55.61,transparent_lyrics_en,,0,0,0,,登川神社
|
Dialogue: 0,0:01:55.54,0:01:57.32,transparent_lyrics_en,,0,0,0,,楓信号場
|
||||||
Dialogue: 0,0:01:55.61,0:01:57.32,transparent_lyrics_en,,0,0,0,,楓信号場
|
|
||||||
Dialogue: 0,0:01:57.32,0:01:59.00,transparent_lyrics_en,,0,0,0,,登川橋
|
Dialogue: 0,0:01:57.32,0:01:59.00,transparent_lyrics_en,,0,0,0,,登川橋
|
||||||
Dialogue: 0,0:01:59.00,0:02:00.74,transparent_lyrics_en,,0,0,0,,登川郵便局
|
Dialogue: 0,0:01:59.00,0:02:00.74,transparent_lyrics_en,,0,0,0,,登川郵便局
|
||||||
Dialogue: 0,0:02:00.74,0:02:01.26,transparent_lyrics_en,,0,0,0,,
|
Dialogue: 0,0:02:00.74,0:02:01.26,transparent_lyrics_en,,0,0,0,,
|
||||||
Dialogue: 0,0:02:01.26,0:02:06.63,transparent_title,,0,0,0,,夕張市登川
|
Dialogue: 0,0:02:01.26,0:02:06.62,transparent_title,,0,0,0,,夕張市登川
|
||||||
Dialogue: 0,0:02:02.93,0:02:04.87,transparent_lyrics_en,,0,0,0,,花園橋
|
Dialogue: 0,0:02:02.93,0:02:05.23,transparent_lyrics_en,,0,0,0,,花園橋
|
||||||
Dialogue: 0,0:02:04.87,0:02:06.63,transparent_lyrics_en,,0,0,0,,登川トンネル
|
Dialogue: 0,0:02:05.23,0:02:06.62,transparent_lyrics_en,,0,0,0,,登川トンネル
|
||||||
Dialogue: 0,0:02:06.63,0:03:30.80,transparent_lyrics_en,,0,0,0,,
|
Dialogue: 0,0:02:06.62,0:03:30.80,transparent_lyrics_en,,0,0,0,,
|
||||||
Dialogue: 0,0:03:30.80,0:03:39.41,transparent_title,,0,0,0,,勇払郡むかわ町穂別長和
|
Dialogue: 0,0:03:30.80,0:03:39.41,transparent_title,,0,0,0,,勇払郡むかわ町穂別長和
|
||||||
Dialogue: 0,0:03:34.55,0:03:36.77,transparent_lyrics_en,,0,0,0,,オマナイ橋
|
Dialogue: 0,0:03:34.55,0:03:36.77,transparent_lyrics_en,,0,0,0,,オマナイ橋
|
||||||
Dialogue: 0,0:03:36.77,0:03:39.41,transparent_lyrics_en,,0,0,0,,桂木橋
|
Dialogue: 0,0:03:36.77,0:03:39.41,transparent_lyrics_en,,0,0,0,,桂木橋
|
||||||
@@ -107,13 +106,13 @@ Dialogue: 0,0:03:57.78,0:04:01.08,transparent_lyrics_en,,0,0,0,,稲里簡易郵
|
|||||||
Dialogue: 0,0:04:01.08,0:04:03.50,transparent_lyrics_en,,0,0,0,,佐主橋
|
Dialogue: 0,0:04:01.08,0:04:03.50,transparent_lyrics_en,,0,0,0,,佐主橋
|
||||||
Dialogue: 0,0:04:03.50,0:04:05.59,transparent_lyrics_en,,0,0,0,,穂別ダム神社
|
Dialogue: 0,0:04:03.50,0:04:05.59,transparent_lyrics_en,,0,0,0,,穂別ダム神社
|
||||||
Dialogue: 0,0:04:05.59,0:04:05.96,transparent_lyrics_en,,0,0,0,,
|
Dialogue: 0,0:04:05.59,0:04:05.96,transparent_lyrics_en,,0,0,0,,
|
||||||
Dialogue: 0,0:04:05.96,0:04:24.97,transparent_title,,0,0,0,,勇払郡むかわ町穂別長和
|
Dialogue: 0,0:04:05.96,0:04:25.27,transparent_title,,0,0,0,,勇払郡むかわ町穂別長和
|
||||||
Dialogue: 0,0:04:10.08,0:04:13.02,transparent_lyrics_en,,0,0,0,,長和トンネル
|
Dialogue: 0,0:04:10.08,0:04:13.02,transparent_lyrics_en,,0,0,0,,長和トンネル
|
||||||
Dialogue: 0,0:04:13.02,0:04:15.39,transparent_lyrics_en,,0,0,0,,穂別大橋
|
Dialogue: 0,0:04:13.02,0:04:15.39,transparent_lyrics_en,,0,0,0,,穂別大橋
|
||||||
Dialogue: 0,0:04:15.39,0:04:18.81,transparent_lyrics_en,,0,0,0,,山水橋
|
Dialogue: 0,0:04:15.39,0:04:18.81,transparent_lyrics_en,,0,0,0,,山水橋
|
||||||
Dialogue: 0,0:04:18.81,0:04:23.20,transparent_lyrics_en,,0,0,0,,沼の沢橋
|
Dialogue: 0,0:04:18.81,0:04:23.20,transparent_lyrics_en,,0,0,0,,沼の沢橋
|
||||||
Dialogue: 0,0:04:23.20,0:04:24.97,transparent_lyrics_en,,0,0,0,,稲里トンネル
|
Dialogue: 0,0:04:23.20,0:04:25.27,transparent_lyrics_en,,0,0,0,,稲里トンネル
|
||||||
Dialogue: 0,0:04:24.97,0:04:26.00,transparent_lyrics_en,,0,0,0,,
|
Dialogue: 0,0:04:25.27,0:04:26.00,transparent_lyrics_en,,0,0,0,,
|
||||||
Dialogue: 0,0:04:26.00,0:04:55.52,transparent_title,,0,0,0,,勇払郡むかわ町穂別福山
|
Dialogue: 0,0:04:26.00,0:04:55.52,transparent_title,,0,0,0,,勇払郡むかわ町穂別福山
|
||||||
Dialogue: 0,0:04:29.74,0:04:31.50,transparent_lyrics_en,,0,0,0,,ペンケ橋
|
Dialogue: 0,0:04:29.74,0:04:31.50,transparent_lyrics_en,,0,0,0,,ペンケ橋
|
||||||
Dialogue: 0,0:04:31.50,0:04:33.62,transparent_lyrics_en,,0,0,0,,下福山橋
|
Dialogue: 0,0:04:31.50,0:04:33.62,transparent_lyrics_en,,0,0,0,,下福山橋
|
||||||
|
|||||||
+16
-16
@@ -2,6 +2,7 @@
|
|||||||
[ar:Northwich committee of magic researches]
|
[ar:Northwich committee of magic researches]
|
||||||
[al:Shirakaba Express Service]
|
[al:Shirakaba Express Service]
|
||||||
|
|
||||||
|
|
||||||
[00:14.54]夕張郡由仁町川端
|
[00:14.54]夕張郡由仁町川端
|
||||||
[00:17.89]川端橋
|
[00:17.89]川端橋
|
||||||
[00:19.67]
|
[00:19.67]
|
||||||
@@ -33,26 +34,25 @@
|
|||||||
[01:27.06]紅葉山郵便局
|
[01:27.06]紅葉山郵便局
|
||||||
[01:30.02]紅葉山神社
|
[01:30.02]紅葉山神社
|
||||||
[01:32.30]セイコーマートもみじやま店
|
[01:32.30]セイコーマートもみじやま店
|
||||||
[01:35.42]紅葉山橋
|
[01:35.24]紅楓橋
|
||||||
[01:37.92]紅楓橋
|
[01:38.48]ポン久留喜橋
|
||||||
[01:39.46]ポン久留喜橋
|
[01:40.25]久留喜橋
|
||||||
[01:41.54]久留喜橋
|
[01:42.44]楓橋
|
||||||
[01:43.84]楓橋
|
[01:43.79]桂橋
|
||||||
[01:45.05]桂橋
|
[01:45.03]
|
||||||
[01:46.47]
|
[01:45.77]夕張市楓
|
||||||
[01:46.84]夕張市楓
|
[01:49.12]千紫橋
|
||||||
[01:48.90]千紫橋
|
[01:50.76]楓駐車帯
|
||||||
[01:50.84]楓駐車帯
|
[01:52.51]万紅橋
|
||||||
[01:52.07]万紅橋
|
[01:53.80]登川神社
|
||||||
[01:53.93]登川神社
|
[01:55.54]楓信号場
|
||||||
[01:55.61]楓信号場
|
|
||||||
[01:57.32]登川橋
|
[01:57.32]登川橋
|
||||||
[01:59.00]登川郵便局
|
[01:59.00]登川郵便局
|
||||||
[02:00.74]
|
[02:00.74]
|
||||||
[02:01.26]夕張市登川
|
[02:01.26]夕張市登川
|
||||||
[02:02.93]花園橋
|
[02:02.93]花園橋
|
||||||
[02:04.87]登川トンネル
|
[02:05.23]登川トンネル
|
||||||
[02:06.63]
|
[02:06.62]
|
||||||
[03:30.80]勇払郡むかわ町穂別長和
|
[03:30.80]勇払郡むかわ町穂別長和
|
||||||
[03:34.55]オマナイ橋
|
[03:34.55]オマナイ橋
|
||||||
[03:36.77]桂木橋
|
[03:36.77]桂木橋
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
[04:15.39]山水橋
|
[04:15.39]山水橋
|
||||||
[04:18.81]沼の沢橋
|
[04:18.81]沼の沢橋
|
||||||
[04:23.20]稲里トンネル
|
[04:23.20]稲里トンネル
|
||||||
[04:24.97]
|
[04:25.27]
|
||||||
[04:26.00]勇払郡むかわ町穂別福山
|
[04:26.00]勇払郡むかわ町穂別福山
|
||||||
[04:29.74]ペンケ橋
|
[04:29.74]ペンケ橋
|
||||||
[04:31.50]下福山橋
|
[04:31.50]下福山橋
|
||||||
|
|||||||
+105
-109
@@ -119,349 +119,345 @@
|
|||||||
紅葉山神社
|
紅葉山神社
|
||||||
|
|
||||||
31
|
31
|
||||||
00:01:32,300 --> 00:01:35,420
|
00:01:32,300 --> 00:01:35,240
|
||||||
セイコーマートもみじやま店
|
セイコーマートもみじやま店
|
||||||
|
|
||||||
32
|
32
|
||||||
00:01:35,420 --> 00:01:37,920
|
00:01:35,240 --> 00:01:38,480
|
||||||
紅葉山橋
|
|
||||||
|
|
||||||
33
|
|
||||||
00:01:37,920 --> 00:01:39,460
|
|
||||||
紅楓橋
|
紅楓橋
|
||||||
|
|
||||||
34
|
33
|
||||||
00:01:39,460 --> 00:01:41,540
|
00:01:38,480 --> 00:01:40,250
|
||||||
ポン久留喜橋
|
ポン久留喜橋
|
||||||
|
|
||||||
35
|
34
|
||||||
00:01:41,540 --> 00:01:43,840
|
00:01:40,250 --> 00:01:42,440
|
||||||
久留喜橋
|
久留喜橋
|
||||||
|
|
||||||
36
|
35
|
||||||
00:01:43,840 --> 00:01:45,050
|
00:01:42,440 --> 00:01:43,790
|
||||||
楓橋
|
楓橋
|
||||||
|
|
||||||
37
|
36
|
||||||
00:01:45,050 --> 00:01:46,470
|
00:01:43,790 --> 00:01:45,030
|
||||||
桂橋
|
桂橋
|
||||||
|
|
||||||
|
37
|
||||||
|
00:01:45,030 --> 00:01:45,770
|
||||||
|
|
||||||
|
|
||||||
38
|
38
|
||||||
00:01:46,470 --> 00:01:46,970
|
00:01:45,770 --> 00:01:49,120
|
||||||
|
|
||||||
|
|
||||||
39
|
|
||||||
00:01:46,840 --> 00:01:48,900
|
|
||||||
夕張市楓
|
夕張市楓
|
||||||
|
|
||||||
40
|
39
|
||||||
00:01:48,900 --> 00:01:50,840
|
00:01:49,120 --> 00:01:50,760
|
||||||
千紫橋
|
千紫橋
|
||||||
|
|
||||||
41
|
40
|
||||||
00:01:50,840 --> 00:01:52,070
|
00:01:50,760 --> 00:01:52,510
|
||||||
楓駐車帯
|
楓駐車帯
|
||||||
|
|
||||||
42
|
41
|
||||||
00:01:52,070 --> 00:01:53,930
|
00:01:52,510 --> 00:01:53,800
|
||||||
万紅橋
|
万紅橋
|
||||||
|
|
||||||
43
|
42
|
||||||
00:01:53,930 --> 00:01:55,610
|
00:01:53,800 --> 00:01:55,540
|
||||||
登川神社
|
登川神社
|
||||||
|
|
||||||
44
|
43
|
||||||
00:01:55,610 --> 00:01:57,320
|
00:01:55,540 --> 00:01:57,320
|
||||||
楓信号場
|
楓信号場
|
||||||
|
|
||||||
45
|
44
|
||||||
00:01:57,320 --> 00:01:59,000
|
00:01:57,320 --> 00:01:59,000
|
||||||
登川橋
|
登川橋
|
||||||
|
|
||||||
46
|
45
|
||||||
00:01:59,000 --> 00:02:00,740
|
00:01:59,000 --> 00:02:00,740
|
||||||
登川郵便局
|
登川郵便局
|
||||||
|
|
||||||
47
|
46
|
||||||
00:02:00,740 --> 00:02:01,260
|
00:02:00,740 --> 00:02:01,260
|
||||||
|
|
||||||
|
|
||||||
48
|
47
|
||||||
00:02:01,260 --> 00:02:02,930
|
00:02:01,260 --> 00:02:02,930
|
||||||
夕張市登川
|
夕張市登川
|
||||||
|
|
||||||
49
|
48
|
||||||
00:02:02,930 --> 00:02:04,870
|
00:02:02,930 --> 00:02:05,230
|
||||||
花園橋
|
花園橋
|
||||||
|
|
||||||
50
|
49
|
||||||
00:02:04,870 --> 00:02:06,630
|
00:02:05,230 --> 00:02:06,620
|
||||||
登川トンネル
|
登川トンネル
|
||||||
|
|
||||||
|
50
|
||||||
|
00:02:06,620 --> 00:03:30,800
|
||||||
|
|
||||||
|
|
||||||
51
|
51
|
||||||
00:02:06,630 --> 00:03:30,800
|
|
||||||
|
|
||||||
|
|
||||||
52
|
|
||||||
00:03:30,800 --> 00:03:34,550
|
00:03:30,800 --> 00:03:34,550
|
||||||
勇払郡むかわ町穂別長和
|
勇払郡むかわ町穂別長和
|
||||||
|
|
||||||
53
|
52
|
||||||
00:03:34,550 --> 00:03:36,770
|
00:03:34,550 --> 00:03:36,770
|
||||||
オマナイ橋
|
オマナイ橋
|
||||||
|
|
||||||
54
|
53
|
||||||
00:03:36,770 --> 00:03:39,410
|
00:03:36,770 --> 00:03:39,410
|
||||||
桂木橋
|
桂木橋
|
||||||
|
|
||||||
55
|
54
|
||||||
00:03:39,410 --> 00:03:41,130
|
00:03:39,410 --> 00:03:41,130
|
||||||
|
|
||||||
|
|
||||||
56
|
55
|
||||||
00:03:41,130 --> 00:03:44,620
|
00:03:41,130 --> 00:03:44,620
|
||||||
勇払郡むかわ町穂別稲里
|
勇払郡むかわ町穂別稲里
|
||||||
|
|
||||||
57
|
56
|
||||||
00:03:44,620 --> 00:03:46,670
|
00:03:44,620 --> 00:03:46,670
|
||||||
大和橋
|
大和橋
|
||||||
|
|
||||||
58
|
57
|
||||||
00:03:46,670 --> 00:03:48,380
|
00:03:46,670 --> 00:03:48,380
|
||||||
豊進橋
|
豊進橋
|
||||||
|
|
||||||
59
|
58
|
||||||
00:03:48,380 --> 00:03:51,610
|
00:03:48,380 --> 00:03:51,610
|
||||||
豊進神社
|
豊進神社
|
||||||
|
|
||||||
60
|
59
|
||||||
00:03:51,610 --> 00:03:53,140
|
00:03:51,610 --> 00:03:53,140
|
||||||
豊里橋
|
豊里橋
|
||||||
|
|
||||||
61
|
60
|
||||||
00:03:53,140 --> 00:03:55,520
|
00:03:53,140 --> 00:03:55,520
|
||||||
稲豊橋
|
稲豊橋
|
||||||
|
|
||||||
62
|
61
|
||||||
00:03:55,520 --> 00:03:57,780
|
00:03:55,520 --> 00:03:57,780
|
||||||
稲里橋
|
稲里橋
|
||||||
|
|
||||||
63
|
62
|
||||||
00:03:57,780 --> 00:04:01,080
|
00:03:57,780 --> 00:04:01,080
|
||||||
稲里簡易郵便局
|
稲里簡易郵便局
|
||||||
|
|
||||||
64
|
63
|
||||||
00:04:01,080 --> 00:04:03,500
|
00:04:01,080 --> 00:04:03,500
|
||||||
佐主橋
|
佐主橋
|
||||||
|
|
||||||
65
|
64
|
||||||
00:04:03,500 --> 00:04:05,590
|
00:04:03,500 --> 00:04:05,590
|
||||||
穂別ダム神社
|
穂別ダム神社
|
||||||
|
|
||||||
66
|
65
|
||||||
00:04:05,590 --> 00:04:06,090
|
00:04:05,590 --> 00:04:06,090
|
||||||
|
|
||||||
|
|
||||||
67
|
66
|
||||||
00:04:05,960 --> 00:04:10,080
|
00:04:05,960 --> 00:04:10,080
|
||||||
勇払郡むかわ町穂別長和
|
勇払郡むかわ町穂別長和
|
||||||
|
|
||||||
68
|
67
|
||||||
00:04:10,080 --> 00:04:13,020
|
00:04:10,080 --> 00:04:13,020
|
||||||
長和トンネル
|
長和トンネル
|
||||||
|
|
||||||
69
|
68
|
||||||
00:04:13,020 --> 00:04:15,390
|
00:04:13,020 --> 00:04:15,390
|
||||||
穂別大橋
|
穂別大橋
|
||||||
|
|
||||||
70
|
69
|
||||||
00:04:15,390 --> 00:04:18,810
|
00:04:15,390 --> 00:04:18,810
|
||||||
山水橋
|
山水橋
|
||||||
|
|
||||||
71
|
70
|
||||||
00:04:18,810 --> 00:04:23,200
|
00:04:18,810 --> 00:04:23,200
|
||||||
沼の沢橋
|
沼の沢橋
|
||||||
|
|
||||||
72
|
71
|
||||||
00:04:23,200 --> 00:04:24,970
|
00:04:23,200 --> 00:04:25,270
|
||||||
稲里トンネル
|
稲里トンネル
|
||||||
|
|
||||||
|
72
|
||||||
|
00:04:25,270 --> 00:04:26,000
|
||||||
|
|
||||||
|
|
||||||
73
|
73
|
||||||
00:04:24,970 --> 00:04:26,000
|
|
||||||
|
|
||||||
|
|
||||||
74
|
|
||||||
00:04:26,000 --> 00:04:29,740
|
00:04:26,000 --> 00:04:29,740
|
||||||
勇払郡むかわ町穂別福山
|
勇払郡むかわ町穂別福山
|
||||||
|
|
||||||
75
|
74
|
||||||
00:04:29,740 --> 00:04:31,500
|
00:04:29,740 --> 00:04:31,500
|
||||||
ペンケ橋
|
ペンケ橋
|
||||||
|
|
||||||
76
|
75
|
||||||
00:04:31,500 --> 00:04:33,620
|
00:04:31,500 --> 00:04:33,620
|
||||||
下福山橋
|
下福山橋
|
||||||
|
|
||||||
77
|
76
|
||||||
00:04:33,620 --> 00:04:35,020
|
00:04:33,620 --> 00:04:35,020
|
||||||
オロロップ橋
|
オロロップ橋
|
||||||
|
|
||||||
78
|
77
|
||||||
00:04:35,020 --> 00:04:37,070
|
00:04:35,020 --> 00:04:37,070
|
||||||
福山橋
|
福山橋
|
||||||
|
|
||||||
79
|
78
|
||||||
00:04:37,070 --> 00:04:38,700
|
00:04:37,070 --> 00:04:38,700
|
||||||
福山神社
|
福山神社
|
||||||
|
|
||||||
80
|
79
|
||||||
00:04:38,700 --> 00:04:41,020
|
00:04:38,700 --> 00:04:41,020
|
||||||
福山大橋
|
福山大橋
|
||||||
|
|
||||||
81
|
80
|
||||||
00:04:41,020 --> 00:04:43,290
|
00:04:41,020 --> 00:04:43,290
|
||||||
千坂橋
|
千坂橋
|
||||||
|
|
||||||
82
|
81
|
||||||
00:04:43,290 --> 00:04:45,120
|
00:04:43,290 --> 00:04:45,120
|
||||||
オコタン橋
|
オコタン橋
|
||||||
|
|
||||||
83
|
82
|
||||||
00:04:45,120 --> 00:04:46,220
|
00:04:45,120 --> 00:04:46,220
|
||||||
モトツトンネル
|
モトツトンネル
|
||||||
|
|
||||||
84
|
83
|
||||||
00:04:46,220 --> 00:04:48,980
|
00:04:46,220 --> 00:04:48,980
|
||||||
モトツ橋にモトツシェルター
|
モトツ橋にモトツシェルター
|
||||||
|
|
||||||
85
|
84
|
||||||
00:04:48,980 --> 00:04:51,390
|
00:04:48,980 --> 00:04:51,390
|
||||||
福山トンネル
|
福山トンネル
|
||||||
|
|
||||||
86
|
85
|
||||||
00:04:51,390 --> 00:04:53,610
|
00:04:51,390 --> 00:04:53,610
|
||||||
福穂橋
|
福穂橋
|
||||||
|
|
||||||
87
|
86
|
||||||
00:04:53,610 --> 00:04:55,520
|
00:04:53,610 --> 00:04:55,520
|
||||||
穂高トンネル
|
穂高トンネル
|
||||||
|
|
||||||
88
|
87
|
||||||
00:04:55,520 --> 00:05:22,600
|
00:04:55,520 --> 00:05:22,600
|
||||||
|
|
||||||
|
|
||||||
89
|
88
|
||||||
00:05:22,600 --> 00:05:25,760
|
00:05:22,600 --> 00:05:25,760
|
||||||
勇払郡占冠村中央
|
勇払郡占冠村中央
|
||||||
|
|
||||||
90
|
89
|
||||||
00:05:25,760 --> 00:05:28,880
|
00:05:25,760 --> 00:05:28,880
|
||||||
穂高橋
|
穂高橋
|
||||||
|
|
||||||
91
|
90
|
||||||
00:05:28,880 --> 00:05:31,520
|
00:05:28,880 --> 00:05:31,520
|
||||||
高翠橋
|
高翠橋
|
||||||
|
|
||||||
92
|
91
|
||||||
00:05:31,520 --> 00:05:34,950
|
00:05:31,520 --> 00:05:34,950
|
||||||
占翠橋
|
占翠橋
|
||||||
|
|
||||||
93
|
92
|
||||||
00:05:34,950 --> 00:05:38,080
|
00:05:34,950 --> 00:05:38,080
|
||||||
名石駐車場
|
名石駐車場
|
||||||
|
|
||||||
94
|
93
|
||||||
00:05:38,080 --> 00:05:40,990
|
00:05:38,080 --> 00:05:40,990
|
||||||
名石橋
|
名石橋
|
||||||
|
|
||||||
95
|
94
|
||||||
00:05:40,990 --> 00:05:43,960
|
00:05:40,990 --> 00:05:43,960
|
||||||
赤岩大橋
|
赤岩大橋
|
||||||
|
|
||||||
96
|
95
|
||||||
00:05:43,960 --> 00:05:48,620
|
00:05:43,960 --> 00:05:48,620
|
||||||
渓流大橋
|
渓流大橋
|
||||||
|
|
||||||
97
|
96
|
||||||
00:05:48,620 --> 00:05:50,730
|
00:05:48,620 --> 00:05:50,730
|
||||||
日高トンネル
|
日高トンネル
|
||||||
|
|
||||||
98
|
97
|
||||||
00:05:50,730 --> 00:07:11,390
|
00:05:50,730 --> 00:07:11,390
|
||||||
|
|
||||||
|
|
||||||
99
|
98
|
||||||
00:07:11,390 --> 00:07:14,140
|
00:07:11,390 --> 00:07:14,140
|
||||||
沙流郡日高町日高
|
沙流郡日高町日高
|
||||||
|
|
||||||
100
|
99
|
||||||
00:07:14,140 --> 00:07:16,380
|
00:07:14,140 --> 00:07:16,380
|
||||||
日夕橋
|
日夕橋
|
||||||
|
|
||||||
101
|
100
|
||||||
00:07:16,380 --> 00:07:28,850
|
00:07:16,380 --> 00:07:28,850
|
||||||
|
|
||||||
|
|
||||||
102
|
101
|
||||||
00:07:28,850 --> 00:07:31,680
|
00:07:28,850 --> 00:07:31,680
|
||||||
沙流郡日高町宮下町
|
沙流郡日高町宮下町
|
||||||
|
|
||||||
103
|
102
|
||||||
00:07:31,680 --> 00:07:34,090
|
00:07:31,680 --> 00:07:34,090
|
||||||
日高神社
|
日高神社
|
||||||
|
|
||||||
104
|
103
|
||||||
00:07:34,090 --> 00:07:42,900
|
00:07:34,090 --> 00:07:42,900
|
||||||
|
|
||||||
|
|
||||||
105
|
104
|
||||||
00:07:42,900 --> 00:07:45,510
|
00:07:42,900 --> 00:07:45,510
|
||||||
沙流郡日高町本町東
|
沙流郡日高町本町東
|
||||||
|
|
||||||
106
|
105
|
||||||
00:07:45,510 --> 00:07:49,880
|
00:07:45,510 --> 00:07:49,880
|
||||||
新川橋
|
新川橋
|
||||||
|
|
||||||
107
|
106
|
||||||
00:07:49,880 --> 00:07:52,760
|
00:07:49,880 --> 00:07:52,760
|
||||||
セイコーマート日高道の駅店
|
セイコーマート日高道の駅店
|
||||||
|
|
||||||
108
|
107
|
||||||
00:07:52,760 --> 00:07:55,110
|
00:07:52,760 --> 00:07:55,110
|
||||||
日高郵便局
|
日高郵便局
|
||||||
|
|
||||||
109
|
108
|
||||||
00:07:55,110 --> 00:07:56,690
|
00:07:55,110 --> 00:07:56,690
|
||||||
|
|
||||||
|
|
||||||
110
|
109
|
||||||
00:07:56,690 --> 00:07:59,360
|
00:07:56,690 --> 00:07:59,360
|
||||||
沙流郡日高町千栄
|
沙流郡日高町千栄
|
||||||
|
|
||||||
111
|
110
|
||||||
00:07:59,360 --> 00:08:02,150
|
00:07:59,360 --> 00:08:02,150
|
||||||
北電日高発電所
|
北電日高発電所
|
||||||
|
|
||||||
112
|
111
|
||||||
00:08:02,150 --> 00:08:03,900
|
00:08:02,150 --> 00:08:03,900
|
||||||
|
|
||||||
|
|
||||||
113
|
112
|
||||||
00:08:03,900 --> 00:08:06,380
|
00:08:03,900 --> 00:08:06,380
|
||||||
沙流郡日高町日高
|
沙流郡日高町日高
|
||||||
|
|
||||||
114
|
113
|
||||||
00:08:06,380 --> 00:08:09,440
|
00:08:06,380 --> 00:08:09,440
|
||||||
右左府発電所
|
右左府発電所
|
||||||
|
|
||||||
115
|
114
|
||||||
00:08:09,440 --> 00:08:10,930
|
00:08:09,440 --> 00:08:10,930
|
||||||
|
|
||||||
|
|
||||||
116
|
115
|
||||||
00:08:10,930 --> 00:08:12,660
|
00:08:10,930 --> 00:08:12,660
|
||||||
東に続く
|
東に続く
|
||||||
|
|
||||||
117
|
116
|
||||||
00:08:12,660 --> 00:08:17,660
|
00:08:12,660 --> 00:08:17,660
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -1,12 +1,13 @@
|
|||||||
# Bill of materials — 274
|
# Bill of materials — 274
|
||||||
|
|
||||||
4 file(s), 238.8 MiB. Generated by `scripts/bom_gen.py`.
|
5 file(s), 465.6 MiB. Generated by `scripts/bom_gen.py`.
|
||||||
|
|
||||||
## audio
|
## audio
|
||||||
|
|
||||||
file size hash description
|
file size hash description
|
||||||
------------------------ --------- -------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------
|
------------------------ --------- -------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
`audio/274_release1.wav` 226.8 MiB `4287774b506177d282b8a035` Release master of "274" (updated 2026-09-16, replaces 274_release.wav) — stereo, 48 kHz, 32-bit float PCM, 10:19 (619.27 s). Peak -0.4 dBFS, mean -12.4 dBFS.
|
`audio/274_release1.wav` 226.8 MiB `4287774b506177d282b8a035` Release master of "274" (2026-09-16), superseded by 274_release2.wav — stereo, 48 kHz, 32-bit float PCM, 10:19 (619.27 s). Peak -0.4 dBFS, mean -12.4 dBFS.
|
||||||
|
`audio/274_release2.wav` 226.8 MiB `834aad4988f387dd9871d099` Release master of "274" (updated 2026-09-17, replaces 274_release1.wav; used by the white/lyrics renders and Song274Transect) — stereo, 48 kHz, 32-bit float PCM, 10:19 (619.27 s). Float peak +0.25 dBFS (1.0297; 25 samples beyond full scale), mean -13.1 dBFS.
|
||||||
|
|
||||||
## images
|
## images
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"frm": 36.5,
|
||||||
|
"to": 38.25,
|
||||||
|
"code": "01427",
|
||||||
|
"city": "夕張郡由仁町",
|
||||||
|
"lv": "川端",
|
||||||
|
"kana": "かわばた"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 38.5,
|
||||||
|
"to": 42.0,
|
||||||
|
"code": "01429",
|
||||||
|
"city": "夕張郡栗山町",
|
||||||
|
"lv": "字滝下",
|
||||||
|
"kana": "たきした"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 42.25,
|
||||||
|
"to": 43.0,
|
||||||
|
"code": "01427",
|
||||||
|
"city": "夕張郡由仁町",
|
||||||
|
"lv": "川端",
|
||||||
|
"kana": "かわばた"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 43.25,
|
||||||
|
"to": 44.0,
|
||||||
|
"code": "01429",
|
||||||
|
"city": "夕張郡栗山町",
|
||||||
|
"lv": "字滝下",
|
||||||
|
"kana": "たきした"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 44.25,
|
||||||
|
"to": 48.25,
|
||||||
|
"code": "01209",
|
||||||
|
"city": "夕張市",
|
||||||
|
"lv": "滝ノ上",
|
||||||
|
"kana": "たきのうえ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 48.5,
|
||||||
|
"to": 55.5,
|
||||||
|
"code": "01209",
|
||||||
|
"city": "夕張市",
|
||||||
|
"lv": "紅葉山",
|
||||||
|
"kana": "もみじやま"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 55.75,
|
||||||
|
"to": 57.75,
|
||||||
|
"code": "01209",
|
||||||
|
"city": "夕張市",
|
||||||
|
"lv": "楓",
|
||||||
|
"kana": "かえで"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 58.0,
|
||||||
|
"to": 61.0,
|
||||||
|
"code": "01209",
|
||||||
|
"city": "夕張市",
|
||||||
|
"lv": "登川",
|
||||||
|
"kana": "のぼりかわ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 61.25,
|
||||||
|
"to": 62.75,
|
||||||
|
"code": "01586",
|
||||||
|
"city": "勇払郡むかわ町",
|
||||||
|
"lv": "穂別長和",
|
||||||
|
"kana": "ほべつおさわ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 63.0,
|
||||||
|
"to": 72.0,
|
||||||
|
"code": "01586",
|
||||||
|
"city": "勇払郡むかわ町",
|
||||||
|
"lv": "穂別稲里",
|
||||||
|
"kana": "ほべついなさと"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 72.25,
|
||||||
|
"to": 76.0,
|
||||||
|
"code": "01586",
|
||||||
|
"city": "勇払郡むかわ町",
|
||||||
|
"lv": "穂別長和",
|
||||||
|
"kana": "ほべつおさわ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 76.25,
|
||||||
|
"to": 88.75,
|
||||||
|
"code": "01586",
|
||||||
|
"city": "勇払郡むかわ町",
|
||||||
|
"lv": "穂別福山",
|
||||||
|
"kana": "ほべつふくやま"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 89.0,
|
||||||
|
"to": 96.75,
|
||||||
|
"code": "01463",
|
||||||
|
"city": "勇払郡占冠村",
|
||||||
|
"lv": "字中央",
|
||||||
|
"kana": "ちゅうおう"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 97.0,
|
||||||
|
"to": 101.75,
|
||||||
|
"code": "01601",
|
||||||
|
"city": "沙流郡日高町",
|
||||||
|
"lv": "字日高",
|
||||||
|
"kana": "ひだか(1く)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 102.0,
|
||||||
|
"to": 102.5,
|
||||||
|
"code": "01601",
|
||||||
|
"city": "沙流郡日高町",
|
||||||
|
"lv": "新町三丁目",
|
||||||
|
"kana": "しんまち"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 102.75,
|
||||||
|
"to": 102.75,
|
||||||
|
"code": "01601",
|
||||||
|
"city": "沙流郡日高町",
|
||||||
|
"lv": "新町一丁目",
|
||||||
|
"kana": "しんまち"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 103.0,
|
||||||
|
"to": 103.0,
|
||||||
|
"code": "01601",
|
||||||
|
"city": "沙流郡日高町",
|
||||||
|
"lv": "栄町東一丁目",
|
||||||
|
"kana": "さかえまちひがし"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 103.25,
|
||||||
|
"to": 103.5,
|
||||||
|
"code": "01601",
|
||||||
|
"city": "沙流郡日高町",
|
||||||
|
"lv": "本町東一丁目",
|
||||||
|
"kana": "ほんちょうひがし"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 103.75,
|
||||||
|
"to": 103.75,
|
||||||
|
"code": "01601",
|
||||||
|
"city": "沙流郡日高町",
|
||||||
|
"lv": "本町東二丁目",
|
||||||
|
"kana": "ほんちょうひがし"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 104.0,
|
||||||
|
"to": 104.0,
|
||||||
|
"code": "01601",
|
||||||
|
"city": "沙流郡日高町",
|
||||||
|
"lv": "松風町一丁目",
|
||||||
|
"kana": "まつかぜちょう"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 104.25,
|
||||||
|
"to": 104.25,
|
||||||
|
"code": "01601",
|
||||||
|
"city": "沙流郡日高町",
|
||||||
|
"lv": "山手町一丁目",
|
||||||
|
"kana": "やまてちょう"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 104.5,
|
||||||
|
"to": 107.0,
|
||||||
|
"code": "01601",
|
||||||
|
"city": "沙流郡日高町",
|
||||||
|
"lv": "字日高",
|
||||||
|
"kana": "ひだか(1く)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frm": 107.25,
|
||||||
|
"to": 107.75,
|
||||||
|
"code": "01601",
|
||||||
|
"city": "沙流郡日高町",
|
||||||
|
"lv": "字千栄",
|
||||||
|
"kana": "ちさか"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
km,name,object,kana,romaji,kind,offset_m,lat,lon,length_m,built,grade,oaza,address,address_kana,location
|
||||||
|
37.27,川端,川端,かわばた,Kawabata,place (neighbourhood),32,42.91538,141.89568,,,,川端,夕張郡由仁町川端,ゆうばりぐんゆにちょうかわばた,
|
||||||
|
38.41,川端,川端橋,かわばたはし,Kawabata hashi,bridge,0,42.91715,141.90896,255,1991,Ⅰ,川端,夕張郡由仁町川端,ゆうばりぐんゆにちょうかわばた,由仁町
|
||||||
|
39.80,川端,北海道企業局 川端発電所,,,power station,451,42.91197,141.91642,,,,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,
|
||||||
|
39.80,川端,川端ダム,,,dam,523,42.91140,141.91590,,,,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,
|
||||||
|
40.16,滝下,滝下八幡神社,たきしたはちまんじんじゃ,Takishitahachiman jinja,Shinto shrine,98,42.91183,141.92472,,,,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,
|
||||||
|
40.57,滝ノ下,滝ノ下信号場,たきのした,Takinoshita,place (locality),400,42.90630,141.92320,,,,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,
|
||||||
|
41.02,クオーベツ,クオーベツダム,くおーぺつ,Kuoopetsu,dam,1798,42.89310,141.93874,,,,川端,夕張郡由仁町川端,ゆうばりぐんゆにちょうかわばた,
|
||||||
|
41.02,滝下川端,滝下川端連絡線,,,power line,75,42.90857,141.93273,,,,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,
|
||||||
|
41.02,砂金,砂金川,,,watercourse,58,42.90889,141.93222,,,,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,石狩川水系
|
||||||
|
41.86,雨霧橋,雨霧橋,あまぎりはし,Amagiri hashi,bridge,0,42.91003,141.94197,280.7,1974,Ⅱ,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,栗山町
|
||||||
|
43.03,竜仙橋,竜仙橋,りゅうせんばし,Ryuusen bashi,bridge,0,42.91604,141.95220,178,1972,Ⅱ,川端,夕張郡由仁町川端,ゆうばりぐんゆにちょうかわばた,由仁町
|
||||||
|
43.07,滝下,北海道企業局 滝下発電所,たきのしたはつでんしょ,Takinoshita hatsudensho,power station,210,42.91801,141.95218,,,,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,
|
||||||
|
43.30,滝下,滝下,たきした,Takishita,place (neighbourhood),1636,42.93155,141.95583,,,,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,
|
||||||
|
43.64,草木,草木川,そうもく,Soumoku,watercourse,84,42.91577,141.96022,,,,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,石狩川水系
|
||||||
|
44.00,草木,草木橋,そうもくはし,Soumoku hashi,bridge,0,42.91449,141.96321,24.1,1979,Ⅲ,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,栗山町
|
||||||
|
44.00,滝の上,滝の上こ線橋,たきのうえこせんきょう,Takinoue kosenkyou,bridge,0,42.91449,141.96321,47.6,1975,Ⅲ,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,夕張市
|
||||||
|
44.00,草木舞,草木舞沢川,そうもくまいさわ,Soumokumaisawa,watercourse,21,42.91436,141.96339,,,,滝下,夕張郡栗山町滝下,ゆうばりぐんくりやまちょうたきした,石狩川水系
|
||||||
|
44.62,滝の上,北海道企業局 滝の上発電所,,,power station,142,42.91152,141.97021,,,,滝ノ上,夕張市滝ノ上,ゆうばりしたきのうえ,
|
||||||
|
44.62,滝の上,滝の上公園,,,park,69,42.91225,141.97000,,,,滝ノ上,夕張市滝ノ上,ゆうばりしたきのうえ,
|
||||||
|
45.21,カミ,カミの沢川,,,watercourse,40,42.91059,141.97704,,,,滝ノ上,夕張市滝ノ上,ゆうばりしたきのうえ,石狩川水系
|
||||||
|
45.21,滝の上,滝ノ上信号場,たきのうえしんごうじょう,Takinoue shingoujou,railway signal post,43,42.91000,141.97642,,,,滝ノ上,夕張市滝ノ上,ゆうばりしたきのうえ,
|
||||||
|
45.29,滝の上,滝ノ上神社,たきのうえじんじゃ,Takinoue jinja,Shinto shrine,100,42.90979,141.97873,,,,滝ノ上,夕張市滝ノ上,ゆうばりしたきのうえ,
|
||||||
|
47.66,滝の上,滝ノ上,たきのうえ,Takinoue,place (neighbourhood),52,42.90347,142.00470,,,,滝ノ上,夕張市滝ノ上,ゆうばりしたきのうえ,
|
||||||
|
48.18,チョポツナイ,チョポツナイ川,ちょぽつない,Chopotsunai,watercourse,63,42.90575,142.01006,,,,滝ノ上,夕張市滝ノ上,ゆうばりしたきのうえ,石狩川水系
|
||||||
|
49.71,十三里,十三里信号場,とみさとしんごうじょう,Tomisato shingoujou,place (locality),39,42.91482,142.02439,,,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,
|
||||||
|
50.28,カライケ,カライケの沢川,からいけ,Karaike,watercourse,132,42.91674,142.03132,,,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,石狩川水系
|
||||||
|
50.28,十三里,十三里橋,とみさとはし,Tomisato hashi,bridge,0,42.91772,142.03043,122,1997,Ⅰ,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,夕張市
|
||||||
|
50.52,紅葉山,紅葉山駐車帯,もみじやまちゅうしゃたい,Momijiyama chuushatai,parking,41,42.91840,142.03331,,,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,
|
||||||
|
52.11,瑞穂,瑞穂橋,みずほはし,Mizuho hashi,bridge,0,42.93244,142.03548,155,1968,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,夕張市
|
||||||
|
52.11,夕張,夕張川,,,watercourse,16,42.93257,142.03538,,,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,石狩川水系
|
||||||
|
52.47,セブン-イレブン,セブンイレブン夕張紅葉山店,せぶんいれぶんゆうばりもみじやまてん,Sebun'irebun'yuubarimomijiyama ten,convenience store,73,42.93507,142.03683,,,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,
|
||||||
|
52.54,新夕張,新夕張駅,しんゆうばり,Shin'yuubari,railway station,173,42.93670,142.03648,,,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,
|
||||||
|
52.61,紅葉山,紅葉山郵便局,もみじやまゆうびんきょく,Momijiyama yuubinkyoku,post office,54,42.93642,142.03925,,,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,
|
||||||
|
52.85,紅葉山,紅葉山神社,もみじやまじんじゃ,Momijiyama jinja,Shinto shrine,67,42.93788,142.03956,,,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,
|
||||||
|
52.99,セイコーマート,セイコーマートもみじやま店,せいこーまーともみじやまてん,Seikoomaatomomijiyama ten,convenience store,31,42.93910,142.04167,,,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,
|
||||||
|
53.13,紅楓,紅楓橋,こうふうばし,Koufuu bashi,bridge,0,42.93855,142.04317,102.5,1958,Ⅱ,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,夕張市
|
||||||
|
53.69,久留喜,ポン久留喜橋,ぽんくるきはし,Ponkuruki hashi,bridge,0,42.93697,142.04976,12.7,1984,Ⅰ,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,夕張市
|
||||||
|
53.69,久留喜,ポンクルキ川,,,watercourse,16,42.93695,142.04995,,,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,石狩川水系
|
||||||
|
53.69,久留喜,久留喜橋,くるきはし,Kuruki hashi,bridge,0,42.93697,142.04976,34,1962,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,夕張市
|
||||||
|
55.14,シイタルキ,シイタルキ川,,,watercourse,143,42.92706,142.06277,,,,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,石狩川水系
|
||||||
|
55.41,楓,楓橋,かえでばし,Kaede bashi,bridge,0,42.92957,142.06562,32,1968,Ⅲ,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,夕張市
|
||||||
|
55.60,桂,桂橋,かつらはし,Katsura hashi,bridge,0,42.93026,142.06775,48.3,1987,Ⅰ,紅葉山,夕張市紅葉山,ゆうばりしもみじやま,夕張市
|
||||||
|
56.60,千紫,千紫橋,せんしばし,Senshi bashi,bridge,0,42.93414,142.07860,31.4,1988,Ⅰ,楓,夕張市楓,ゆうばりしかえで,夕張市
|
||||||
|
56.88,楓,楓,かえで,Kaede,place (neighbourhood),711,42.94002,142.08407,,,,楓,夕張市楓,ゆうばりしかえで,
|
||||||
|
57.08,楓,楓駐車帯,かえでちゅうしゃたい,Kaede chuushatai,parking,39,42.93352,142.08412,,,,楓,夕張市楓,ゆうばりしかえで,
|
||||||
|
57.25,万紅,万紅橋,ばんこうばし,Bankou bashi,bridge,0,42.93274,142.08627,27.6,1988,Ⅰ,楓,夕張市楓,ゆうばりしかえで,夕張市
|
||||||
|
57.44,登川,登川神社,のぼりかわじんじゃ,Noborikawa jinja,Shinto shrine,164,42.93395,142.08819,,,,楓,夕張市楓,ゆうばりしかえで,
|
||||||
|
57.76,楓,楓信号場,かえでしんごうじょう,Kaede shingoujou,railway signal post,47,42.93157,142.09230,,,,楓,夕張市楓,ゆうばりしかえで,
|
||||||
|
57.84,登川,登川橋,のぼりかわばし,Noborikawa bashi,bridge,0,42.93167,142.09327,21,1988,Ⅰ,楓,夕張市楓,ゆうばりしかえで,夕張市
|
||||||
|
57.84,登川,登川郵便局,のぼりかわゆうびんきょく,Noborikawa yuubinkyoku,post office,21,42.93185,142.09335,,,,楓,夕張市楓,ゆうばりしかえで,
|
||||||
|
58.23,花園,花園橋,はなぞのばし,Hanazono bashi,bridge,0,42.92922,142.09647,58.6,1971,Ⅱ,登川,夕張市登川,ゆうばりしのぼりかわ,夕張市
|
||||||
|
58.26,ホルカクルキ,ホルカクルキ川,,,watercourse,9,42.92920,142.09685,,,,登川,夕張市登川,ゆうばりしのぼりかわ,石狩川水系
|
||||||
|
58.56,滝沢川,滝沢川,,,watercourse,52,42.92962,142.10029,,,,登川,夕張市登川,ゆうばりしのぼりかわ,石狩川水系
|
||||||
|
59.54,松竹沢,松竹沢川,,,watercourse,58,42.93047,142.11198,,,,登川,夕張市登川,ゆうばりしのぼりかわ,石狩川水系
|
||||||
|
59.66,登川,登川,のぼりかわ,Noborikawa,place (neighbourhood),1208,42.93831,142.12137,,,,登川,夕張市登川,ゆうばりしのぼりかわ,
|
||||||
|
60.29,登川,登川トンネル,のぼりかわとんねる,Noborikawa tonneru,tunnel,0,42.92478,142.11599,348,1978,,登川,夕張市登川,ゆうばりしのぼりかわ,夕張市
|
||||||
|
62.36,オマナイ,オマナイ橋,おまないはし,Omanai hashi,bridge,0,42.90892,142.12482,174.2,1988,Ⅲ,穂別長和,勇払郡むかわ町穂別長和,ゆうふつぐんむかわちょうほべつおさわ,むかわ町
|
||||||
|
62.94,桂木,桂木橋,かつらぎはし,Katsuragi hashi,bridge,0,42.90434,142.12726,129.6,1986,Ⅲ,穂別長和,勇払郡むかわ町穂別長和,ゆうふつぐんむかわちょうほべつおさわ,むかわ町
|
||||||
|
64.44,大和,大和橋,やまとはし,Yamato hashi,bridge,0,42.89157,142.12305,16,1967,Ⅲ,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,むかわ町
|
||||||
|
66.69,豊進,豊進橋,ほうしんばし,Houshin bashi,bridge,0,42.87371,142.13048,16,1967,Ⅲ,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,むかわ町
|
||||||
|
66.78,豊進,豊進神社,ほうしんじんじゃ,Houshin jinja,Shinto shrine,49,42.87318,142.13135,,,,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,
|
||||||
|
66.83,穂別,穂別キャンプ場,,,campsite,66,42.87222,142.13061,,,,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,
|
||||||
|
66.86,石山,石山の沢川,,,watercourse,161,42.87125,142.13037,,,,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,鵡川水系
|
||||||
|
67.05,狩勝,狩勝幹線,,,power line,414,42.86806,142.13398,,,,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,
|
||||||
|
67.48,豊里,豊里橋,とよさとはし,Toyosato hashi,bridge,0,42.87311,142.13854,27,1966,Ⅰ,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,むかわ町
|
||||||
|
67.60,稲豊,稲豊橋,いなとよはし,Inatoyo hashi,bridge,0,42.87313,142.14000,27,1966,Ⅰ,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,むかわ町
|
||||||
|
67.62,サヌシュッペ,サヌシュッペ川,,,watercourse,5,42.87304,142.14032,,,,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,鵡川水系
|
||||||
|
68.63,稲里,稲里橋,いなさとはし,Inasato hashi,bridge,0,42.87144,142.15164,31,1988,Ⅱ,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,むかわ町
|
||||||
|
69.29,稲里,稲里簡易郵便局,いなさとかんいゆうびんきょく,Inasatokan'i yuubinkyoku,post office,161,42.86734,142.15774,,,,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,
|
||||||
|
69.48,佐主,佐主橋,さぬしばし,Sanushi bashi,bridge,0,42.86894,142.16085,85,1973,Ⅲ,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,むかわ町
|
||||||
|
70.22,穂別,穂別川,,,watercourse,32,42.87408,142.16642,,,,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,鵡川水系
|
||||||
|
71.86,穂別,穂別ダム神社,ほべつだむじんじゃ,Hobetsudamu jinja,Shinto shrine,18,42.88475,142.17737,,,,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,
|
||||||
|
71.90,穂別,穂別ダム,,,dam,166,42.88502,142.17937,,,,穂別稲里,勇払郡むかわ町穂別稲里,ゆうふつぐんむかわちょうほべついなさと,
|
||||||
|
72.02,長和,長和トンネル,おさわとんねる,Osawa tonneru,tunnel,0,42.88619,142.17748,281,1983,,穂別長和,勇払郡むかわ町穂別長和,ゆうふつぐんむかわちょうほべつおさわ,むかわ町
|
||||||
|
72.29,穂別,穂別大橋,ほべつおおはし,Hobetsu oohashi,bridge,0,42.88820,142.17918,506.2,1979,Ⅲ,穂別長和,勇払郡むかわ町穂別長和,ゆうふつぐんむかわちょうほべつおさわ,むかわ町
|
||||||
|
72.90,山水,山水橋,さんすいばし,Sansui bashi,bridge,0,42.89187,142.18476,53.5,1979,Ⅰ,穂別長和,勇払郡むかわ町穂別長和,ゆうふつぐんむかわちょうほべつおさわ,むかわ町
|
||||||
|
72.93,高西,高西の沢川,,,watercourse,9,42.89195,142.18498,,,,穂別長和,勇払郡むかわ町穂別長和,ゆうふつぐんむかわちょうほべつおさわ,鵡川水系
|
||||||
|
74.31,沼の沢,沼の沢橋,ぬまのさわはし,Numanosawa hashi,bridge,0,42.88830,142.20015,188,1983,Ⅲ,穂別長和,勇払郡むかわ町穂別長和,ゆうふつぐんむかわちょうほべつおさわ,むかわ町
|
||||||
|
75.28,稲里,稲里トンネル,いなさととんねる,Inasato tonneru,tunnel,0,42.88343,142.20951,1441,1985,Ⅲ,穂別長和,勇払郡むかわ町穂別長和,ゆうふつぐんむかわちょうほべつおさわ,むかわ町
|
||||||
|
76.97,ペンケ橋,ペンケ橋,ぺんけばし,Penke bashi,bridge,0,42.87802,142.22782,120.7,1985,Ⅲ,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
77.05,オロロップ,オロロップ沢川,,,watercourse,15,42.87849,142.22885,,,,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,鵡川水系
|
||||||
|
78.03,下福山,下福山橋,しもふくやまはし,Shimofukuyama hashi,bridge,0,42.88572,142.23487,129.9,1982,Ⅰ,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
78.31,オロロップ,オロロップ橋,おろろっぷはし,Ororoppu hashi,bridge,0,42.88721,142.23759,205.9,1983,Ⅱ,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
79.11,福山,福山橋,ふくやまはし,Fukuyama hashi,bridge,0,42.89249,142.24390,134.7,1984,Ⅲ,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
79.67,福山,福山神社,ふくやまじんじゃ,Fukuyama jinja,Shinto shrine,184,42.89114,142.25175,,,,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,
|
||||||
|
79.81,福山第1ゲート,福山第1ゲート,,,gate,71,42.89003,142.25118,,,,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,
|
||||||
|
79.86,福山第2ゲート,福山第2ゲート,,,gate,47,42.88890,142.25072,,,,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,
|
||||||
|
80.01,穂別福山 (穂別 + 福山),穂別福山,ほべつふくやま,Hobetsufukuyama,place (neighbourhood),172,42.88942,142.25385,,,,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,
|
||||||
|
80.24,鵡川,鵡川,,,watercourse,68,42.88740,142.25421,,,,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,鵡川水系
|
||||||
|
80.24,福山,福山大橋,ふくやまおおはし,Fukuyama oohashi,bridge,0,42.88678,142.25416,160,1968,Ⅲ,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
85.40,千坂,千坂橋,ちさかはし,Chisaka hashi,bridge,0,42.88901,142.29725,138.7,1975,Ⅱ,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
85.87,オコタン,オコタン橋,おこたんばし,Okotan bashi,bridge,0,42.89179,142.30059,338,1985,Ⅰ,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
86.16,パンケモトツ,パンケモトツ沢川,,,watercourse,10,42.89278,142.30394,,,,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,鵡川水系
|
||||||
|
86.24,モトツ,モトツトンネル,もとつとんねる,Mototsu tonneru,tunnel,0,42.89321,142.30463,924,1991,Ⅱ,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
87.12,モトツ,モトツ橋,もとつばし,Mototsu bashi,bridge,0,42.89931,142.31156,62,1988,Ⅱ,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
87.12,モトツ,モトツシェルター,もとつしぇるたー,Mototsu sherutaa,shed,0,42.89931,142.31156,62,1990,Ⅲ,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
87.21,福山,福山トンネル,,,tunnel,0,42.89988,142.31229,839,1991,,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
88.04,ペンケモトツ,ペンケモトツ沢川,,,watercourse,26,42.90332,142.32161,,,,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,鵡川水系
|
||||||
|
88.04,福穂,福穂橋,ふくすいはし,Fukusui hashi,bridge,0,42.90322,142.32132,210,1990,Ⅰ,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
88.25,穂高,穂高トンネル,ほだかとんねる,Hodaka tonneru,tunnel,0,42.90398,142.32368,1991,1991,Ⅱ,穂別福山,勇払郡むかわ町穂別福山,ゆうふつぐんむかわちょうほべつふくやま,むかわ町
|
||||||
|
90.58,穂高,穂高橋,ほだかはし,Hodaka hashi,bridge,0,42.90958,142.35128,140.6,1988,Ⅱ,中央,勇払郡占冠村中央,ゆうふつぐんしむかっぷむらちゅうおう,占冠村
|
||||||
|
90.90,高翠,高翠橋,こうすいばし,Kousui bashi,bridge,0,42.90889,142.35485,114,1988,Ⅰ,中央,勇払郡占冠村中央,ゆうふつぐんしむかっぷむらちゅうおう,占冠村
|
||||||
|
91.14,占翠,占翠橋,せんすいばし,Sensui bashi,bridge,0,42.90869,142.35768,167,1989,Ⅰ,中央,勇払郡占冠村中央,ゆうふつぐんしむかっぷむらちゅうおう,占冠村
|
||||||
|
93.58,名石,名石駐車場,めいせきちゅうしゃじょう,Meiseki chuushajou,parking,32,42.90980,142.36986,,,,中央,勇払郡占冠村中央,ゆうふつぐんしむかっぷむらちゅうおう,
|
||||||
|
93.67,名石,名石橋,めいせきばし,Meiseki bashi,bridge,0,42.91029,142.37052,39.6,1970,Ⅰ,中央,勇払郡占冠村中央,ゆうふつぐんしむかっぷむらちゅうおう,占冠村
|
||||||
|
93.73,ニセイパオマナイ,ニセイパオマナイ川,,,watercourse,30,42.91045,142.37087,,,,中央,勇払郡占冠村中央,ゆうふつぐんしむかっぷむらちゅうおう,鵡川水系
|
||||||
|
94.35,赤岩,赤岩大橋,あかいわおおはし,Akaiwa oohashi,bridge,0,42.91317,142.37731,157.4,1970,Ⅱ,中央,勇払郡占冠村中央,ゆうふつぐんしむかっぷむらちゅうおう,占冠村
|
||||||
|
95.37,一の沢川,一の沢川,,,watercourse,44,42.91532,142.38713,,,,中央,勇払郡占冠村中央,ゆうふつぐんしむかっぷむらちゅうおう,鵡川水系
|
||||||
|
95.37,渓流,渓流大橋,けいりゅうおおはし,Keiryuu oohashi,bridge,0,42.91502,142.38677,153.7,1974,Ⅲ,中央,勇払郡占冠村中央,ゆうふつぐんしむかっぷむらちゅうおう,占冠村
|
||||||
|
96.43,日高,日高トンネル,ひだかとんねる,Hidaka tonneru,tunnel,0,42.91588,142.39911,730,1972,Ⅲ,中央,勇払郡占冠村中央,ゆうふつぐんしむかっぷむらちゅうおう,占冠村
|
||||||
|
99.93,右の沢川,右の沢川,,,watercourse,145,42.89623,142.41771,,,,日高,沙流郡日高町日高,さるぐんひだかちょうひだか,沙流川水系
|
||||||
|
99.98,ホロカワウシャップ,ホロカワウシャップ川,,,watercourse,79,42.89623,142.41942,,,,日高,沙流郡日高町日高,さるぐんひだかちょうひだか,沙流川水系
|
||||||
|
100.60,日夕,日夕橋,にちゆうばし,Nichiyuu bashi,bridge,0,42.89710,142.42716,30,1968,Ⅰ,日高,沙流郡日高町日高,さるぐんひだかちょうひだか,日高町
|
||||||
|
100.66,パンケウシャップ,パンケウシャップ川,,,watercourse,21,42.89691,142.42766,,,,日高,沙流郡日高町日高,さるぐんひだかちょうひだか,沙流川水系
|
||||||
|
100.90,日高,日高,,,place (neighbourhood),373,42.89635,142.43448,,,,日高,沙流郡日高町日高,さるぐんひだかちょうひだか,
|
||||||
|
102.18,新町,新町三丁目,しんまち3ちょうめ,Shinmachi 3-choume,place (neighbourhood),13,42.88427,142.43237,,,,新町,沙流郡日高町新町,さるぐんひだかちょうしんまち,
|
||||||
|
102.36,日高,日高神社,ひだかじんじゃ,Hidaka jinja,Shinto shrine,221,42.88427,142.43553,,,,宮下町,沙流郡日高町宮下町,さるぐんひだかちょうみやしたちょう,
|
||||||
|
102.72,kanamoto,kanamoto,かなもと,Kanamoto,shop,42,42.88086,142.43687,,,,宮下町,沙流郡日高町宮下町,さるぐんひだかちょうみやしたちょう,
|
||||||
|
103.12,新川,新川橋,しんかわはし,Shinkawa hashi,bridge,0,42.87791,142.44001,3.6,1993,Ⅰ,本町東,沙流郡日高町本町東,さるぐんひだかちょうほんちょうひがし,日高町
|
||||||
|
103.12,新川,新川,にいかわ,Niikawa,watercourse,23,42.87811,142.43992,,,,本町東,沙流郡日高町本町東,さるぐんひだかちょうほんちょうひがし,沙流川水系
|
||||||
|
103.29,日高,日高郵便局,ひだかゆうびんきょく,Hidaka yuubinkyoku,post office,85,42.87748,142.44195,,,,本町東,沙流郡日高町本町東,さるぐんひだかちょうほんちょうひがし,
|
||||||
|
103.29,セイコーマート,セイコーマート日高道の駅店,せいこーまーとひだかみちのえきてん,Seikoomaatohidakamichinoeki ten,convenience store,85,42.87734,142.44216,,,,本町東,沙流郡日高町本町東,さるぐんひだかちょうほんちょうひがし,
|
||||||
|
104.39,ウシャップ,ペンケウシャップ川,,,watercourse,15,42.88146,142.45211,,,,日高,沙流郡日高町日高,さるぐんひだかちょうひだか,沙流川水系
|
||||||
|
104.52,日高,北海道電力 日高発電所,ひだかはつでんしょ,Hidaka hatsudensho,power station,666,42.87724,142.45788,,,,千栄,沙流郡日高町千栄,さるぐんひだかちょうちさか,
|
||||||
|
105.67,沙流川,沙流川,,,watercourse,272,42.88829,142.46766,,,,千栄,沙流郡日高町千栄,さるぐんひだかちょうちさか,沙流川水系
|
||||||
|
105.99,ユウケシュオマナイ,パンケユウケシュオマナイ川,,,watercourse,181,42.88869,142.46778,,,,日高,沙流郡日高町日高,さるぐんひだかちょうひだか,沙流川水系
|
||||||
|
106.22,右左府,右左府発電所,うさっぷはつでんしょ,Usappu hatsudensho,power station,244,42.89314,142.46755,,,,日高,沙流郡日高町日高,さるぐんひだかちょうひだか,
|
||||||
|
106.22,右左府,右左府変電所,,,substation,245,42.89280,142.46713,,,,日高,沙流郡日高町日高,さるぐんひだかちょうひだか,
|
||||||
|
106.47,オワイタカ,オワイタカ沢川,,,watercourse,52,42.89254,142.47167,,,,日高,沙流郡日高町日高,さるぐんひだかちょうひだか,沙流川水系
|
||||||
|
107.29,滝の沢川,滝の沢川,,,watercourse,18,42.89575,142.48126,,,,千栄,沙流郡日高町千栄,さるぐんひだかちょうちさか,沙流川水系
|
||||||
|
107.83,ルウケシオマナイ,ルウケシオマナイ川,,,watercourse,134,42.89400,142.48842,,,,千栄,沙流郡日高町千栄,さるぐんひだかちょうちさか,沙流川水系
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -0,0 +1,99 @@
|
|||||||
|
start,stop,start_s,stop_s,sung,object,kind,km,lat,lon,km_from,km_to
|
||||||
|
00:14.54,00:17.89,14.54,17.89,夕張郡由仁町川端,夕張郡由仁町川端,district,38.41,42.91715,141.90896,38.41,38.41
|
||||||
|
00:17.89,00:19.67,17.89,19.67,川端橋,川端橋,bridge,38.41,42.91715,141.90896,,
|
||||||
|
00:25.04,00:28.41,25.04,28.41,夕張郡栗山町滝下,夕張郡栗山町滝下,district,39.80,42.91197,141.91642,39.80,41.86
|
||||||
|
00:28.41,00:32.06,28.41,32.06,川端発電所,北海道企業局 川端発電所,power station,39.80,42.91197,141.91642,,
|
||||||
|
00:32.06,00:35.44,32.06,35.44,滝下八幡神社,滝下八幡神社,Shinto shrine,40.16,42.91183,141.92472,,
|
||||||
|
00:35.44,00:39.84,35.44,39.84,滝ノ下信号場,滝ノ下信号場,place (locality),40.57,42.90630,141.92320,,
|
||||||
|
00:39.84,00:42.01,39.84,42.01,雨霧橋,雨霧橋,bridge,41.86,42.91003,141.94197,,
|
||||||
|
00:42.45,00:45.15,42.45,45.15,夕張郡由仁町川端,夕張郡由仁町川端,district,43.03,42.91604,141.95220,43.03,43.03
|
||||||
|
00:45.15,00:46.69,45.15,46.69,竜仙橋,竜仙橋,bridge,43.03,42.91604,141.95220,,
|
||||||
|
00:47.63,00:50.08,47.63,50.08,夕張郡栗山町滝下,夕張郡栗山町滝下,district,44.00,42.91449,141.96321,44.00,44.00
|
||||||
|
00:50.08,00:52.88,50.08,52.88,草木橋,草木橋,bridge,44.00,42.91449,141.96321,,
|
||||||
|
00:52.88,00:54.73,52.88,54.73,滝の上こ線橋,滝の上こ線橋,bridge,44.00,42.91449,141.96321,,
|
||||||
|
00:56.44,00:59.95,56.44,59.95,夕張市滝ノ上,夕張市滝ノ上,district,44.62,42.91152,141.97021,44.62,45.29
|
||||||
|
00:59.95,01:03.47,59.95,63.47,滝の上発電所,北海道企業局 滝の上発電所,power station,44.62,42.91152,141.97021,,
|
||||||
|
01:03.47,01:06.94,63.47,66.94,滝ノ上信号場,滝ノ上信号場,railway signal post,45.21,42.91000,141.97642,,
|
||||||
|
01:06.94,01:08.78,66.94,68.78,滝ノ上神社,滝ノ上神社,Shinto shrine,45.29,42.90979,141.97873,,
|
||||||
|
01:10.50,01:12.05,70.50,72.05,夕張市紅葉山,夕張市紅葉山,district,49.71,42.91482,142.02439,49.71,55.60
|
||||||
|
01:12.05,01:13.86,72.05,73.86,十三里信号場,十三里信号場,place (locality),49.71,42.91482,142.02439,,
|
||||||
|
01:13.86,01:16.44,73.86,76.44,十三里橋,十三里橋,bridge,50.28,42.91772,142.03043,,
|
||||||
|
01:16.44,01:18.78,76.44,78.78,紅葉山駐車帯,紅葉山駐車帯,parking,50.52,42.91840,142.03331,,
|
||||||
|
01:18.78,01:21.06,78.78,81.06,瑞穂橋,瑞穂橋,bridge,52.11,42.93244,142.03548,,
|
||||||
|
01:21.06,01:24.44,81.06,84.44,セブンイレブン夕張紅葉山店,セブンイレブン夕張紅葉山店,convenience store,52.47,42.93507,142.03683,,
|
||||||
|
01:24.44,01:27.06,84.44,87.06,新夕張駅,新夕張駅,railway station,52.54,42.93670,142.03648,,
|
||||||
|
01:27.06,01:30.02,87.06,90.02,紅葉山郵便局,紅葉山郵便局,post office,52.61,42.93642,142.03925,,
|
||||||
|
01:30.02,01:32.30,90.02,92.30,紅葉山神社,紅葉山神社,Shinto shrine,52.85,42.93788,142.03956,,
|
||||||
|
01:32.30,01:35.24,92.30,95.24,セイコーマートもみじやま店,セイコーマートもみじやま店,convenience store,52.99,42.93910,142.04167,,
|
||||||
|
01:35.24,01:38.48,95.24,98.48,紅楓橋,紅楓橋,bridge,53.13,42.93855,142.04317,,
|
||||||
|
01:38.48,01:40.25,98.48,100.25,ポン久留喜橋,ポン久留喜橋,bridge,53.69,42.93697,142.04976,,
|
||||||
|
01:40.25,01:42.44,100.25,102.44,久留喜橋,久留喜橋,bridge,53.69,42.93697,142.04976,,
|
||||||
|
01:42.44,01:43.79,102.44,103.79,楓橋,楓橋,bridge,55.41,42.92957,142.06562,,
|
||||||
|
01:43.79,01:45.03,103.79,105.03,桂橋,桂橋,bridge,55.60,42.93026,142.06775,,
|
||||||
|
01:45.77,01:49.12,105.77,109.12,夕張市楓,夕張市楓,district,56.60,42.93414,142.07860,56.60,57.84
|
||||||
|
01:49.12,01:50.76,109.12,110.76,千紫橋,千紫橋,bridge,56.60,42.93414,142.07860,,
|
||||||
|
01:50.76,01:52.51,110.76,112.51,楓駐車帯,楓駐車帯,parking,57.08,42.93352,142.08412,,
|
||||||
|
01:52.51,01:53.80,112.51,113.80,万紅橋,万紅橋,bridge,57.25,42.93274,142.08627,,
|
||||||
|
01:53.80,01:55.54,113.80,115.54,登川神社,登川神社,Shinto shrine,57.44,42.93395,142.08819,,
|
||||||
|
01:55.54,01:57.32,115.54,117.32,楓信号場,楓信号場,railway signal post,57.76,42.93157,142.09230,,
|
||||||
|
01:57.32,01:59.00,117.32,119.00,登川橋,登川橋,bridge,57.84,42.93167,142.09327,,
|
||||||
|
01:59.00,02:00.74,119.00,120.74,登川郵便局,登川郵便局,post office,57.84,42.93185,142.09335,,
|
||||||
|
02:01.26,02:02.93,121.26,122.93,夕張市登川,夕張市登川,district,58.23,42.92922,142.09647,58.23,60.29
|
||||||
|
02:02.93,02:05.23,122.93,125.23,花園橋,花園橋,bridge,58.23,42.92922,142.09647,,
|
||||||
|
02:05.23,02:06.62,125.23,126.62,登川トンネル,登川トンネル,tunnel,60.29,42.92478,142.11599,,
|
||||||
|
03:30.80,03:34.55,210.80,214.55,勇払郡むかわ町穂別長和,勇払郡むかわ町穂別長和,district,62.36,42.90892,142.12482,62.36,62.94
|
||||||
|
03:34.55,03:36.77,214.55,216.77,オマナイ橋,オマナイ橋,bridge,62.36,42.90892,142.12482,,
|
||||||
|
03:36.77,03:39.41,216.77,219.41,桂木橋,桂木橋,bridge,62.94,42.90434,142.12726,,
|
||||||
|
03:41.13,03:44.62,221.13,224.62,勇払郡むかわ町穂別稲里,勇払郡むかわ町穂別稲里,district,64.44,42.89157,142.12305,64.44,71.86
|
||||||
|
03:44.62,03:46.67,224.62,226.67,大和橋,大和橋,bridge,64.44,42.89157,142.12305,,
|
||||||
|
03:46.67,03:48.38,226.67,228.38,豊進橋,豊進橋,bridge,66.69,42.87371,142.13048,,
|
||||||
|
03:48.38,03:51.61,228.38,231.61,豊進神社,豊進神社,Shinto shrine,66.78,42.87318,142.13135,,
|
||||||
|
03:51.61,03:53.14,231.61,233.14,豊里橋,豊里橋,bridge,67.48,42.87311,142.13854,,
|
||||||
|
03:53.14,03:55.52,233.14,235.52,稲豊橋,稲豊橋,bridge,67.60,42.87313,142.14000,,
|
||||||
|
03:55.52,03:57.78,235.52,237.78,稲里橋,稲里橋,bridge,68.63,42.87144,142.15164,,
|
||||||
|
03:57.78,04:01.08,237.78,241.08,稲里簡易郵便局,稲里簡易郵便局,post office,69.29,42.86734,142.15774,,
|
||||||
|
04:01.08,04:03.50,241.08,243.50,佐主橋,佐主橋,bridge,69.48,42.86894,142.16085,,
|
||||||
|
04:03.50,04:05.59,243.50,245.59,穂別ダム神社,穂別ダム神社,Shinto shrine,71.86,42.88475,142.17737,,
|
||||||
|
04:05.96,04:10.08,245.96,250.08,勇払郡むかわ町穂別長和,勇払郡むかわ町穂別長和,district,72.02,42.88619,142.17748,72.02,75.28
|
||||||
|
04:10.08,04:13.02,250.08,253.02,長和トンネル,長和トンネル,tunnel,72.02,42.88619,142.17748,,
|
||||||
|
04:13.02,04:15.39,253.02,255.39,穂別大橋,穂別大橋,bridge,72.29,42.88820,142.17918,,
|
||||||
|
04:15.39,04:18.81,255.39,258.81,山水橋,山水橋,bridge,72.90,42.89187,142.18476,,
|
||||||
|
04:18.81,04:23.20,258.81,263.20,沼の沢橋,沼の沢橋,bridge,74.31,42.88830,142.20015,,
|
||||||
|
04:23.20,04:25.27,263.20,265.27,稲里トンネル,稲里トンネル,tunnel,75.28,42.88343,142.20951,,
|
||||||
|
04:26.00,04:29.74,266.00,269.74,勇払郡むかわ町穂別福山,勇払郡むかわ町穂別福山,district,76.97,42.87802,142.22782,76.97,88.25
|
||||||
|
04:29.74,04:31.50,269.74,271.50,ペンケ橋,ペンケ橋,bridge,76.97,42.87802,142.22782,,
|
||||||
|
04:31.50,04:33.62,271.50,273.62,下福山橋,下福山橋,bridge,78.03,42.88572,142.23487,,
|
||||||
|
04:33.62,04:35.02,273.62,275.02,オロロップ橋,オロロップ橋,bridge,78.31,42.88721,142.23759,,
|
||||||
|
04:35.02,04:37.07,275.02,277.07,福山橋,福山橋,bridge,79.11,42.89249,142.24390,,
|
||||||
|
04:37.07,04:38.70,277.07,278.70,福山神社,福山神社,Shinto shrine,79.67,42.89114,142.25175,,
|
||||||
|
04:38.70,04:41.02,278.70,281.02,福山大橋,福山大橋,bridge,80.24,42.88678,142.25416,,
|
||||||
|
04:41.02,04:43.29,281.02,283.29,千坂橋,千坂橋,bridge,85.40,42.88901,142.29725,,
|
||||||
|
04:43.29,04:45.12,283.29,285.12,オコタン橋,オコタン橋,bridge,85.87,42.89179,142.30059,,
|
||||||
|
04:45.12,04:46.22,285.12,286.22,モトツトンネル,モトツトンネル,tunnel,86.24,42.89321,142.30463,,
|
||||||
|
04:46.22,04:48.98,286.22,288.98,モトツ橋にモトツシェルター,モトツ橋,bridge,87.12,42.89931,142.31156,,
|
||||||
|
04:46.22,04:48.98,286.22,288.98,モトツ橋にモトツシェルター,モトツシェルター,shed,87.12,42.89931,142.31156,,
|
||||||
|
04:48.98,04:51.39,288.98,291.39,福山トンネル,福山トンネル,tunnel,87.21,42.89988,142.31229,,
|
||||||
|
04:51.39,04:53.61,291.39,293.61,福穂橋,福穂橋,bridge,88.04,42.90322,142.32132,,
|
||||||
|
04:53.61,04:55.52,293.61,295.52,穂高トンネル,穂高トンネル,tunnel,88.25,42.90398,142.32368,,
|
||||||
|
05:22.60,05:25.76,322.60,325.76,勇払郡占冠村中央,勇払郡占冠村中央,district,90.58,42.90958,142.35128,90.58,96.43
|
||||||
|
05:25.76,05:28.88,325.76,328.88,穂高橋,穂高橋,bridge,90.58,42.90958,142.35128,,
|
||||||
|
05:28.88,05:31.52,328.88,331.52,高翠橋,高翠橋,bridge,90.90,42.90889,142.35485,,
|
||||||
|
05:31.52,05:34.95,331.52,334.95,占翠橋,占翠橋,bridge,91.14,42.90869,142.35768,,
|
||||||
|
05:34.95,05:38.08,334.95,338.08,名石駐車場,名石駐車場,parking,93.58,42.90980,142.36986,,
|
||||||
|
05:38.08,05:40.99,338.08,340.99,名石橋,名石橋,bridge,93.67,42.91029,142.37052,,
|
||||||
|
05:40.99,05:43.96,340.99,343.96,赤岩大橋,赤岩大橋,bridge,94.35,42.91317,142.37731,,
|
||||||
|
05:43.96,05:48.62,343.96,348.62,渓流大橋,渓流大橋,bridge,95.37,42.91502,142.38677,,
|
||||||
|
05:48.62,05:50.73,348.62,350.73,日高トンネル,日高トンネル,tunnel,96.43,42.91588,142.39911,,
|
||||||
|
07:11.39,07:14.14,431.39,434.14,沙流郡日高町日高,沙流郡日高町日高,district,100.60,42.89710,142.42716,100.60,100.60
|
||||||
|
07:14.14,07:16.38,434.14,436.38,日夕橋,日夕橋,bridge,100.60,42.89710,142.42716,,
|
||||||
|
07:28.85,07:31.68,448.85,451.68,沙流郡日高町宮下町,沙流郡日高町宮下町,district,102.36,42.88427,142.43553,102.36,102.36
|
||||||
|
07:31.68,07:34.09,451.68,454.09,日高神社,日高神社,Shinto shrine,102.36,42.88427,142.43553,,
|
||||||
|
07:42.90,07:45.51,462.90,465.51,沙流郡日高町本町東,沙流郡日高町本町東,district,103.12,42.87791,142.44001,103.12,103.29
|
||||||
|
07:45.51,07:49.88,465.51,469.88,新川橋,新川橋,bridge,103.12,42.87791,142.44001,,
|
||||||
|
07:49.88,07:52.76,469.88,472.76,セイコーマート日高道の駅店,セイコーマート日高道の駅店,convenience store,103.29,42.87734,142.44216,,
|
||||||
|
07:52.76,07:55.11,472.76,475.11,日高郵便局,日高郵便局,post office,103.29,42.87748,142.44195,,
|
||||||
|
07:56.69,07:59.36,476.69,479.36,沙流郡日高町千栄,沙流郡日高町千栄,district,104.52,42.87724,142.45788,104.52,104.52
|
||||||
|
07:59.36,08:02.15,479.36,482.15,北電日高発電所,北海道電力 日高発電所,power station,104.52,42.87724,142.45788,,
|
||||||
|
08:03.90,08:06.38,483.90,486.38,沙流郡日高町日高,沙流郡日高町日高,district,106.22,42.89314,142.46755,106.22,106.22
|
||||||
|
08:06.38,08:09.44,486.38,489.44,右左府発電所,右左府発電所,power station,106.22,42.89314,142.46755,,
|
||||||
|
08:10.93,08:12.66,490.93,492.66,東に続く,,closing,,,,,
|
||||||
|
@@ -0,0 +1 @@
|
|||||||
|
[[108.557,42.89528,142.49683],[108.603,42.89539,142.49736],[108.649,42.89556,142.49787],[108.695,42.89571,142.49842],[108.736,42.89578,142.4989],[108.794,42.89581,142.49962],[108.84,42.89571,142.50016],[108.946,42.89545,142.50142],[109.173,42.89489,142.5041],[109.371,42.89434,142.5064],[109.456,42.8942,142.50743],[109.52,42.89412,142.5082],[110.111,42.89351,142.51541],[110.297,42.89332,142.51768],[110.457,42.89317,142.51963],[110.482,42.89315,142.51995],[110.575,42.89305,142.52107],[110.738,42.89288,142.52306],[111.028,42.89258,142.5266],[111.056,42.89255,142.52694],[111.318,42.89229,142.53014],[111.333,42.89227,142.53031],[111.358,42.89224,142.53062],[111.359,42.89224,142.53064],[111.498,42.89212,142.53233],[111.527,42.89209,142.53269],[111.596,42.89201,142.53353],[111.671,42.89194,142.53444],[111.814,42.89181,142.53619],[111.842,42.89182,142.53653],[111.864,42.89177,142.5368],[111.958,42.89168,142.53794],[112.065,42.89155,142.53924],[112.09,42.89153,142.53954],[112.111,42.89153,142.53981],[112.138,42.89155,142.54013],[112.164,42.89159,142.54045],[112.196,42.89167,142.54083],[112.333,42.89204,142.54243],[112.688,42.89295,142.5466],[112.973,42.89375,142.54994],[113.048,42.89392,142.55082],[113.143,42.89417,142.55194],[113.202,42.89435,142.55262],[113.23,42.89444,142.55295],[113.27,42.89459,142.55338],[113.312,42.89478,142.55384],[113.395,42.8952,142.55467],[113.435,42.8954,142.55508],[113.492,42.89569,142.55566],[113.793,42.89718,142.55874],[113.829,42.89736,142.55911],[113.851,42.89747,142.55933],[113.987,42.89814,142.56073]]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[[30.456,42.94898,141.83538],[30.485,42.94902,141.83573],[31.021,42.94975,141.84224],[31.152,42.94995,141.84383],[31.305,42.95011,141.8457],[31.317,42.95013,141.84585],[31.385,42.95022,141.84667],[31.396,42.95024,141.8468],[31.405,42.95025,141.84692],[31.543,42.95043,141.84859],[31.633,42.95055,141.84968],[31.656,42.95058,141.84996],[31.663,42.95059,141.85004],[31.719,42.95067,141.85073],[31.953,42.95099,141.85357],[31.986,42.95103,141.85397],[32.022,42.95104,141.85441],[32.046,42.95104,141.8547],[32.061,42.95102,141.85489],[32.082,42.951,141.85514],[32.102,42.95095,141.85538],[32.124,42.95088,141.85564],[32.148,42.95079,141.8559],[32.17,42.95069,141.85614],[32.192,42.95059,141.85636],[32.214,42.95046,141.85658],[32.249,42.95025,141.8569],[32.278,42.95007,141.85715],[32.304,42.9499,141.85737],[32.315,42.94983,141.85746],[32.398,42.94927,141.85815],[32.462,42.94884,141.85865],[32.474,42.94875,141.85875],[32.607,42.94783,141.85978],[32.639,42.9476,141.86004],[32.72,42.94705,141.86067],[32.929,42.94561,141.86234],[32.957,42.94542,141.86256],[33.001,42.94512,141.86292],[33.138,42.94418,141.86399],[33.305,42.94303,141.8653],[33.489,42.94176,141.86678],[33.731,42.94012,141.86873],[33.99,42.93834,141.87077],[34.132,42.93738,141.87193],[34.161,42.93717,141.87214],[34.308,42.93617,141.87331],[34.584,42.93429,141.87554],[34.753,42.93312,141.87686],[35.006,42.9314,141.87888],[35.192,42.93012,141.88036],[35.335,42.92915,141.8815],[35.443,42.92841,141.88237],[35.527,42.92783,141.88304]]
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,74 @@
|
|||||||
|
# Route data — 274
|
||||||
|
|
||||||
|
Copied from `novoyuuparosk-wiki/ncmr-songs/wip/274/`, which is where these are
|
||||||
|
generated and edited. **Treat everything here as read-only**: change it upstream
|
||||||
|
and re-copy, or the two will drift.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
| File | What it is |
|
||||||
|
|---|---|
|
||||||
|
| `274-lyrics-index.csv` | One row per sung line, resolved to its roster entry, with start/stop timing and coordinates. The file the video syncs to. |
|
||||||
|
| `274-lookup.csv` | The full roster — every named object on the stretch, sung or not. The page draws all of these; the index only covers the ones that get sung. |
|
||||||
|
| `274-route.json` | The road itself: `[km, lat, lon]` per point, for drawing the line. |
|
||||||
|
| `274-route-west.json` | A short run of R274 before the western cutoff, same format — km 30.46 to 35.53, ending exactly on the first point of `274-route.json`. The road arriving before 川端橋, in symmetry with the east stub. Also in the GeoJSON as `kind: route-west`. |
|
||||||
|
| `274-route-east.json` | A short continuation past the eastern cutoff — km 108.56 to 113.99, overlapping the main shape by 0.18 km so the join is seamless. For `東に続く`: the road visibly carrying on after the last named thing. Also in the GeoJSON as `kind: route-east`. |
|
||||||
|
| `274-districts.json` | The 大字 bands with entry/exit km — the strip across the top of the transect page. |
|
||||||
|
| `274-lookup.geojson` | Route line, one point per roster entry, and the bands as geometryless features. For anything that wants GeoJSON directly. |
|
||||||
|
| `274-transect.html` | The interactive page the video is based on. Self-contained; opens from disk. |
|
||||||
|
|
||||||
|
## Using the index
|
||||||
|
|
||||||
|
`start` / `stop` are `mm:ss.xx`; `start_s` / `stop_s` are the same in seconds.
|
||||||
|
`stop` is the next timestamp in the LRC, blank spacer lines included, so every
|
||||||
|
line has one and the spans butt up against each other without gaps.
|
||||||
|
|
||||||
|
Join to `274-lookup.csv` on `object`, which is unique across the roster. The
|
||||||
|
`sung` column is the line as it appears in the lyric — the three power stations
|
||||||
|
are sung without their operator prefix, so `sung` and `object` differ for those.
|
||||||
|
|
||||||
|
Two row types are not ordinary nodes:
|
||||||
|
|
||||||
|
- **`kind = district`** — the address headers. These have no single point; they
|
||||||
|
carry the first coordinate of the run they introduce, plus `km_from`/`km_to`
|
||||||
|
spanning it.
|
||||||
|
- **`kind = closing`** — `東に続く`, which is text rather than an object. No
|
||||||
|
coordinates.
|
||||||
|
|
||||||
|
**モトツ橋にモトツシェルター emits two rows** sharing one timing and one
|
||||||
|
coordinate. It is one structure to drive through — a bridge roofed by a shelter,
|
||||||
|
between モトツトンネル and 福山トンネル — and two separately inspected facilities
|
||||||
|
in the national registers. Light both or either; they are the same place.
|
||||||
|
|
||||||
|
## Caveats that matter for the visuals
|
||||||
|
|
||||||
|
**All three route shapes are single clean polylines.** Where R274 has a central
|
||||||
|
reservation — the divided climbs after 福山大橋 and through 占冠 — OpenStreetMap
|
||||||
|
draws each carriageway as its own way. The shapes follow one spine through those
|
||||||
|
sections: point spacing adds up to exactly the km span, and km strictly increases
|
||||||
|
along every file, so the line can be drawn point to point without sideways spikes.
|
||||||
|
|
||||||
|
**`km` is not an official kilopost.** It is measured along the OpenStreetMap
|
||||||
|
route geometry from a datum near 上野幌, because the route relation is broken
|
||||||
|
across the divided carriageway in 札幌. Official KP is roughly this plus 14 km,
|
||||||
|
unverified. Ordering, spacing and geometry are all internally consistent; only
|
||||||
|
the absolute labels would be wrong if shown as real KP.
|
||||||
|
|
||||||
|
**`offset_m` is the straight-line distance from the object to the road.** Some
|
||||||
|
things sung are well off the carriageway — 日高神社 is 221 m away, クオーベツダム
|
||||||
|
1798 m. If the camera follows the road, an object's own coordinate is not always
|
||||||
|
where the camera should point.
|
||||||
|
|
||||||
|
**The lyric is monotonic by km end to end** — no backward jumps — so a camera
|
||||||
|
driven by `start_s` moves forward continuously from km 38.41 to 106.22.
|
||||||
|
|
||||||
|
**The lyric ends before the music does.** Lines run 14.54 s to 492.66 s (8:12),
|
||||||
|
while the release master is 619.27 s (10:19). Roughly two minutes of music play
|
||||||
|
past 東に続く.
|
||||||
|
|
||||||
|
## Provenance
|
||||||
|
|
||||||
|
How the roster was built, what was verified by hand, and what is derived rather
|
||||||
|
than measured: see `274-dev.md` in the source directory. Several entries exist
|
||||||
|
only because they were found on Google Maps and are absent from OpenStreetMap
|
||||||
|
entirely — ten of them, including four of the eight shrines.
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
import "./index.css";
|
import "./index.css";
|
||||||
import { MyComposition } from "./Composition";
|
import { MyComposition } from "./Composition";
|
||||||
|
import { Song274Transect } from "./song-274/Composition";
|
||||||
|
|
||||||
export const RemotionRoot: React.FC = () => {
|
export const RemotionRoot: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<MyComposition />
|
<MyComposition />
|
||||||
|
<Song274Transect />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { CalculateMetadataFunction, Composition } from "remotion";
|
||||||
|
import { loadTransectData } from "./data";
|
||||||
|
import { darkPalette } from "./palette";
|
||||||
|
import { Transect, type TransectProps } from "./Transect";
|
||||||
|
|
||||||
|
const FPS = 30;
|
||||||
|
/** Length of song-274/audio/274_release2.wav (see BOM.md). */
|
||||||
|
const AUDIO_DURATION_S = 619.270083;
|
||||||
|
|
||||||
|
const calculateMetadata: CalculateMetadataFunction<TransectProps> = async ({
|
||||||
|
props,
|
||||||
|
}) => ({
|
||||||
|
props: { ...props, data: await loadTransectData() },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Song274Transect: React.FC = () => (
|
||||||
|
<Composition
|
||||||
|
id="Song274Transect"
|
||||||
|
component={Transect}
|
||||||
|
durationInFrames={Math.ceil(AUDIO_DURATION_S * FPS)}
|
||||||
|
fps={FPS}
|
||||||
|
width={1920}
|
||||||
|
height={1080}
|
||||||
|
defaultProps={{
|
||||||
|
palette: darkPalette,
|
||||||
|
audio: "audio/274_release2.wav",
|
||||||
|
data: null,
|
||||||
|
}}
|
||||||
|
calculateMetadata={calculateMetadata}
|
||||||
|
/>
|
||||||
|
);
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
import React, { useMemo } from "react";
|
||||||
|
import {
|
||||||
|
AbsoluteFill,
|
||||||
|
Html5Audio,
|
||||||
|
staticFile,
|
||||||
|
useCurrentFrame,
|
||||||
|
useVideoConfig,
|
||||||
|
} from "remotion";
|
||||||
|
import {
|
||||||
|
blendViews,
|
||||||
|
followView,
|
||||||
|
narrationParts,
|
||||||
|
overviewLeadKm,
|
||||||
|
overviewView,
|
||||||
|
overviewWeight,
|
||||||
|
smoothedFocus,
|
||||||
|
toCamera,
|
||||||
|
type Frame,
|
||||||
|
} from "./camera";
|
||||||
|
import type { Cue, RosterItem, TransectData } from "./data";
|
||||||
|
import {
|
||||||
|
extendBounds,
|
||||||
|
GROUND,
|
||||||
|
nodePositions,
|
||||||
|
prefixBounds,
|
||||||
|
projectGround,
|
||||||
|
routePath,
|
||||||
|
} from "./layout";
|
||||||
|
import { useWindowedAudioData } from "@remotion/media-utils";
|
||||||
|
import { isAwake, mixLooks, nodeLookAt, spectrumLook } from "./nodeAnimation";
|
||||||
|
import {
|
||||||
|
AUDIO_WINDOW_S,
|
||||||
|
audioWindowFrame,
|
||||||
|
bandLevels,
|
||||||
|
shuffledBandFrequencies,
|
||||||
|
spectrumWeight,
|
||||||
|
} from "./spectrum";
|
||||||
|
import type { TransectPalette } from "./palette";
|
||||||
|
import {
|
||||||
|
coveredRoute,
|
||||||
|
monotoneCurve,
|
||||||
|
paintableRoute,
|
||||||
|
progressKeyframes,
|
||||||
|
routeAtKm,
|
||||||
|
} from "./progress";
|
||||||
|
|
||||||
|
export type TransectProps = {
|
||||||
|
palette: TransectPalette;
|
||||||
|
/** Path under the public dir (song-274/). */
|
||||||
|
audio: string;
|
||||||
|
/** Filled in by calculateMetadata from song-274/route/. */
|
||||||
|
data: TransectData | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Road stroke widths in map units; they grow with zoom like everything else. */
|
||||||
|
const ROAD_AHEAD_WIDTH = 1.4;
|
||||||
|
const ROAD_COVERED_WIDTH = 2.4;
|
||||||
|
|
||||||
|
/** Each object's cues in time order; most nodes are sung exactly once. */
|
||||||
|
const cuesByObject = (cues: Cue[]): Map<string, Cue[]> => {
|
||||||
|
const map = new Map<string, Cue[]>();
|
||||||
|
for (const cue of cues) {
|
||||||
|
for (const object of cue.objects) {
|
||||||
|
const list = map.get(object) ?? [];
|
||||||
|
list.push(cue);
|
||||||
|
map.set(object, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The cue that governs an object at `t`: the latest one to have started. */
|
||||||
|
const currentCue = (list: Cue[] | undefined, t: number): Cue | undefined => {
|
||||||
|
let current: Cue | undefined;
|
||||||
|
for (const cue of list ?? []) {
|
||||||
|
if (cue.startS <= t) {
|
||||||
|
current = cue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Transect: React.FC<TransectProps> = ({ palette, audio, data }) => {
|
||||||
|
const frame = useCurrentFrame();
|
||||||
|
const { fps, width, height } = useVideoConfig();
|
||||||
|
const projection = useMemo(() => (data ? projectGround(data.route) : null), [data]);
|
||||||
|
// The main road plus the east continuation. The paint runs into the latter
|
||||||
|
// after 東に続く; the camera and overview stay on the main road, so that run
|
||||||
|
// leaves the screen.
|
||||||
|
const paintRoute = useMemo(() => (data ? paintableRoute(data) : []), [data]);
|
||||||
|
// The dimmed road ahead includes the east continuation, so it shows all along.
|
||||||
|
const fullRoad = useMemo(
|
||||||
|
() => (projection && paintRoute.length > 1 ? routePath(paintRoute, projection) : ""),
|
||||||
|
[paintRoute, projection],
|
||||||
|
);
|
||||||
|
const bounds = useMemo(
|
||||||
|
() => (data && projection ? prefixBounds(data.route, projection) : []),
|
||||||
|
[data, projection],
|
||||||
|
);
|
||||||
|
const kmAt = useMemo(() => (data ? monotoneCurve(progressKeyframes(data)) : null), [data]);
|
||||||
|
const westRoad = useMemo(
|
||||||
|
() =>
|
||||||
|
data && projection && data.routeWest.length > 1
|
||||||
|
? routePath(data.routeWest, projection)
|
||||||
|
: "",
|
||||||
|
[data, projection],
|
||||||
|
);
|
||||||
|
const parts = useMemo(() => narrationParts(data ? data.lines : []), [data]);
|
||||||
|
const cueMap = useMemo(() => cuesByObject(data ? data.cues : []), [data]);
|
||||||
|
// Nodes at identical coordinates are spread slightly apart along the road.
|
||||||
|
const positions = useMemo(
|
||||||
|
() => (data && projection ? nodePositions(data.items, data.route, projection) : null),
|
||||||
|
[data, projection],
|
||||||
|
);
|
||||||
|
// Each node gets one log-spaced band, dealt out in a seeded shuffle.
|
||||||
|
const frequencies = useMemo(
|
||||||
|
() => shuffledBandFrequencies(data ? data.items.length : 0),
|
||||||
|
[data],
|
||||||
|
);
|
||||||
|
const { audioData, dataOffsetInSeconds } = useWindowedAudioData({
|
||||||
|
src: staticFile(audio),
|
||||||
|
frame: audioWindowFrame(frame, fps),
|
||||||
|
fps,
|
||||||
|
windowInSeconds: AUDIO_WINDOW_S,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data || !projection || !kmAt || !positions) {
|
||||||
|
return <AbsoluteFill style={{ backgroundColor: palette.background }} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const t = frame / fps;
|
||||||
|
const headAt = (time: number) => {
|
||||||
|
const km = kmAt(time);
|
||||||
|
const pos = routeAtKm(data.route, km);
|
||||||
|
return { km, index: pos.index, x: projection.x(pos.lon), y: projection.y(pos.lat) };
|
||||||
|
};
|
||||||
|
const head = headAt(t);
|
||||||
|
const routeStartKm = data.route[0][0];
|
||||||
|
const routeEndKm = data.route[data.route.length - 1][0];
|
||||||
|
const lead = routeAtKm(
|
||||||
|
data.route,
|
||||||
|
Math.min(routeEndKm, head.km + overviewLeadKm(head.km - routeStartKm)),
|
||||||
|
);
|
||||||
|
|
||||||
|
const view: Frame = {
|
||||||
|
worldWidth: GROUND.width,
|
||||||
|
worldHeight: projection.height,
|
||||||
|
frameWidth: width,
|
||||||
|
frameHeight: height,
|
||||||
|
};
|
||||||
|
const camera = toCamera(
|
||||||
|
blendViews(
|
||||||
|
followView(smoothedFocus(headAt, t)),
|
||||||
|
overviewView(
|
||||||
|
extendBounds(bounds[lead.index], projection.x(lead.lon), projection.y(lead.lat)),
|
||||||
|
view,
|
||||||
|
),
|
||||||
|
overviewWeight(parts, t),
|
||||||
|
),
|
||||||
|
view,
|
||||||
|
);
|
||||||
|
|
||||||
|
// In the outro the nodes hand over from their lyric looks to the spectrum.
|
||||||
|
const spectrum = spectrumWeight(t);
|
||||||
|
const levels =
|
||||||
|
spectrum > 0 && audioData
|
||||||
|
? bandLevels({ audioData, dataOffsetInSeconds, frame, fps, frequencies })
|
||||||
|
: null;
|
||||||
|
const nodes = data.items.map((item: RosterItem, i) => {
|
||||||
|
const lyricLook = nodeLookAt(currentCue(cueMap.get(item.object), t), t);
|
||||||
|
return {
|
||||||
|
item,
|
||||||
|
look: levels ? mixLooks(lyricLook, spectrumLook(levels[i]), spectrum) : lyricLook,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const draw = ({ item, look }: (typeof nodes)[number]) => (
|
||||||
|
<circle
|
||||||
|
key={item.object}
|
||||||
|
cx={positions.get(item.object)?.x ?? projection.x(item.lon)}
|
||||||
|
cy={positions.get(item.object)?.y ?? projection.y(item.lat)}
|
||||||
|
r={look.radius}
|
||||||
|
fill={palette[item.family]}
|
||||||
|
opacity={look.opacity}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AbsoluteFill style={{ backgroundColor: palette.background }}>
|
||||||
|
<Html5Audio src={staticFile(audio)} />
|
||||||
|
<svg width={width} height={height} viewBox={`0 0 ${width} ${height}`}>
|
||||||
|
<g transform={`translate(${camera.originX} ${camera.originY}) scale(${camera.scale})`}>
|
||||||
|
<path
|
||||||
|
d={fullRoad}
|
||||||
|
fill="none"
|
||||||
|
stroke={palette.roadAhead}
|
||||||
|
strokeWidth={ROAD_AHEAD_WIDTH}
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
{/* The road arriving from the west: already travelled, so always painted. */}
|
||||||
|
{westRoad ? (
|
||||||
|
<path
|
||||||
|
d={westRoad}
|
||||||
|
fill="none"
|
||||||
|
stroke={palette.roadCovered}
|
||||||
|
strokeWidth={ROAD_COVERED_WIDTH}
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
<path
|
||||||
|
d={routePath(coveredRoute(paintRoute, head.km), projection)}
|
||||||
|
fill="none"
|
||||||
|
stroke={palette.roadCovered}
|
||||||
|
strokeWidth={ROAD_COVERED_WIDTH}
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
{/* Animating nodes last so they sit on top of their neighbours. */}
|
||||||
|
{nodes.filter((n) => !isAwake(n.look)).map(draw)}
|
||||||
|
{nodes.filter((n) => isAwake(n.look)).map(draw)}
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</AbsoluteFill>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
import type { Bounds } from "./layout";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where the map sits on screen.
|
||||||
|
*
|
||||||
|
* The song narrates the road in parts separated by long instrumental breaks.
|
||||||
|
* During a part the camera holds a fixed close zoom and follows the head of the
|
||||||
|
* covered road. When a part ends it pulls back to frame everything covered so
|
||||||
|
* far, and just before the next part it closes in on the head again, arriving
|
||||||
|
* as the first line starts. After the last part it pulls back for good, which
|
||||||
|
* by then frames the whole route.
|
||||||
|
*
|
||||||
|
* Views are described in map units ({zoom, centre}); `toCamera` turns one into
|
||||||
|
* the scale and origin the drawing uses: screen = map unit × scale + origin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Zoom while following, relative to the whole route fitting the frame width. */
|
||||||
|
export const FOLLOW_ZOOM = 4;
|
||||||
|
/** Lines closer together than this belong to the same narration part. */
|
||||||
|
export const PART_GAP_S = 20;
|
||||||
|
/** Pull-back after a part ends, and close-in before the next one starts. */
|
||||||
|
export const ZOOM_OUT_S = 3;
|
||||||
|
export const ZOOM_IN_S = 3;
|
||||||
|
/**
|
||||||
|
* The camera follows a Gaussian-weighted average of the head's position, so a
|
||||||
|
* road zigzagging under a nearly straight run of objects does not shake it.
|
||||||
|
* This is the standard deviation, in seconds; the window spans ±3 of these.
|
||||||
|
*/
|
||||||
|
export const FOLLOW_SMOOTH_S = 0.6;
|
||||||
|
/**
|
||||||
|
* An overview frames the covered road plus some road ahead of the head, so the
|
||||||
|
* head does not sit against the frame edge: this fraction of the distance
|
||||||
|
* covered so far, but never less than the minimum.
|
||||||
|
*/
|
||||||
|
export const OVERVIEW_LEAD = 0.25;
|
||||||
|
export const OVERVIEW_LEAD_MIN_KM = 3;
|
||||||
|
/** Frame pixels kept clear around an overview. */
|
||||||
|
export const MARGIN_X = 80;
|
||||||
|
export const MARGIN_Y = 80;
|
||||||
|
|
||||||
|
export type Span = { startS: number; endS: number };
|
||||||
|
export type Point = { x: number; y: number };
|
||||||
|
export type View = { zoom: number; centreX: number; centreY: number };
|
||||||
|
export type Camera = { scale: number; originX: number; originY: number };
|
||||||
|
|
||||||
|
export type Frame = {
|
||||||
|
worldWidth: number;
|
||||||
|
worldHeight: number;
|
||||||
|
frameWidth: number;
|
||||||
|
frameHeight: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const clamp01 = (v: number) => Math.min(1, Math.max(0, v));
|
||||||
|
|
||||||
|
const easeInOutCubic = (p: number) =>
|
||||||
|
p < 0.5 ? 4 * p * p * p : 1 - Math.pow(-2 * p + 2, 3) / 2;
|
||||||
|
|
||||||
|
/** Merge lyric lines into narration parts wherever the gap is short. */
|
||||||
|
export const narrationParts = (lines: { startS: number; stopS: number }[]): Span[] => {
|
||||||
|
const sorted = lines.slice().sort((a, b) => a.startS - b.startS);
|
||||||
|
const parts: Span[] = [];
|
||||||
|
for (const line of sorted) {
|
||||||
|
const last = parts[parts.length - 1];
|
||||||
|
if (last && line.startS - last.endS <= PART_GAP_S) {
|
||||||
|
last.endS = Math.max(last.endS, line.stopS);
|
||||||
|
} else {
|
||||||
|
parts.push({ startS: line.startS, endS: line.stopS });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parts;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 while following the head, 1 while showing everything covered so far.
|
||||||
|
* The intro before the first part counts as following.
|
||||||
|
*/
|
||||||
|
export const overviewWeight = (parts: Span[], t: number): number => {
|
||||||
|
for (let i = 0; i < parts.length; i++) {
|
||||||
|
const part = parts[i];
|
||||||
|
if (t < part.startS) {
|
||||||
|
if (i === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const out = clamp01((t - parts[i - 1].endS) / ZOOM_OUT_S);
|
||||||
|
const into = clamp01((part.startS - t) / ZOOM_IN_S);
|
||||||
|
return easeInOutCubic(Math.min(out, into));
|
||||||
|
}
|
||||||
|
if (t <= part.endS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const lastPart = parts[parts.length - 1];
|
||||||
|
return lastPart ? easeInOutCubic(clamp01((t - lastPart.endS) / ZOOM_OUT_S)) : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The head's position averaged over a Gaussian window around `t`. */
|
||||||
|
export const smoothedFocus = (focusAt: (t: number) => Point, t: number): Point => {
|
||||||
|
const step = 1 / 30;
|
||||||
|
const reach = 3 * FOLLOW_SMOOTH_S;
|
||||||
|
let sumX = 0;
|
||||||
|
let sumY = 0;
|
||||||
|
let sumW = 0;
|
||||||
|
for (let dt = -reach; dt <= reach + 1e-9; dt += step) {
|
||||||
|
const w = Math.exp(-(dt * dt) / (2 * FOLLOW_SMOOTH_S * FOLLOW_SMOOTH_S));
|
||||||
|
const p = focusAt(t + dt);
|
||||||
|
sumX += p.x * w;
|
||||||
|
sumY += p.y * w;
|
||||||
|
sumW += w;
|
||||||
|
}
|
||||||
|
return { x: sumX / sumW, y: sumY / sumW };
|
||||||
|
};
|
||||||
|
|
||||||
|
const fitScale = (frame: Frame) => (frame.frameWidth - 2 * MARGIN_X) / frame.worldWidth;
|
||||||
|
|
||||||
|
/** How much road beyond the head (km) an overview includes. */
|
||||||
|
export const overviewLeadKm = (coveredKm: number): number =>
|
||||||
|
Math.max(OVERVIEW_LEAD_MIN_KM, coveredKm * OVERVIEW_LEAD);
|
||||||
|
|
||||||
|
export const followView = (focus: Point): View => ({
|
||||||
|
zoom: FOLLOW_ZOOM,
|
||||||
|
centreX: focus.x,
|
||||||
|
centreY: focus.y,
|
||||||
|
});
|
||||||
|
|
||||||
|
/** Frame `bounds` with margins, never closer than following nor wider than the full map. */
|
||||||
|
export const overviewView = (bounds: Bounds, frame: Frame): View => {
|
||||||
|
const base = fitScale(frame);
|
||||||
|
const width = Math.max(bounds.maxX - bounds.minX, 1e-6);
|
||||||
|
const height = Math.max(bounds.maxY - bounds.minY, 1e-6);
|
||||||
|
const zoom = Math.min(
|
||||||
|
(frame.frameWidth - 2 * MARGIN_X) / (width * base),
|
||||||
|
(frame.frameHeight - 2 * MARGIN_Y) / (height * base),
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
zoom: Math.min(FOLLOW_ZOOM, Math.max(1, zoom)),
|
||||||
|
centreX: (bounds.minX + bounds.maxX) / 2,
|
||||||
|
centreY: (bounds.minY + bounds.maxY) / 2,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Blend two views; zoom on a log scale so zooming in and out feel even. */
|
||||||
|
export const blendViews = (a: View, b: View, w: number): View => ({
|
||||||
|
zoom: Math.exp(Math.log(a.zoom) + (Math.log(b.zoom) - Math.log(a.zoom)) * w),
|
||||||
|
centreX: a.centreX + (b.centreX - a.centreX) * w,
|
||||||
|
centreY: a.centreY + (b.centreY - a.centreY) * w,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centre on `focus`, but never scroll past the map's ends: once the map is
|
||||||
|
* smaller than the view, centre the map itself.
|
||||||
|
*/
|
||||||
|
const clampAxis = (focus: number, worldSize: number, halfView: number, scale: number) => {
|
||||||
|
const low = halfView / scale;
|
||||||
|
const high = worldSize - halfView / scale;
|
||||||
|
return low >= high ? worldSize / 2 : Math.min(high, Math.max(low, focus));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toCamera = (view: View, frame: Frame): Camera => {
|
||||||
|
const scale = fitScale(frame) * view.zoom;
|
||||||
|
const centreX = clampAxis(view.centreX, frame.worldWidth, frame.frameWidth / 2 - MARGIN_X, scale);
|
||||||
|
const centreY = clampAxis(view.centreY, frame.worldHeight, frame.frameHeight / 2, scale);
|
||||||
|
return {
|
||||||
|
scale,
|
||||||
|
originX: frame.frameWidth / 2 - centreX * scale,
|
||||||
|
originY: frame.frameHeight / 2 - centreY * scale,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
import { staticFile } from "remotion";
|
||||||
|
import type { FeatureFamily } from "./palette";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the route data straight from `song-274/route/` (the public dir), so the
|
||||||
|
* video never holds its own copy that could drift from the wiki. See that
|
||||||
|
* folder's README for what each file is.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type RosterItem = {
|
||||||
|
object: string;
|
||||||
|
kind: string;
|
||||||
|
family: FeatureFamily;
|
||||||
|
/** Distance along the road; the nearest road point for off-road objects. */
|
||||||
|
km: number;
|
||||||
|
lat: number;
|
||||||
|
lon: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** `[km, lat, lon]` along the road, in order of km. */
|
||||||
|
export type RoutePoint = [number, number, number];
|
||||||
|
|
||||||
|
/** One sung line: the roster entries it lights, where they are, and when. */
|
||||||
|
export type Cue = {
|
||||||
|
startS: number;
|
||||||
|
stopS: number;
|
||||||
|
/** Distance along the road; the nearest road point for off-road objects. */
|
||||||
|
km: number;
|
||||||
|
objects: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TransectData = {
|
||||||
|
route: RoutePoint[];
|
||||||
|
/**
|
||||||
|
* The road carrying on past the eastern cutoff (274-route-east.json), painted
|
||||||
|
* only after 東に続く. Empty if the file is absent.
|
||||||
|
*/
|
||||||
|
routeEast: RoutePoint[];
|
||||||
|
/**
|
||||||
|
* The road arriving before the western cutoff (274-route-west.json), always
|
||||||
|
* drawn as covered. Empty if the file is absent.
|
||||||
|
*/
|
||||||
|
routeWest: RoutePoint[];
|
||||||
|
/** When 東に続く (the closing line) starts, or null if the index has none. */
|
||||||
|
closingStartS: number | null;
|
||||||
|
/** Only the entries the song names; nothing else is drawn. */
|
||||||
|
items: RosterItem[];
|
||||||
|
cues: Cue[];
|
||||||
|
/** Every lyric line, districts and 東に続く included: when words are sung. */
|
||||||
|
lines: { startS: number; stopS: number }[];
|
||||||
|
/** When the last lyric line (東に続く included) ends. */
|
||||||
|
lyricsEndS: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The page's famOf() grouping, plus shrines and railway. Railway goes by name as
|
||||||
|
* well as kind: some 信号場 are in the roster as `place (locality)`.
|
||||||
|
*/
|
||||||
|
const familyOf = (kind: string, object: string): FeatureFamily => {
|
||||||
|
if (
|
||||||
|
kind === "railway station" ||
|
||||||
|
kind === "railway signal post" ||
|
||||||
|
/信号場$/.test(object)
|
||||||
|
) {
|
||||||
|
return "railway";
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
kind === "bridge" ||
|
||||||
|
kind === "tunnel" ||
|
||||||
|
kind === "shed" ||
|
||||||
|
kind === "watercourse"
|
||||||
|
) {
|
||||||
|
return kind;
|
||||||
|
} else if (
|
||||||
|
kind === "Shinto shrine"
|
||||||
|
) {
|
||||||
|
return "shrine";
|
||||||
|
}
|
||||||
|
return kind.indexOf("place") === 0 ? "place" : "other";
|
||||||
|
};
|
||||||
|
|
||||||
|
/** RFC 4180 CSV into header-keyed rows. Quoted fields may hold commas. */
|
||||||
|
const parseCsv = (text: string): Record<string, string>[] => {
|
||||||
|
const rows: string[][] = [];
|
||||||
|
let row: string[] = [];
|
||||||
|
let field = "";
|
||||||
|
let quoted = false;
|
||||||
|
const src = text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;
|
||||||
|
|
||||||
|
for (let i = 0; i < src.length; i++) {
|
||||||
|
const c = src[i];
|
||||||
|
if (quoted) {
|
||||||
|
if (c !== '"') {
|
||||||
|
field += c;
|
||||||
|
} else if (src[i + 1] === '"') {
|
||||||
|
field += '"';
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
quoted = false;
|
||||||
|
}
|
||||||
|
} else if (c === '"') {
|
||||||
|
quoted = true;
|
||||||
|
} else if (c === ",") {
|
||||||
|
row.push(field);
|
||||||
|
field = "";
|
||||||
|
} else if (c === "\n" || c === "\r") {
|
||||||
|
if (c === "\r" && src[i + 1] === "\n") {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
row.push(field);
|
||||||
|
rows.push(row);
|
||||||
|
row = [];
|
||||||
|
field = "";
|
||||||
|
} else {
|
||||||
|
field += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (field !== "" || row.length > 0) {
|
||||||
|
row.push(field);
|
||||||
|
rows.push(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [header, ...body] = rows.filter((r) => r.length > 1 || r[0] !== "");
|
||||||
|
return body.map((r) => {
|
||||||
|
const record: Record<string, string> = {};
|
||||||
|
header.forEach((key, j) => {
|
||||||
|
record[key] = r[j] === undefined ? "" : r[j];
|
||||||
|
});
|
||||||
|
return record;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchText = async (path: string): Promise<string> => {
|
||||||
|
const res = await fetch(staticFile(path));
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`Could not load ${path}: HTTP ${res.status}`);
|
||||||
|
}
|
||||||
|
return res.text();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Like fetchText, but a missing file (404) is not an error: returns null. */
|
||||||
|
const fetchOptionalText = async (path: string): Promise<string | null> => {
|
||||||
|
const res = await fetch(staticFile(path));
|
||||||
|
if (res.status === 404) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`Could not load ${path}: HTTP ${res.status}`);
|
||||||
|
}
|
||||||
|
return res.text();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const loadTransectData = async (): Promise<TransectData> => {
|
||||||
|
const [routeJson, routeEastJson, routeWestJson, lookupCsv, indexCsv] = await Promise.all([
|
||||||
|
fetchText("route/274-route.json"),
|
||||||
|
fetchOptionalText("route/274-route-east.json"),
|
||||||
|
fetchOptionalText("route/274-route-west.json"),
|
||||||
|
fetchText("route/274-lookup.csv"),
|
||||||
|
fetchText("route/274-lyrics-index.csv"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const roster = new Map<string, RosterItem>();
|
||||||
|
for (const r of parseCsv(lookupCsv)) {
|
||||||
|
roster.set(r.object, {
|
||||||
|
object: r.object,
|
||||||
|
kind: r.kind,
|
||||||
|
family: familyOf(r.kind, r.object),
|
||||||
|
km: Number(r.km),
|
||||||
|
lat: Number(r.lat),
|
||||||
|
lon: Number(r.lon),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const items: RosterItem[] = [];
|
||||||
|
const cues: Cue[] = [];
|
||||||
|
const lines: TransectData["lines"] = [];
|
||||||
|
let lyricsEndS = 0;
|
||||||
|
let closingStartS: number | null = null;
|
||||||
|
for (const r of parseCsv(indexCsv)) {
|
||||||
|
lyricsEndS = Math.max(lyricsEndS, Number(r.stop_s));
|
||||||
|
lines.push({ startS: Number(r.start_s), stopS: Number(r.stop_s) });
|
||||||
|
if (r.kind === "closing") {
|
||||||
|
closingStartS = Number(r.start_s);
|
||||||
|
}
|
||||||
|
// Address headers and the closing line have no single node to light.
|
||||||
|
if (r.kind === "district" || r.kind === "closing") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const item = roster.get(r.object);
|
||||||
|
if (!item) {
|
||||||
|
throw new Error(`Lyrics index names ${r.object}, which is not in the roster`);
|
||||||
|
}
|
||||||
|
items.push(item);
|
||||||
|
|
||||||
|
const startS = Number(r.start_s);
|
||||||
|
const stopS = Number(r.stop_s);
|
||||||
|
const last = cues[cues.length - 1];
|
||||||
|
// モトツ橋にモトツシェルター emits two rows sharing one timing: light both.
|
||||||
|
if (last && last.startS === startS && last.stopS === stopS) {
|
||||||
|
last.objects.push(r.object);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cues.push({ startS, stopS, km: Number(r.km), objects: [r.object] });
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
route: JSON.parse(routeJson) as RoutePoint[],
|
||||||
|
routeEast: routeEastJson ? (JSON.parse(routeEastJson) as RoutePoint[]) : [],
|
||||||
|
routeWest: routeWestJson ? (JSON.parse(routeWestJson) as RoutePoint[]) : [],
|
||||||
|
closingStartS,
|
||||||
|
items,
|
||||||
|
cues,
|
||||||
|
lines,
|
||||||
|
lyricsEndS,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
import type { RosterItem, RoutePoint } from "./data";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "Ground — true shape" projection of `274-transect.html`, in the page's
|
||||||
|
* own units: an equirectangular plot with longitude shrunk by cos(lat), so
|
||||||
|
* distances read true east–west and north–south. camera.ts decides how these
|
||||||
|
* units land on screen.
|
||||||
|
*/
|
||||||
|
export const GROUND = {
|
||||||
|
width: 1200,
|
||||||
|
pad: 34,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type Projection = {
|
||||||
|
height: number;
|
||||||
|
x: (lon: number) => number;
|
||||||
|
y: (lat: number) => number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const projectGround = (route: RoutePoint[]): Projection => {
|
||||||
|
const lats = route.map((p) => p[1]);
|
||||||
|
const lons = route.map((p) => p[2]);
|
||||||
|
const la0 = Math.min(...lats);
|
||||||
|
const la1 = Math.max(...lats);
|
||||||
|
const lo0 = Math.min(...lons);
|
||||||
|
const lo1 = Math.max(...lons);
|
||||||
|
|
||||||
|
const kx = Math.cos((((la0 + la1) / 2) * Math.PI) / 180);
|
||||||
|
const sx = (lo1 - lo0) * kx;
|
||||||
|
const sy = la1 - la0;
|
||||||
|
const iw = GROUND.width - 2 * GROUND.pad;
|
||||||
|
const ih = (iw * sy) / sx;
|
||||||
|
|
||||||
|
return {
|
||||||
|
height: ih + 2 * GROUND.pad,
|
||||||
|
x: (lon) => GROUND.pad + (((lon - lo0) * kx) / sx) * iw,
|
||||||
|
y: (lat) => GROUND.pad + ih - ((lat - la0) / sy) * ih,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Distance, in map units, between nodes that share exactly the same roster
|
||||||
|
* coordinates (草木橋 / 滝の上こ線橋, ポン久留喜橋 / 久留喜橋, モトツ橋 /
|
||||||
|
* モトツシェルター): small, so they read as a doubled dot on the road. Grows with
|
||||||
|
* zoom like the nodes themselves. (1 map unit ≈ 44 m on the ground here.)
|
||||||
|
*/
|
||||||
|
export const COINCIDENT_SPREAD = 1.5;
|
||||||
|
|
||||||
|
export type NodePosition = { x: number; y: number };
|
||||||
|
|
||||||
|
/** Direction of the road at `km`, as a unit vector in map units. */
|
||||||
|
const roadDirection = (route: RoutePoint[], km: number, proj: Projection) => {
|
||||||
|
const at = (k: number) => {
|
||||||
|
let i = 1;
|
||||||
|
while (i < route.length - 1 && route[i][0] < k) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
const [k0, lat0, lon0] = route[i - 1];
|
||||||
|
const [k1, lat1, lon1] = route[i];
|
||||||
|
const p = k1 === k0 ? 0 : Math.min(1, Math.max(0, (k - k0) / (k1 - k0)));
|
||||||
|
return { x: proj.x(lon0 + (lon1 - lon0) * p), y: proj.y(lat0 + (lat1 - lat0) * p) };
|
||||||
|
};
|
||||||
|
const a = at(km - 0.1);
|
||||||
|
const b = at(km + 0.1);
|
||||||
|
const length = Math.hypot(b.x - a.x, b.y - a.y);
|
||||||
|
return length > 0 ? { x: (b.x - a.x) / length, y: (b.y - a.y) / length } : { x: 1, y: 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where each node is drawn, by object name. Usually its roster coordinate; nodes
|
||||||
|
* sharing exactly the same coordinate are spread COINCIDENT_SPREAD apart along
|
||||||
|
* the road there, in road order, centred on the shared point. All such pairs are
|
||||||
|
* on-road structures, so they stay on the road. Keep the spread small: at 6,
|
||||||
|
* モトツシェルター landed on 福山トンネル, only 90 m further on.
|
||||||
|
*/
|
||||||
|
export const nodePositions = (
|
||||||
|
items: RosterItem[],
|
||||||
|
route: RoutePoint[],
|
||||||
|
proj: Projection,
|
||||||
|
): Map<string, NodePosition> => {
|
||||||
|
const groups = new Map<string, RosterItem[]>();
|
||||||
|
for (const item of items) {
|
||||||
|
const key = `${item.lat},${item.lon}`;
|
||||||
|
const group = groups.get(key) ?? [];
|
||||||
|
group.push(item);
|
||||||
|
groups.set(key, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
const positions = new Map<string, NodePosition>();
|
||||||
|
groups.forEach((group) => {
|
||||||
|
const x = proj.x(group[0].lon);
|
||||||
|
const y = proj.y(group[0].lat);
|
||||||
|
if (group.length === 1) {
|
||||||
|
positions.set(group[0].object, { x, y });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ordered = group.slice().sort((a, b) => a.km - b.km);
|
||||||
|
const dir = roadDirection(route, ordered[0].km, proj);
|
||||||
|
ordered.forEach((item, i) => {
|
||||||
|
const offset = (i - (ordered.length - 1) / 2) * COINCIDENT_SPREAD;
|
||||||
|
positions.set(item.object, { x: x + dir.x * offset, y: y + dir.y * offset });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return positions;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Bounds = { minX: number; minY: number; maxX: number; maxY: number };
|
||||||
|
|
||||||
|
/** Bounds of the projected route from its start up to each point, inclusive. */
|
||||||
|
export const prefixBounds = (route: RoutePoint[], proj: Projection): Bounds[] => {
|
||||||
|
const out: Bounds[] = [];
|
||||||
|
for (const p of route) {
|
||||||
|
const x = proj.x(p[2]);
|
||||||
|
const y = proj.y(p[1]);
|
||||||
|
const prev = out[out.length - 1];
|
||||||
|
out.push(prev ? extendBounds(prev, x, y) : { minX: x, minY: y, maxX: x, maxY: y });
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const extendBounds = (b: Bounds, x: number, y: number): Bounds => ({
|
||||||
|
minX: Math.min(b.minX, x),
|
||||||
|
minY: Math.min(b.minY, y),
|
||||||
|
maxX: Math.max(b.maxX, x),
|
||||||
|
maxY: Math.max(b.maxY, y),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const routePath = (points: RoutePoint[], proj: Projection): string =>
|
||||||
|
points
|
||||||
|
.map(
|
||||||
|
(p, i) =>
|
||||||
|
`${i ? "L" : "M"}${proj.x(p[2]).toFixed(2)} ${proj.y(p[1]).toFixed(2)}`,
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
import type { Cue } from "./data";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How one node looks at one instant. The animation functions below produce
|
||||||
|
* these, and Transect.tsx only draws them, so adding a property here (a colour,
|
||||||
|
* a stroke, a glow) is the only change the drawing needs to follow.
|
||||||
|
*/
|
||||||
|
export type NodeLook = {
|
||||||
|
radius: number;
|
||||||
|
opacity: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node that is not being sung. Radius is in map units (the page's pixels),
|
||||||
|
* so nodes grow with the camera's zoom. (The page itself uses 3 at 0.85.)
|
||||||
|
*/
|
||||||
|
export const RESTING: NodeLook = { radius: 2.5, opacity: 0.9 };
|
||||||
|
/** A node while its line is sung: the page's selected mark. */
|
||||||
|
export const LIT: NodeLook = { radius: 7, opacity: 1 };
|
||||||
|
|
||||||
|
const clamp01 = (v: number) => Math.min(1, Math.max(0, v));
|
||||||
|
|
||||||
|
/** Slightly slower lighting up and switching off. Relatively slower decay. */
|
||||||
|
const LIGHT_UP_S = 0.12;
|
||||||
|
const SWITCH_OFF_S = 0.5;
|
||||||
|
|
||||||
|
|
||||||
|
/** Blend two looks; p = 0 is `from`, p = 1 is `to`. */
|
||||||
|
export const mixLooks = (from: NodeLook, to: NodeLook, p: number): NodeLook => ({
|
||||||
|
radius: from.radius + (to.radius - from.radius) * p,
|
||||||
|
opacity: from.opacity + (to.opacity - from.opacity) * p,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node being switched on.
|
||||||
|
* @param elapsedS seconds since its line started (0 at the lyric timestamp)
|
||||||
|
* @param from the look it starts from
|
||||||
|
*/
|
||||||
|
export const lightUp = (elapsedS: number, from: NodeLook = RESTING): NodeLook =>
|
||||||
|
mixLooks(from, LIT, clamp01(elapsedS / LIGHT_UP_S));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node being switched off.
|
||||||
|
* @param elapsedS seconds since its line ended (0 at the next lyric timestamp)
|
||||||
|
* @param from the look it had when it was switched off
|
||||||
|
*/
|
||||||
|
export const switchOff = (elapsedS: number, from: NodeLook = LIT): NodeLook =>
|
||||||
|
mixLooks(from, RESTING, clamp01(elapsedS / SWITCH_OFF_S));
|
||||||
|
|
||||||
|
/** Longest a node holds fully lit, after lighting up, before it switches off. */
|
||||||
|
export const MAX_LIT_S = 0.9;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a cue's nodes start switching off: when the line ends, or once they have
|
||||||
|
* lit up and held for MAX_LIT_S, whichever comes first, so a long line does not
|
||||||
|
* keep a node lit for too long.
|
||||||
|
*/
|
||||||
|
export const switchOffAt = (cue: Cue): number =>
|
||||||
|
Math.min(cue.stopS, cue.startS + LIGHT_UP_S + MAX_LIT_S);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The look of a node at time `t`, given the cue that lights it (or none).
|
||||||
|
* Before the line: resting. Then lighting up until switchOffAt(). After that:
|
||||||
|
* switching off, starting from however far the light-up got, so a short line
|
||||||
|
* never jumps.
|
||||||
|
*/
|
||||||
|
export const nodeLookAt = (cue: Cue | undefined, t: number): NodeLook => {
|
||||||
|
if (!cue || t < cue.startS) {
|
||||||
|
return RESTING;
|
||||||
|
}
|
||||||
|
const offS = switchOffAt(cue);
|
||||||
|
if (t < offS) {
|
||||||
|
return lightUp(t - cue.startS);
|
||||||
|
}
|
||||||
|
return switchOff(t - offS, lightUp(offS - cue.startS));
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A node at full amplitude in the outro spectrum (see spectrum.ts). */
|
||||||
|
export const SPECTRUM_PEAK: NodeLook = { radius: 9, opacity: 1 };
|
||||||
|
|
||||||
|
/** level scaling helper */
|
||||||
|
export const levelExponential = (level: number, exponent: number = 2.0): number =>
|
||||||
|
Math.pow(clamp01(level), exponent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node in the outro spectrum.
|
||||||
|
* @param level its band's level, 0 (silence: resting) to 1 (SPECTRUM_PEAK)
|
||||||
|
*/
|
||||||
|
export const spectrumLook = (level: number): NodeLook =>
|
||||||
|
mixLooks(RESTING, SPECTRUM_PEAK, clamp01(levelExponential(level)));
|
||||||
|
|
||||||
|
/** Whether a look is anything other than resting (drawn on top if so). */
|
||||||
|
export const isAwake = (look: NodeLook): boolean =>
|
||||||
|
look.radius !== RESTING.radius || look.opacity !== RESTING.opacity;
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* Every colour the 274 transect video draws, named by what it is for rather than
|
||||||
|
* what it looks like. Change values here, or override `palette` in the Studio's
|
||||||
|
* input props, without touching the drawing code.
|
||||||
|
*
|
||||||
|
* The dark palette is the video's own, grown from the dark palette of
|
||||||
|
* `song-274/route/274-transect.html`; comments name the page's CSS variable each
|
||||||
|
* token corresponds to. The light palette is the page's, extended with the
|
||||||
|
* tokens the video added (shrine, railway).
|
||||||
|
*/
|
||||||
|
export type TransectPalette = {
|
||||||
|
/** Frame background. */
|
||||||
|
background: string;
|
||||||
|
/** The whole road, before the song has covered it. */
|
||||||
|
roadAhead: string;
|
||||||
|
/** The road the song has covered so far. */
|
||||||
|
roadCovered: string;
|
||||||
|
/** Node fill per feature family, as on the page's legend. */
|
||||||
|
bridge: string;
|
||||||
|
tunnel: string;
|
||||||
|
shed: string;
|
||||||
|
watercourse: string;
|
||||||
|
place: string;
|
||||||
|
/** Stations and every 信号場, whatever their roster kind. */
|
||||||
|
railway: string;
|
||||||
|
shrine: string;
|
||||||
|
other: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FeatureFamily =
|
||||||
|
| "bridge"
|
||||||
|
| "tunnel"
|
||||||
|
| "shed"
|
||||||
|
| "watercourse"
|
||||||
|
| "place"
|
||||||
|
| "railway"
|
||||||
|
| "shrine"
|
||||||
|
| "other";
|
||||||
|
|
||||||
|
export const darkPalette: TransectPalette = {
|
||||||
|
background: "#28323d", // --paper
|
||||||
|
roadAhead: "#49565f", // --rule
|
||||||
|
roadCovered: "#fdb021", // --road
|
||||||
|
bridge: "#9be9de", // --bridge
|
||||||
|
tunnel: "#b6c5c1", // --tunnel
|
||||||
|
shed: "#eba9eb", // --shed
|
||||||
|
watercourse: "#5FB6D6", // --water
|
||||||
|
place: "#68ad7f", // --place
|
||||||
|
railway: "#68ad7f", // --railway
|
||||||
|
shrine: "#a05050", // --shrine
|
||||||
|
other: "#a7b7d6", // --util
|
||||||
|
};
|
||||||
|
|
||||||
|
export const lightPalette: TransectPalette = {
|
||||||
|
background: "#E7ECEE",
|
||||||
|
roadAhead: "#C0CCD2",
|
||||||
|
roadCovered: "#2E4A5A",
|
||||||
|
bridge: "#116B62",
|
||||||
|
tunnel: "#3A4650",
|
||||||
|
shed: "#7A5AA6",
|
||||||
|
watercourse: "#2F7E9E",
|
||||||
|
place: "#8A6D1F",
|
||||||
|
railway: "#1F6E43",
|
||||||
|
shrine: "#9B2C2C",
|
||||||
|
other: "#5B6B75",
|
||||||
|
};
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
import type { RoutePoint, TransectData } from "./data";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How far along the road (km) the song has got at any moment: the head of the
|
||||||
|
* "covered so far" paint, and what the camera follows.
|
||||||
|
*
|
||||||
|
* The head is pinned to each sung object's km at the instant its line starts,
|
||||||
|
* and glides between those pins on a monotone cubic curve: it passes through
|
||||||
|
* every pin exactly, never runs backwards, and changes speed smoothly rather
|
||||||
|
* than lurching at each object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type Keyframe = { t: number; km: number };
|
||||||
|
|
||||||
|
/** How long the paint takes to run the east continuation once 東に続く starts. */
|
||||||
|
export const EAST_RUN_S = 75.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pins, in time order: the start of the route at 0 s and each sung line's
|
||||||
|
* object. Then the end of the main road as 東に続く starts, and the end of the
|
||||||
|
* east continuation EAST_RUN_S later. Without a closing line or an east
|
||||||
|
* continuation, the main road simply ends as the last lyric line ends.
|
||||||
|
*/
|
||||||
|
export const progressKeyframes = (data: TransectData): Keyframe[] => {
|
||||||
|
const { route, routeEast, closingStartS, cues, lyricsEndS } = data;
|
||||||
|
const keys: Keyframe[] = [{ t: 0, km: route[0][0] }];
|
||||||
|
// Keep time strictly increasing and km never decreasing.
|
||||||
|
const pin = (t: number, km: number) => {
|
||||||
|
const last = keys[keys.length - 1];
|
||||||
|
if (t <= last.t) {
|
||||||
|
last.km = Math.max(last.km, km);
|
||||||
|
} else {
|
||||||
|
keys.push({ t, km: Math.max(last.km, km) });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const cue of cues) {
|
||||||
|
pin(cue.startS, cue.km);
|
||||||
|
}
|
||||||
|
const mainEndKm = route[route.length - 1][0];
|
||||||
|
if (closingStartS !== null && routeEast.length > 0) {
|
||||||
|
pin(closingStartS, mainEndKm);
|
||||||
|
pin(closingStartS + EAST_RUN_S, routeEast[routeEast.length - 1][0]);
|
||||||
|
} else {
|
||||||
|
pin(lyricsEndS, mainEndKm);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The road the paint can travel: the main route, then the east continuation
|
||||||
|
* from where it passes the main route's end (the two overlap slightly).
|
||||||
|
*/
|
||||||
|
export const paintableRoute = (data: TransectData): RoutePoint[] => {
|
||||||
|
const mainEndKm = data.route[data.route.length - 1][0];
|
||||||
|
return data.route.concat(data.routeEast.filter((p) => p[0] > mainEndKm));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fritsch–Carlson monotone cubic Hermite interpolation through `keys`.
|
||||||
|
* Returns km as a function of time, held flat before the first and after the
|
||||||
|
* last keyframe.
|
||||||
|
*/
|
||||||
|
export const monotoneCurve = (keys: Keyframe[]): ((t: number) => number) => {
|
||||||
|
const n = keys.length;
|
||||||
|
if (n === 1) {
|
||||||
|
return () => keys[0].km;
|
||||||
|
}
|
||||||
|
const secant: number[] = [];
|
||||||
|
for (let i = 0; i < n - 1; i++) {
|
||||||
|
secant.push((keys[i + 1].km - keys[i].km) / (keys[i + 1].t - keys[i].t));
|
||||||
|
}
|
||||||
|
const tangent: number[] = [secant[0]];
|
||||||
|
for (let i = 1; i < n - 1; i++) {
|
||||||
|
tangent.push(secant[i - 1] * secant[i] <= 0 ? 0 : (secant[i - 1] + secant[i]) / 2);
|
||||||
|
}
|
||||||
|
tangent.push(secant[n - 2]);
|
||||||
|
for (let i = 0; i < n - 1; i++) {
|
||||||
|
if (secant[i] === 0) {
|
||||||
|
tangent[i] = 0;
|
||||||
|
tangent[i + 1] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const a = tangent[i] / secant[i];
|
||||||
|
const b = tangent[i + 1] / secant[i];
|
||||||
|
const h = a * a + b * b;
|
||||||
|
if (h > 9) {
|
||||||
|
const tau = 3 / Math.sqrt(h);
|
||||||
|
tangent[i] = tau * a * secant[i];
|
||||||
|
tangent[i + 1] = tau * b * secant[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (t) => {
|
||||||
|
if (t <= keys[0].t) {
|
||||||
|
return keys[0].km;
|
||||||
|
}
|
||||||
|
if (t >= keys[n - 1].t) {
|
||||||
|
return keys[n - 1].km;
|
||||||
|
}
|
||||||
|
let i = 0;
|
||||||
|
while (keys[i + 1].t < t) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
const h = keys[i + 1].t - keys[i].t;
|
||||||
|
const s = (t - keys[i].t) / h;
|
||||||
|
const s2 = s * s;
|
||||||
|
const s3 = s2 * s;
|
||||||
|
return (
|
||||||
|
(2 * s3 - 3 * s2 + 1) * keys[i].km +
|
||||||
|
(s3 - 2 * s2 + s) * h * tangent[i] +
|
||||||
|
(-2 * s3 + 3 * s2) * keys[i + 1].km +
|
||||||
|
(s3 - s2) * h * tangent[i + 1]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RoutePosition = {
|
||||||
|
/** Last route point at or before this km. */
|
||||||
|
index: number;
|
||||||
|
lat: number;
|
||||||
|
lon: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The point on the road at `km`, interpolated between route points. */
|
||||||
|
export const routeAtKm = (route: RoutePoint[], km: number): RoutePosition => {
|
||||||
|
const lastIndex = route.length - 1;
|
||||||
|
if (km <= route[0][0]) {
|
||||||
|
return { index: 0, lat: route[0][1], lon: route[0][2] };
|
||||||
|
}
|
||||||
|
if (km >= route[lastIndex][0]) {
|
||||||
|
return { index: lastIndex, lat: route[lastIndex][1], lon: route[lastIndex][2] };
|
||||||
|
}
|
||||||
|
let low = 0;
|
||||||
|
let high = lastIndex;
|
||||||
|
while (high - low > 1) {
|
||||||
|
const mid = (low + high) >> 1;
|
||||||
|
if (route[mid][0] <= km) {
|
||||||
|
low = mid;
|
||||||
|
} else {
|
||||||
|
high = mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const [k0, lat0, lon0] = route[low];
|
||||||
|
const [k1, lat1, lon1] = route[high];
|
||||||
|
const p = k1 === k0 ? 0 : (km - k0) / (k1 - k0);
|
||||||
|
return { index: low, lat: lat0 + (lat1 - lat0) * p, lon: lon0 + (lon1 - lon0) * p };
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The covered stretch of road: every route point up to the head, then the head. */
|
||||||
|
export const coveredRoute = (route: RoutePoint[], km: number): RoutePoint[] => {
|
||||||
|
const head = routeAtKm(route, km);
|
||||||
|
return [...route.slice(0, head.index + 1), [km, head.lat, head.lon]];
|
||||||
|
};
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
import { visualizeAudio, type MediaUtilsAudioData } from "@remotion/media-utils";
|
||||||
|
import { random } from "remotion";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The outro spectrum: from SPECTRUM_START_S the nodes stop following the lyric
|
||||||
|
* and act as a spectrum analyser. The log-spaced frequency bands are dealt out
|
||||||
|
* to the nodes in a seeded shuffle (see BAND_SEED), with no relation to where
|
||||||
|
* a node is on the road; each node's size follows its band's amplitude.
|
||||||
|
*
|
||||||
|
* Everything here is a pure function of the frame, so Studio previews and
|
||||||
|
* renders agree. Starting values were calibrated on the outro of
|
||||||
|
* 274_release2.wav (8:20 to the end, left channel).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** When the spectrum takes over from the lyric-driven looks. */
|
||||||
|
export const SPECTRUM_START_S = 504.4;
|
||||||
|
/** How long the hand-over from lyric looks to spectrum looks takes. */
|
||||||
|
export const SPECTRUM_FADE_S = 1.5;
|
||||||
|
|
||||||
|
/** Band centres are log-spaced across this range, one band per node. */
|
||||||
|
export const FREQ_LOW_HZ = 40;
|
||||||
|
export const FREQ_HIGH_HZ = 12000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seed for the node-to-band shuffle. Any string or number; change it to deal a
|
||||||
|
* different mapping. Seeded (Remotion's random()) rather than Math.random(), so
|
||||||
|
* every render tab and the Studio agree on which node gets which band.
|
||||||
|
*/
|
||||||
|
export const BAND_SEED = "274-spectrum";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raw amplitude → level (0–1): (raw × GAIN × (f / FREQ_LOW_HZ)^TREBLE_TILT)^CURVE.
|
||||||
|
* High bands are far quieter than bass, so TREBLE_TILT lifts them; CURVE below 1
|
||||||
|
* lifts quiet passages so more than the loudest bands move.
|
||||||
|
*
|
||||||
|
* On the release2 outro these give a median level of 0.35 (10–90% range
|
||||||
|
* 0.18–0.67), with nodes pinned at full size 0.6% of the time. GAIN 10 pinned
|
||||||
|
* them 11% of the time with the bass nodes nearly always full; CURVE 0.8 with
|
||||||
|
* GAIN 8 is livelier (0.15–0.85) but pins 6%.
|
||||||
|
*/
|
||||||
|
export const GAIN = 5;
|
||||||
|
export const TREBLE_TILT = 0.5;
|
||||||
|
export const CURVE = 0.6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release: a node's level is the loudest of its last RELEASE_FRAMES frames, each
|
||||||
|
* frame back multiplied by RELEASE_DECAY once more. Hits jump up at once and
|
||||||
|
* fall back smoothly, without any state carried between frames.
|
||||||
|
*/
|
||||||
|
export const RELEASE_FRAMES = 6;
|
||||||
|
export const RELEASE_DECAY = 0.75;
|
||||||
|
|
||||||
|
/** FFT size for visualizeAudio: bins are (sample rate / 2) / FFT_SAMPLES wide (23.4 Hz). */
|
||||||
|
export const FFT_SAMPLES = 1024;
|
||||||
|
/** Seconds of audio useWindowedAudioData keeps loaded around the current frame. */
|
||||||
|
export const AUDIO_WINDOW_S = 10;
|
||||||
|
|
||||||
|
const clamp01 = (v: number) => Math.min(1, Math.max(0, v));
|
||||||
|
|
||||||
|
const easeInOutCubic = (p: number) =>
|
||||||
|
p < 0.5 ? 4 * p * p * p : 1 - Math.pow(-2 * p + 2, 3) / 2;
|
||||||
|
|
||||||
|
/** 0 before the spectrum, 1 once the hand-over has finished. */
|
||||||
|
export const spectrumWeight = (t: number): number =>
|
||||||
|
easeInOutCubic(clamp01((t - SPECTRUM_START_S) / SPECTRUM_FADE_S));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The frame to load audio around: the real frame once the spectrum is active,
|
||||||
|
* otherwise the spectrum's start, so nothing is fetched for the rest of the song.
|
||||||
|
*/
|
||||||
|
export const audioWindowFrame = (frame: number, fps: number): number =>
|
||||||
|
Math.max(frame, Math.floor((SPECTRUM_START_S - SPECTRUM_FADE_S) * fps));
|
||||||
|
|
||||||
|
/** `count` log-spaced band centres from FREQ_LOW_HZ to FREQ_HIGH_HZ. */
|
||||||
|
export const bandFrequencies = (count: number): number[] =>
|
||||||
|
Array.from({ length: count }, (_, i) =>
|
||||||
|
count === 1
|
||||||
|
? FREQ_LOW_HZ
|
||||||
|
: FREQ_LOW_HZ * Math.pow(FREQ_HIGH_HZ / FREQ_LOW_HZ, i / (count - 1)),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One band centre per node, in node order: bandFrequencies(count) dealt out in a
|
||||||
|
* Fisher–Yates shuffle seeded by BAND_SEED.
|
||||||
|
*/
|
||||||
|
export const shuffledBandFrequencies = (count: number): number[] => {
|
||||||
|
const frequencies = bandFrequencies(count);
|
||||||
|
for (let i = frequencies.length - 1; i > 0; i--) {
|
||||||
|
const j = Math.floor(random(`${BAND_SEED}-${i}`) * (i + 1));
|
||||||
|
const swap = frequencies[i];
|
||||||
|
frequencies[i] = frequencies[j];
|
||||||
|
frequencies[j] = swap;
|
||||||
|
}
|
||||||
|
return frequencies;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A band's raw amplitude from one spectrum: the mean over the bins between its
|
||||||
|
* geometric edges, or, for bands narrower than a bin (the bass end), the value
|
||||||
|
* interpolated at its centre, so neighbouring bass nodes still differ.
|
||||||
|
*/
|
||||||
|
const bandValue = (spectrum: number[], centreHz: number, ratio: number, binHz: number) => {
|
||||||
|
const half = Math.sqrt(ratio);
|
||||||
|
const low = centreHz / half / binHz;
|
||||||
|
const high = centreHz * half / binHz;
|
||||||
|
const first = Math.max(1, Math.ceil(low));
|
||||||
|
const last = Math.min(spectrum.length - 1, Math.floor(high));
|
||||||
|
if (last >= first) {
|
||||||
|
let sum = 0;
|
||||||
|
for (let k = first; k <= last; k++) {
|
||||||
|
sum += spectrum[k];
|
||||||
|
}
|
||||||
|
return sum / (last - first + 1);
|
||||||
|
}
|
||||||
|
const pos = Math.min(spectrum.length - 1.001, Math.max(0, centreHz / binHz));
|
||||||
|
const k = Math.floor(pos);
|
||||||
|
return spectrum[k] + (spectrum[k + 1] - spectrum[k]) * (pos - k);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Every band's level (0–1) at `frame`, release included. */
|
||||||
|
export const bandLevels = (args: {
|
||||||
|
audioData: MediaUtilsAudioData;
|
||||||
|
dataOffsetInSeconds: number;
|
||||||
|
frame: number;
|
||||||
|
fps: number;
|
||||||
|
frequencies: number[];
|
||||||
|
}): number[] => {
|
||||||
|
const { audioData, dataOffsetInSeconds, frame, fps, frequencies } = args;
|
||||||
|
const binHz = audioData.sampleRate / 2 / FFT_SAMPLES;
|
||||||
|
const ratio =
|
||||||
|
frequencies.length > 1 ? Math.pow(FREQ_HIGH_HZ / FREQ_LOW_HZ, 1 / (frequencies.length - 1)) : 2;
|
||||||
|
const levels = frequencies.map(() => 0);
|
||||||
|
|
||||||
|
for (let back = 0; back < RELEASE_FRAMES && frame - back >= 0; back++) {
|
||||||
|
const spectrum = visualizeAudio({
|
||||||
|
audioData,
|
||||||
|
frame: frame - back,
|
||||||
|
fps,
|
||||||
|
numberOfSamples: FFT_SAMPLES,
|
||||||
|
dataOffsetInSeconds,
|
||||||
|
optimizeFor: "accuracy",
|
||||||
|
});
|
||||||
|
const decay = Math.pow(RELEASE_DECAY, back);
|
||||||
|
frequencies.forEach((hz, i) => {
|
||||||
|
const raw = bandValue(spectrum, hz, ratio, binHz);
|
||||||
|
const level =
|
||||||
|
Math.pow(clamp01(raw * GAIN * Math.pow(hz / FREQ_LOW_HZ, TREBLE_TILT)), CURVE) * decay;
|
||||||
|
levels[i] = Math.max(levels[i], level);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return levels;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user